diff options
1169 files changed, 27063 insertions, 10815 deletions
diff --git a/Android.bp b/Android.bp index 874d76fe8d00..03a6af5997bb 100644 --- a/Android.bp +++ b/Android.bp @@ -339,9 +339,7 @@ java_defaults { "sax/java", "telecomm/java", - // TODO(b/148660295): remove this - "apex/media/framework/java", - + "apex/media/aidl/stable", // TODO(b/147699819): remove this "telephony/java", ], @@ -911,6 +909,7 @@ cc_library { filegroup { name: "incremental_aidl", srcs: [ + "core/java/android/os/incremental/IIncrementalServiceConnector.aidl", "core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl", ], path: "core/java", diff --git a/StubLibraries.bp b/StubLibraries.bp index 60f6174740df..f06f2792e0d7 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -256,18 +256,16 @@ droidstubs { ///////////////////////////////////////////////////////////////////// java_defaults { - name: "framework-stubs-default", + name: "android_defaults_stubs_current", libs: [ "stub-annotations" ], static_libs: [ "private-stub-annotations-jar" ], - sdk_version: "core_current", errorprone: { javacflags: [ "-XepDisableAllChecks", ], }, - java_resources: [ - ":notices-for-framework-stubs", - ], + java_resources: [":notices-for-framework-stubs"], + sdk_version: "none", system_modules: "none", java_version: "1.8", compile_dex: true, @@ -276,25 +274,25 @@ java_defaults { java_library_static { name: "android_stubs_current", srcs: [ ":api-stubs-docs" ], - defaults: ["framework-stubs-default"], + defaults: ["android_defaults_stubs_current"], } java_library_static { name: "android_system_stubs_current", srcs: [ ":system-api-stubs-docs" ], - defaults: ["framework-stubs-default"], + defaults: ["android_defaults_stubs_current"], } java_library_static { name: "android_test_stubs_current", srcs: [ ":test-api-stubs-docs" ], - defaults: ["framework-stubs-default"], + defaults: ["android_defaults_stubs_current"], } java_library_static { name: "android_module_lib_stubs_current", srcs: [ ":module-lib-api-stubs-docs" ], - defaults: ["framework-stubs-default"], + defaults: ["android_defaults_stubs_current"], libs: ["android_system_stubs_current"], } diff --git a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java index 73b4a1914ad1..836e6b617395 100644 --- a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java +++ b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java @@ -192,6 +192,11 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase { Assume.assumeNoException( new AssertionError("onAnimationCanceled should not be called")); } + + @Override + public void onTaskAppeared(RemoteAnimationTarget app) throws RemoteException { + /* no-op */ + } }; recentsSemaphore.tryAcquire(); diff --git a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java index 8633c9613138..8139a2e963c5 100644 --- a/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/wm/RelayoutPerfTest.java @@ -30,6 +30,7 @@ import android.util.MergedConfiguration; import android.view.DisplayCutout; import android.view.IWindow; import android.view.IWindowSession; +import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.SurfaceControl; import android.view.View; @@ -120,6 +121,7 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase { new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT); final MergedConfiguration mOutMergedConfiguration = new MergedConfiguration(); final InsetsState mOutInsetsState = new InsetsState(); + final InsetsSourceControl[] mOutControls = new InsetsSourceControl[0]; final IWindow mWindow; final View mView; final WindowManager.LayoutParams mParams; @@ -152,7 +154,7 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase { mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrame, mOutContentInsets, mOutVisibleInsets, mOutStableInsets, mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration, - mOutSurfaceControl, mOutInsetsState, mOutSurfaceSize, + mOutSurfaceControl, mOutInsetsState, mOutControls, mOutSurfaceSize, mOutBlastSurfaceControl); } } diff --git a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java index 4ac3adfd19ce..c72cc9d635e0 100644 --- a/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java +++ b/apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java @@ -29,6 +29,7 @@ import android.view.Display; import android.view.DisplayCutout; import android.view.IWindowSession; import android.view.InputChannel; +import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.View; import android.view.WindowManager; @@ -91,6 +92,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase final DisplayCutout.ParcelableWrapper mOutDisplayCutout = new DisplayCutout.ParcelableWrapper(); final InsetsState mOutInsetsState = new InsetsState(); + final InsetsSourceControl[] mOutControls = new InsetsSourceControl[0]; TestWindow() { mLayoutParams.setTitle(TestWindow.class.getName()); @@ -109,7 +111,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase long startTime = SystemClock.elapsedRealtimeNanos(); session.addToDisplay(this, mSeq, mLayoutParams, View.VISIBLE, Display.DEFAULT_DISPLAY, mOutFrame, mOutContentInsets, mOutStableInsets, - mOutDisplayCutout, inputChannel, mOutInsetsState); + mOutDisplayCutout, inputChannel, mOutInsetsState, mOutControls); final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime; state.addExtraResult("add", elapsedTimeNsOfAdd); diff --git a/apex/Android.bp b/apex/Android.bp index 5f418d47f090..67cd0d7fcd1e 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -67,7 +67,7 @@ stubs_defaults { name: "framework-module-stubs-defaults-publicapi", args: mainline_framework_stubs_args, installable: false, - sdk_version: "current", + sdk_version: "module_current", filter_packages: framework_packages_to_document, check_api: { current: { @@ -86,7 +86,7 @@ stubs_defaults { args: mainline_framework_stubs_args + priv_apps, libs: ["framework-annotations-lib"], installable: false, - sdk_version: "system_current", + sdk_version: "module_current", filter_packages: framework_packages_to_document, check_api: { current: { diff --git a/apex/blobstore/framework/java/android/app/blob/XmlTags.java b/apex/blobstore/framework/java/android/app/blob/XmlTags.java index e64edc393769..dbfdcba05a73 100644 --- a/apex/blobstore/framework/java/android/app/blob/XmlTags.java +++ b/apex/blobstore/framework/java/android/app/blob/XmlTags.java @@ -48,6 +48,7 @@ public final class XmlTags { // For committer public static final String TAG_COMMITTER = "c"; + public static final String ATTR_COMMIT_TIME_MS = "cmt"; // For leasee public static final String TAG_LEASEE = "l"; diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java index c8ca44b6ef74..49b3ec1d113b 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java @@ -15,6 +15,7 @@ */ package com.android.server.blob; +import static android.app.blob.XmlTags.ATTR_COMMIT_TIME_MS; import static android.app.blob.XmlTags.ATTR_DESCRIPTION; import static android.app.blob.XmlTags.ATTR_DESCRIPTION_RES_NAME; import static android.app.blob.XmlTags.ATTR_EXPIRY_TIME; @@ -30,6 +31,7 @@ import static android.os.Process.INVALID_UID; import static android.system.OsConstants.O_RDONLY; import static com.android.server.blob.BlobStoreConfig.TAG; +import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_COMMIT_TIME; import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_DESC_RES_NAME; import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_STRING_DESC; import static com.android.server.blob.BlobStoreConfig.hasLeaseWaitTimeElapsed; @@ -54,6 +56,7 @@ import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; import com.android.server.blob.BlobStoreManagerService.DumpArgs; @@ -125,7 +128,7 @@ class BlobMetadata { } } - void addCommitters(ArraySet<Committer> committers) { + void setCommitters(ArraySet<Committer> committers) { synchronized (mMetadataLock) { mCommitters.clear(); mCommitters.addAll(committers); @@ -153,11 +156,16 @@ class BlobMetadata { } @Nullable - Committer getExistingCommitter(@NonNull Committer newCommitter) { + Committer getExistingCommitter(@NonNull String packageName, int uid) { synchronized (mCommitters) { - final int index = mCommitters.indexOf(newCommitter); - return index >= 0 ? mCommitters.valueAt(index) : null; + for (int i = 0, size = mCommitters.size(); i < size; ++i) { + final Committer committer = mCommitters.valueAt(i); + if (committer.uid == uid && committer.packageName.equals(packageName)) { + return committer; + } + } } + return null; } void addOrReplaceLeasee(String callingPackage, int callingUid, int descriptionResId, @@ -172,7 +180,7 @@ class BlobMetadata { } } - void addLeasees(ArraySet<Leasee> leasees) { + void setLeasees(ArraySet<Leasee> leasees) { synchronized (mMetadataLock) { mLeasees.clear(); mLeasees.addAll(leasees); @@ -380,8 +388,7 @@ class BlobMetadata { } // Blobs with no active leases - // TODO: Track commit time instead of using last modified time. - if ((!respectLeaseWaitTime || hasLeaseWaitTimeElapsed(getBlobFile().lastModified())) + if ((!respectLeaseWaitTime || hasLeaseWaitTimeElapsedForAll()) && !hasLeases()) { return true; } @@ -389,6 +396,17 @@ class BlobMetadata { return false; } + @VisibleForTesting + boolean hasLeaseWaitTimeElapsedForAll() { + for (int i = 0, size = mCommitters.size(); i < size; ++i) { + final Committer committer = mCommitters.valueAt(i); + if (!hasLeaseWaitTimeElapsed(committer.getCommitTimeMs())) { + return false; + } + } + return true; + } + void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) { fout.println("blobHandle:"); fout.increaseIndent(); @@ -492,20 +510,28 @@ class BlobMetadata { } final BlobMetadata blobMetadata = new BlobMetadata(context, blobId, blobHandle, userId); - blobMetadata.addCommitters(committers); - blobMetadata.addLeasees(leasees); + blobMetadata.setCommitters(committers); + blobMetadata.setLeasees(leasees); return blobMetadata; } static final class Committer extends Accessor { public final BlobAccessMode blobAccessMode; + public final long commitTimeMs; - Committer(String packageName, int uid, BlobAccessMode blobAccessMode) { + Committer(String packageName, int uid, BlobAccessMode blobAccessMode, long commitTimeMs) { super(packageName, uid); this.blobAccessMode = blobAccessMode; + this.commitTimeMs = commitTimeMs; + } + + long getCommitTimeMs() { + return commitTimeMs; } void dump(IndentingPrintWriter fout) { + fout.println("commit time: " + + (commitTimeMs == 0 ? "<null>" : BlobStoreUtils.formatTime(commitTimeMs))); fout.println("accessMode:"); fout.increaseIndent(); blobAccessMode.dump(fout); @@ -515,6 +541,7 @@ class BlobMetadata { void writeToXml(@NonNull XmlSerializer out) throws IOException { XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, packageName); XmlUtils.writeIntAttribute(out, ATTR_UID, uid); + XmlUtils.writeLongAttribute(out, ATTR_COMMIT_TIME_MS, commitTimeMs); out.startTag(null, TAG_ACCESS_MODE); blobAccessMode.writeToXml(out); @@ -526,6 +553,9 @@ class BlobMetadata { throws XmlPullParserException, IOException { final String packageName = XmlUtils.readStringAttribute(in, ATTR_PACKAGE); final int uid = XmlUtils.readIntAttribute(in, ATTR_UID); + final long commitTimeMs = version >= XML_VERSION_ADD_COMMIT_TIME + ? XmlUtils.readLongAttribute(in, ATTR_COMMIT_TIME_MS) + : 0; final int depth = in.getDepth(); BlobAccessMode blobAccessMode = null; @@ -538,7 +568,7 @@ class BlobMetadata { Slog.wtf(TAG, "blobAccessMode should be available"); return null; } - return new Committer(packageName, uid, blobAccessMode); + return new Committer(packageName, uid, blobAccessMode, commitTimeMs); } } diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java index f2c158658562..6af1178b55f1 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java @@ -45,8 +45,9 @@ class BlobStoreConfig { // Added a string variant of lease description. public static final int XML_VERSION_ADD_STRING_DESC = 2; public static final int XML_VERSION_ADD_DESC_RES_NAME = 3; + public static final int XML_VERSION_ADD_COMMIT_TIME = 4; - public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_DESC_RES_NAME; + public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_COMMIT_TIME; private static final String ROOT_DIR_NAME = "blobstore"; private static final String BLOBS_DIR_NAME = "blobs"; @@ -100,6 +101,18 @@ class BlobStoreConfig { public static long LEASE_ACQUISITION_WAIT_DURATION_MS = DEFAULT_LEASE_ACQUISITION_WAIT_DURATION_MS; + /** + * Denotes the duration from the time a blob is committed that any new commits of the same + * data blob from the same committer will be treated as if they occurred at the earlier + * commit time. + */ + public static final String KEY_COMMIT_COOL_OFF_DURATION_MS = + "commit_cool_off_duration_ms"; + public static final long DEFAULT_COMMIT_COOL_OFF_DURATION_MS = + TimeUnit.HOURS.toMillis(48); + public static long COMMIT_COOL_OFF_DURATION_MS = + DEFAULT_COMMIT_COOL_OFF_DURATION_MS; + static void refresh(Properties properties) { if (!NAMESPACE_BLOBSTORE.equals(properties.getNamespace())) { return; @@ -163,6 +176,27 @@ class BlobStoreConfig { < System.currentTimeMillis(); } + /** + * Returns an adjusted commit time depending on whether commit cool-off period has elapsed. + * + * If this is the initial commit or the earlier commit cool-off period has elapsed, then + * the new commit time is used. Otherwise, the earlier commit time is used. + */ + public static long getAdjustedCommitTimeMs(long oldCommitTimeMs, long newCommitTimeMs) { + if (oldCommitTimeMs == 0 || hasCommitCoolOffPeriodElapsed(oldCommitTimeMs)) { + return newCommitTimeMs; + } + return oldCommitTimeMs; + } + + /** + * Returns whether the commit cool-off period has elapsed. + */ + private static boolean hasCommitCoolOffPeriodElapsed(long commitTimeMs) { + return commitTimeMs + DeviceConfigProperties.COMMIT_COOL_OFF_DURATION_MS + < System.currentTimeMillis(); + } + @Nullable public static File prepareBlobFile(long sessionId) { final File blobsDir = prepareBlobsDir(); diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java index e472d052f32f..35a2436702da 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -31,6 +31,7 @@ import static com.android.server.blob.BlobStoreConfig.LOGV; import static com.android.server.blob.BlobStoreConfig.SESSION_EXPIRY_TIMEOUT_MILLIS; import static com.android.server.blob.BlobStoreConfig.TAG; import static com.android.server.blob.BlobStoreConfig.XML_VERSION_CURRENT; +import static com.android.server.blob.BlobStoreConfig.getAdjustedCommitTimeMs; import static com.android.server.blob.BlobStoreSession.STATE_ABANDONED; import static com.android.server.blob.BlobStoreSession.STATE_COMMITTED; import static com.android.server.blob.BlobStoreSession.STATE_VERIFIED_INVALID; @@ -566,13 +567,18 @@ public class BlobStoreManagerService extends SystemService { userId); BlobMetadata blob = userBlobs.get(session.getBlobHandle()); if (blob == null) { - blob = new BlobMetadata(mContext, - session.getSessionId(), session.getBlobHandle(), userId); + blob = new BlobMetadata(mContext, session.getSessionId(), + session.getBlobHandle(), userId); addBlobForUserLocked(blob, userBlobs); } + final Committer existingCommitter = blob.getExistingCommitter( + session.getOwnerPackageName(), session.getOwnerUid()); + final long existingCommitTimeMs = + (existingCommitter == null) ? 0 : existingCommitter.getCommitTimeMs(); final Committer newCommitter = new Committer(session.getOwnerPackageName(), - session.getOwnerUid(), session.getBlobAccessMode()); - final Committer existingCommitter = blob.getExistingCommitter(newCommitter); + session.getOwnerUid(), session.getBlobAccessMode(), + getAdjustedCommitTimeMs(existingCommitTimeMs, + System.currentTimeMillis())); blob.addOrReplaceCommitter(newCommitter); try { writeBlobsInfoLocked(); diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java index fabce766c237..1d07e88773c3 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.text.format.TimeMigrationUtils; import android.util.Slog; class BlobStoreUtils { @@ -56,4 +57,9 @@ class BlobStoreUtils { ? Resources.ID_NULL : getDescriptionResourceId(resources, resourceEntryName, packageName); } + + @NonNull + static String formatTime(long timeMs) { + return TimeMigrationUtils.formatMillisWithFixedFormat(timeMs); + } } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java index d7b1e0793f67..1645bcb928c1 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java @@ -184,7 +184,6 @@ public final class BackgroundJobsController extends StateController { } boolean updateSingleJobRestrictionLocked(JobStatus jobStatus, int activeState) { - final int uid = jobStatus.getSourceUid(); final String packageName = jobStatus.getSourcePackageName(); @@ -199,7 +198,7 @@ public final class BackgroundJobsController extends StateController { isActive = (activeState == KNOWN_ACTIVE); } if (isActive && jobStatus.getStandbyBucket() == NEVER_INDEX) { - Slog.wtf(TAG, "App became active but still in NEVER bucket"); + Slog.wtf(TAG, "App " + packageName + " became active but still in NEVER bucket"); } boolean didChange = jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun); didChange |= jobStatus.setUidActive(isActive); diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java index f74eb3b9a45f..e2c8f649fdb7 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java @@ -19,10 +19,12 @@ package com.android.server.job.controllers.idle; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import android.app.AlarmManager; +import android.app.UiModeManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.PowerManager; import android.util.Log; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -39,6 +41,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id || Log.isLoggable(TAG, Log.DEBUG); private AlarmManager mAlarm; + private PowerManager mPowerManager; // After construction, mutations of idle/screen-on state will only happen // on the main looper thread, either in onReceive() or in an alarm callback. @@ -47,6 +50,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id private boolean mIdle; private boolean mScreenOn; private boolean mDockIdle; + private boolean mInCarMode; private IdlenessListener mIdleListener; private AlarmManager.OnAlarmListener mIdleAlarmListener = () -> { @@ -59,6 +63,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id mIdle = false; mScreenOn = true; mDockIdle = false; + mInCarMode = false; } @Override @@ -74,6 +79,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id mIdleWindowSlop = context.getResources().getInteger( com.android.internal.R.integer.config_jobSchedulerIdleWindowSlop); mAlarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + mPowerManager = context.getSystemService(PowerManager.class); IntentFilter filter = new IntentFilter(); @@ -92,6 +98,10 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id filter.addAction(Intent.ACTION_DOCK_IDLE); filter.addAction(Intent.ACTION_DOCK_ACTIVE); + // Car mode + filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED); + filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED); + context.registerReceiver(this, filter); } @@ -100,6 +110,8 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id pw.print(" mIdle: "); pw.println(mIdle); pw.print(" mScreenOn: "); pw.println(mScreenOn); pw.print(" mDockIdle: "); pw.println(mDockIdle); + pw.print(" mInCarMode: "); + pw.println(mInCarMode); } @Override @@ -116,6 +128,9 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id proto.write( StateControllerProto.IdleController.IdlenessTracker.DeviceIdlenessTracker.IS_DOCK_IDLE, mDockIdle); + proto.write( + StateControllerProto.IdleController.IdlenessTracker.DeviceIdlenessTracker.IN_CAR_MODE, + mInCarMode); proto.end(diToken); proto.end(token); @@ -124,63 +139,90 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); - if (action.equals(Intent.ACTION_SCREEN_ON) - || action.equals(Intent.ACTION_DREAMING_STOPPED) - || action.equals(Intent.ACTION_DOCK_ACTIVE)) { - if (action.equals(Intent.ACTION_DOCK_ACTIVE)) { + if (DEBUG) { + Slog.v(TAG, "Received action: " + action); + } + switch (action) { + case Intent.ACTION_DOCK_ACTIVE: if (!mScreenOn) { // Ignore this intent during screen off return; - } else { - mDockIdle = false; } - } else { + // Intentional fallthrough + case Intent.ACTION_DREAMING_STOPPED: + if (!mPowerManager.isInteractive()) { + // Ignore this intent if the device isn't interactive. + return; + } + // Intentional fallthrough + case Intent.ACTION_SCREEN_ON: mScreenOn = true; mDockIdle = false; - } - if (DEBUG) { - Slog.v(TAG,"exiting idle : " + action); - } - //cancel the alarm - mAlarm.cancel(mIdleAlarmListener); - if (mIdle) { - // possible transition to not-idle - mIdle = false; - mIdleListener.reportNewIdleState(mIdle); - } - } else if (action.equals(Intent.ACTION_SCREEN_OFF) - || action.equals(Intent.ACTION_DREAMING_STARTED) - || action.equals(Intent.ACTION_DOCK_IDLE)) { - // when the screen goes off or dreaming starts or wireless charging dock in idle, - // we schedule the alarm that will tell us when we have decided the device is - // truly idle. - if (action.equals(Intent.ACTION_DOCK_IDLE)) { - if (!mScreenOn) { - // Ignore this intent during screen off - return; + if (DEBUG) { + Slog.v(TAG, "exiting idle"); + } + cancelIdlenessCheck(); + if (mIdle) { + mIdle = false; + mIdleListener.reportNewIdleState(mIdle); + } + break; + case Intent.ACTION_SCREEN_OFF: + case Intent.ACTION_DREAMING_STARTED: + case Intent.ACTION_DOCK_IDLE: + // when the screen goes off or dreaming starts or wireless charging dock in idle, + // we schedule the alarm that will tell us when we have decided the device is + // truly idle. + if (action.equals(Intent.ACTION_DOCK_IDLE)) { + if (!mScreenOn) { + // Ignore this intent during screen off + return; + } else { + mDockIdle = true; + } } else { - mDockIdle = true; + mScreenOn = false; + mDockIdle = false; } - } else { - mScreenOn = false; - mDockIdle = false; - } + maybeScheduleIdlenessCheck(action); + break; + case UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED: + mInCarMode = true; + cancelIdlenessCheck(); + if (mIdle) { + mIdle = false; + mIdleListener.reportNewIdleState(mIdle); + } + break; + case UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED: + mInCarMode = false; + maybeScheduleIdlenessCheck(action); + break; + case ActivityManagerService.ACTION_TRIGGER_IDLE: + handleIdleTrigger(); + break; + } + } + + private void maybeScheduleIdlenessCheck(String reason) { + if ((!mScreenOn || mDockIdle) && !mInCarMode) { final long nowElapsed = sElapsedRealtimeClock.millis(); final long when = nowElapsed + mInactivityIdleThreshold; if (DEBUG) { - Slog.v(TAG, "Scheduling idle : " + action + " now:" + nowElapsed + " when=" - + when); + Slog.v(TAG, "Scheduling idle : " + reason + " now:" + nowElapsed + " when=" + when); } mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mIdleWindowSlop, "JS idleness", mIdleAlarmListener, null); - } else if (action.equals(ActivityManagerService.ACTION_TRIGGER_IDLE)) { - handleIdleTrigger(); } } + private void cancelIdlenessCheck() { + mAlarm.cancel(mIdleAlarmListener); + } + private void handleIdleTrigger() { // idle time starts now. Do not set mIdle if screen is on. - if (!mIdle && (!mScreenOn || mDockIdle)) { + if (!mIdle && (!mScreenOn || mDockIdle) && !mInCarMode) { if (DEBUG) { Slog.v(TAG, "Idle trigger fired @ " + sElapsedRealtimeClock.millis()); } @@ -189,7 +231,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id } else { if (DEBUG) { Slog.v(TAG, "TRIGGER_IDLE received but not changing state; idle=" - + mIdle + " screen=" + mScreenOn); + + mIdle + " screen=" + mScreenOn + " car=" + mInCarMode); } } } diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index b6f85b2d06bf..3c1fafbc1495 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -172,8 +172,7 @@ public class AppStandbyController implements AppStandbyInternal { COMPRESS_TIME ? 1 * ONE_MINUTE : 12 * ONE_HOUR, COMPRESS_TIME ? 4 * ONE_MINUTE : 24 * ONE_HOUR, COMPRESS_TIME ? 16 * ONE_MINUTE : 48 * ONE_HOUR, - // TODO(149050681): increase timeout to 30+ days - COMPRESS_TIME ? 32 * ONE_MINUTE : 4 * ONE_DAY + COMPRESS_TIME ? 32 * ONE_MINUTE : 30 * ONE_DAY }; /** The minimum allowed values for each index in {@link #ELAPSED_TIME_THRESHOLDS}. */ @@ -1364,6 +1363,19 @@ public class AppStandbyController implements AppStandbyInternal { if (DEBUG) { Slog.d(TAG, " Keeping at WORKING_SET due to min timeout"); } + } else if (newBucket == STANDBY_BUCKET_RARE + && getBucketForLocked(packageName, userId, elapsedRealtime) + == STANDBY_BUCKET_RESTRICTED) { + // Prediction doesn't think the app will be used anytime soon and + // it's been long enough that it could just time out into restricted, + // so time it out there instead. Using TIMEOUT will allow prediction + // to raise the bucket when it needs to. + newBucket = STANDBY_BUCKET_RESTRICTED; + reason = REASON_MAIN_TIMEOUT; + if (DEBUG) { + Slog.d(TAG, + "Prediction to RARE overridden by timeout into RESTRICTED"); + } } } diff --git a/apex/media/aidl/Android.bp b/apex/media/aidl/Android.bp new file mode 100644 index 000000000000..409a04897f56 --- /dev/null +++ b/apex/media/aidl/Android.bp @@ -0,0 +1,35 @@ +// +// Copyright 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. +// + +filegroup { + name: "stable-mediasession2-aidl-srcs", + srcs: ["stable/**/*.aidl"], + path: "stable", +} + +filegroup { + name: "private-mediasession2-aidl-srcs", + srcs: ["private/**/I*.aidl"], + path: "private", +} + +filegroup { + name: "mediasession2-aidl-srcs", + srcs: [ + ":private-mediasession2-aidl-srcs", + ":stable-mediasession2-aidl-srcs", + ], +} diff --git a/apex/media/framework/java/android/media/Controller2Link.aidl b/apex/media/aidl/private/android/media/Controller2Link.aidl index 64edafcb11fc..64edafcb11fc 100644 --- a/apex/media/framework/java/android/media/Controller2Link.aidl +++ b/apex/media/aidl/private/android/media/Controller2Link.aidl diff --git a/apex/media/framework/java/android/media/IMediaController2.aidl b/apex/media/aidl/private/android/media/IMediaController2.aidl index 42c6e70529ec..42c6e70529ec 100644 --- a/apex/media/framework/java/android/media/IMediaController2.aidl +++ b/apex/media/aidl/private/android/media/IMediaController2.aidl diff --git a/apex/media/framework/java/android/media/IMediaSession2.aidl b/apex/media/aidl/private/android/media/IMediaSession2.aidl index 26e717b39afc..26e717b39afc 100644 --- a/apex/media/framework/java/android/media/IMediaSession2.aidl +++ b/apex/media/aidl/private/android/media/IMediaSession2.aidl diff --git a/apex/media/framework/java/android/media/IMediaSession2Service.aidl b/apex/media/aidl/private/android/media/IMediaSession2Service.aidl index 10ac1be0a36e..10ac1be0a36e 100644 --- a/apex/media/framework/java/android/media/IMediaSession2Service.aidl +++ b/apex/media/aidl/private/android/media/IMediaSession2Service.aidl diff --git a/apex/media/framework/java/android/media/Session2Command.aidl b/apex/media/aidl/private/android/media/Session2Command.aidl index 43a7b123ed29..43a7b123ed29 100644 --- a/apex/media/framework/java/android/media/Session2Command.aidl +++ b/apex/media/aidl/private/android/media/Session2Command.aidl diff --git a/apex/media/framework/java/android/media/Session2Token.aidl b/apex/media/aidl/stable/android/media/Session2Token.aidl index c5980e9e77fd..c5980e9e77fd 100644 --- a/apex/media/framework/java/android/media/Session2Token.aidl +++ b/apex/media/aidl/stable/android/media/Session2Token.aidl diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp index 99e82e7a3367..34fe22879ca9 100644 --- a/apex/media/framework/Android.bp +++ b/apex/media/framework/Android.bp @@ -55,17 +55,15 @@ filegroup { name: "updatable-media-srcs", srcs: [ ":mediaparser-srcs", - ":mediasession2-srcs", + ":mediasession2-java-srcs", + ":mediasession2-aidl-srcs", ], } filegroup { - name: "mediasession2-srcs", + name: "mediasession2-java-srcs", srcs: [ "java/android/media/Controller2Link.java", - "java/android/media/IMediaController2.aidl", - "java/android/media/IMediaSession2.aidl", - "java/android/media/IMediaSession2Service.aidl", "java/android/media/MediaConstants.java", "java/android/media/MediaController2.java", "java/android/media/MediaSession2.java", @@ -83,7 +81,7 @@ filegroup { srcs: [ "java/android/media/MediaParser.java" ], - path: "java" + path: "java", } stubs_defaults { @@ -94,7 +92,6 @@ stubs_defaults { // TODO(b/135922046) remove this include_dirs: ["frameworks/base/core/java"], }, - sdk_version: "system_current", } droidstubs { diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp index 793247e88614..fc9052e8beac 100644 --- a/apex/permission/framework/Android.bp +++ b/apex/permission/framework/Android.bp @@ -46,12 +46,10 @@ stubs_defaults { name: "framework-permission-stubs-defaults", srcs: [ ":framework-permission-sources" ], libs: [ "framework-annotations-lib" ], - sdk_version: "system_current", } droidstubs { name: "framework-permission-stubs-srcs-publicapi", - sdk_version: "system_current", defaults: [ "framework-module-stubs-defaults-publicapi", "framework-permission-stubs-defaults", @@ -60,7 +58,6 @@ droidstubs { droidstubs { name: "framework-permission-stubs-srcs-systemapi", - sdk_version: "system_current", defaults: [ "framework-module-stubs-defaults-systemapi", "framework-permission-stubs-defaults", @@ -69,7 +66,6 @@ droidstubs { droidstubs { name: "framework-permission-api-module_libs_api", - sdk_version: "system_current", defaults: [ "framework-module-api-defaults-module_libs_api", "framework-permission-stubs-defaults", @@ -78,7 +74,6 @@ droidstubs { droidstubs { name: "framework-permission-stubs-srcs-module_libs_api", - sdk_version: "system_current", defaults: [ "framework-module-stubs-defaults-module_libs_api", "framework-permission-stubs-defaults", diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp index 707113b9672c..3eabb88fec7d 100644 --- a/apex/sdkextensions/framework/Android.bp +++ b/apex/sdkextensions/framework/Android.bp @@ -48,7 +48,6 @@ stubs_defaults { name: "framework-sdkextensions-stubs-defaults", srcs: [ ":framework-sdkextensions-sources" ], libs: [ "framework-annotations-lib" ], - sdk_version: "system_current", } droidstubs { diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp index 32e13e31eebe..15d74951019d 100644 --- a/apex/statsd/Android.bp +++ b/apex/statsd/Android.bp @@ -67,7 +67,6 @@ cc_library_shared { "liblog", // Has a stable abi - should not be copied into apex. "libstatssocket", ], - //TODO: is libc++_static correct? stl: "libc++_static", cflags: [ "-Wall", diff --git a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl index b94928f09ae0..5cdb3249501b 100644 --- a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl +++ b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl @@ -59,9 +59,6 @@ interface IStatsCompanionService { /** Cancel any alarm for the purpose of subscriber triggering. */ oneway void cancelAlarmForSubscriberTriggering(); - /** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */ - oneway void triggerUidSnapshot(); - /** * Ask StatsCompanionService if the given permission is allowed for a particular process * and user ID. statsd is incapable of doing this check itself because checkCallingPermission diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl index d5b5949cd032..80308d26a430 100644 --- a/apex/statsd/aidl/android/os/IStatsd.aidl +++ b/apex/statsd/aidl/android/os/IStatsd.aidl @@ -31,6 +31,11 @@ interface IStatsd { oneway void systemRunning(); /** + * Tell the stats daemon that the android system has finished booting. + */ + oneway void bootCompleted(); + + /** * Tell the stats daemon that the StatsCompanionService is up and running. * Two-way binder call so that caller knows message received. */ @@ -182,10 +187,15 @@ interface IStatsd { */ void sendAppBreadcrumbAtom(int label, int state); - /** - * Registers a puller callback function that, when invoked, pulls the data - * for the specified atom tag. - */ + /** + * Tell the stats daemon that all the pullers registered during boot have been sent. + */ + oneway void allPullersFromBootRegistered(); + + /** + * Registers a puller callback function that, when invoked, pulls the data + * for the specified atom tag. + */ oneway void registerPullAtomCallback(int uid, int atomTag, long coolDownMillis, long timeoutMillis,in int[] additiveFields, IPullAtomCallback pullerCallback); diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java index c1ba73f03c06..dc477a5590ea 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java @@ -87,6 +87,9 @@ public class StatsCompanion { if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { mStatsCompanionService.systemReady(); } + if (phase == PHASE_BOOT_COMPLETED) { + mStatsCompanionService.bootCompleted(); + } } } diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index aad51124c8d2..93e6c108a289 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -112,6 +112,18 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final HashMap<Long, String> mDeletedFiles = new HashMap<>(); private final CompanionHandler mHandler; + // Flag that is set when PHASE_BOOT_COMPLETED is triggered in the StatsCompanion lifecycle. This + // and the flag mSentBootComplete below is used for synchronization to ensure that the boot + // complete signal is only ever sent once to statsd. Two signals are needed because + // #sayHiToStatsd can be called from both statsd and #onBootPhase + // PHASE_THIRD_PARTY_APPS_CAN_START. + @GuardedBy("sStatsdLock") + private boolean mBootCompleted = false; + // Flag that is set when IStatsd#bootCompleted is called. This flag ensures that boot complete + // signal is only ever sent once. + @GuardedBy("sStatsdLock") + private boolean mSentBootComplete = false; + public StatsCompanionService(Context context) { super(); mContext = context; @@ -153,14 +165,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private static void informAllUidsLocked(Context context) throws RemoteException { - UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); - PackageManager pm = context.getPackageManager(); - final List<UserHandle> users = um.getUserHandles(true); - if (DEBUG) { - Log.d(TAG, "Iterating over " + users.size() + " userHandles."); - } - + private static void informAllUids(Context context) { ParcelFileDescriptor[] fds; try { fds = ParcelFileDescriptor.createPipe(); @@ -168,18 +173,32 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { Log.e(TAG, "Failed to create a pipe to send uid map data.", e); return; } - sStatsd.informAllUidData(fds[0]); - try { - fds[0].close(); - } catch (IOException e) { - Log.e(TAG, "Failed to close the read side of the pipe.", e); - } - final ParcelFileDescriptor writeFd = fds[1]; HandlerThread backgroundThread = new HandlerThread( "statsCompanionService.bg", THREAD_PRIORITY_BACKGROUND); backgroundThread.start(); Handler handler = new Handler(backgroundThread.getLooper()); handler.post(() -> { + UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); + PackageManager pm = context.getPackageManager(); + final List<UserHandle> users = um.getUserHandles(true); + if (DEBUG) { + Log.d(TAG, "Iterating over " + users.size() + " userHandles."); + } + IStatsd statsd = getStatsdNonblocking(); + if (statsd == null) { + return; + } + try { + statsd.informAllUidData(fds[0]); + } catch (RemoteException e) { + Log.e(TAG, "Failed to send uid map to statsd"); + } + try { + fds[0].close(); + } catch (IOException e) { + Log.e(TAG, "Failed to close the read side of the pipe.", e); + } + final ParcelFileDescriptor writeFd = fds[1]; FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(writeFd); try { ProtoOutputStream output = new ProtoOutputStream(fout); @@ -188,7 +207,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { for (UserHandle userHandle : users) { List<PackageInfo> pi = pm.getInstalledPackagesAsUser(PackageManager.MATCH_UNINSTALLED_PACKAGES - | PackageManager.MATCH_ANY_USER, + | PackageManager.MATCH_ANY_USER + | PackageManager.MATCH_APEX, userHandle.getIdentifier()); for (int j = 0; j < pi.size(); j++) { if (pi.get(j).applicationInfo != null) { @@ -319,19 +339,9 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private static final class UserUpdateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - synchronized (sStatsdLock) { - if (sStatsd == null) { - Log.w(TAG, "Could not access statsd for UserUpdateReceiver"); - return; - } - try { - // Pull the latest state of UID->app name, version mapping. - // Needed since the new user basically has a version of every app. - informAllUidsLocked(context); - } catch (RemoteException e) { - Log.e(TAG, "Failed to inform statsd latest update of all apps", e); - } - } + // Pull the latest state of UID->app name, version mapping. + // Needed since the new user basically has a version of every app. + informAllUids(context); } } @@ -589,21 +599,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } @Override // Binder call - public void triggerUidSnapshot() { - StatsCompanion.enforceStatsdCallingUid(); - synchronized (sStatsdLock) { - final long token = Binder.clearCallingIdentity(); - try { - informAllUidsLocked(mContext); - } catch (RemoteException e) { - Log.e(TAG, "Failed to trigger uid snapshot.", e); - } finally { - Binder.restoreCallingIdentity(token); - } - } - } - - @Override // Binder call public boolean checkPermission(String permission, int pid, int uid) { StatsCompanion.enforceStatsdCallingUid(); return mContext.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED; @@ -703,14 +698,22 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { deathRecipient.addRegisteredBroadcastReceivers( List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver)); - final long token = Binder.clearCallingIdentity(); - try { - // Pull the latest state of UID->app name, version mapping when - // statsd starts. - informAllUidsLocked(mContext); - } finally { - Binder.restoreCallingIdentity(token); + // Used so we can call statsd.bootComplete() outside of the lock. + boolean shouldSendBootComplete = false; + synchronized (sStatsdLock) { + if (mBootCompleted && !mSentBootComplete) { + mSentBootComplete = true; + shouldSendBootComplete = true; + } + } + if (shouldSendBootComplete) { + statsd.bootCompleted(); } + + // Pull the latest state of UID->app name, version mapping when + // statsd starts. + informAllUids(mContext); + Log.i(TAG, "Told statsd that StatsCompanionService is alive."); } catch (RemoteException e) { Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e); @@ -765,6 +768,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { mContext.unregisterReceiver(receiver); } statsdNotReadyLocked(); + mSentBootComplete = false; } } } @@ -774,6 +778,28 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { mStatsManagerService.statsdNotReady(); } + void bootCompleted() { + IStatsd statsd = getStatsdNonblocking(); + synchronized (sStatsdLock) { + mBootCompleted = true; + if (mSentBootComplete) { + // do not send a boot complete a second time. + return; + } + if (statsd == null) { + // Statsd is not yet ready. + // Delay the boot completed ping to {@link #sayHiToStatsd()} + return; + } + mSentBootComplete = true; + } + try { + statsd.bootCompleted(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to notify statsd that boot completed"); + } + } + @Override protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java index 58c78da5cea7..90764b0bd426 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java @@ -600,6 +600,7 @@ public class StatsManagerService extends IStatsManagerService.Stub { statsd.registerPullAtomCallback(key.getUid(), key.getAtom(), value.getCoolDownMillis(), value.getTimeoutMillis(), value.getAdditiveFields(), value.getCallback()); } + statsd.allPullersFromBootRegistered(); } // Pre-condition: the Binder calling identity has already been cleared diff --git a/apex/statsd/tests/libstatspull/Android.bp b/apex/statsd/tests/libstatspull/Android.bp index 2d64f190839c..0df96e149d4f 100644 --- a/apex/statsd/tests/libstatspull/Android.bp +++ b/apex/statsd/tests/libstatspull/Android.bp @@ -32,7 +32,7 @@ android_test { "protos/**/*.proto", ], test_suites: [ - "general-tests", + "device-tests", ], platform_apis: true, privileged: true, diff --git a/api/current.txt b/api/current.txt index b4db1f7bc10a..80e2d00b3e48 100644 --- a/api/current.txt +++ b/api/current.txt @@ -46230,7 +46230,7 @@ package android.telecom { method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(); method public String getDefaultDialerPackage(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telecom.PhoneAccountHandle getDefaultOutgoingPhoneAccount(String); - method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1Number(android.telecom.PhoneAccountHandle); + method @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}, conditional=true) public String getLine1Number(android.telecom.PhoneAccountHandle); method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getSelfManagedPhoneAccounts(); method public android.telecom.PhoneAccountHandle getSimCallManager(); diff --git a/api/test-current.txt b/api/test-current.txt index 629ce4e6470e..0dff41b6a99c 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -214,6 +214,7 @@ package android.app { field public static final String OPSTR_GPS = "android:gps"; field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground"; field public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage"; + field public static final String OPSTR_MANAGE_EXTERNAL_STORAGE = "android:manage_external_storage"; field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels"; field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone"; field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells"; @@ -4814,7 +4815,14 @@ package android.view { public final class Display { method @NonNull public android.graphics.ColorSpace[] getSupportedWideColorGamut(); + method public int getType(); method public boolean hasAccess(int); + field public static final int TYPE_EXTERNAL = 2; // 0x2 + field public static final int TYPE_INTERNAL = 1; // 0x1 + field public static final int TYPE_OVERLAY = 4; // 0x4 + field public static final int TYPE_UNKNOWN = 0; // 0x0 + field public static final int TYPE_VIRTUAL = 5; // 0x5 + field public static final int TYPE_WIFI = 3; // 0x3 } public class FocusFinder { @@ -4852,6 +4860,13 @@ package android.view { method public abstract String asyncImpl() default ""; } + public final class SurfaceControl implements android.os.Parcelable { + ctor public SurfaceControl(@NonNull android.view.SurfaceControl); + method public static long acquireFrameRateFlexibilityToken(); + method public boolean isSameSurface(@NonNull android.view.SurfaceControl); + method public static void releaseFrameRateFlexibilityToken(long); + } + public class SurfaceControlViewHost { method public void relayout(android.view.WindowManager.LayoutParams); method public void setView(@NonNull android.view.View, @NonNull android.view.WindowManager.LayoutParams); @@ -5201,10 +5216,10 @@ package android.window { method public void onDisplayAreaAppeared(@NonNull android.window.WindowContainerToken); method public void onDisplayAreaVanished(@NonNull android.window.WindowContainerToken); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void registerOrganizer(int); + field public static final int FEATURE_DEFAULT_TASK_CONTAINER = 1; // 0x1 field public static final int FEATURE_ROOT = 0; // 0x0 field public static final int FEATURE_SYSTEM_FIRST = 0; // 0x0 field public static final int FEATURE_SYSTEM_LAST = 10000; // 0x2710 - field public static final int FEATURE_TASK_CONTAINER = 1; // 0x1 field public static final int FEATURE_UNDEFINED = -1; // 0xffffffff field public static final int FEATURE_VENDOR_FIRST = 10001; // 0x2711 field public static final int FEATURE_WINDOW_TOKENS = 2; // 0x2 @@ -5217,14 +5232,14 @@ package android.window { method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static android.window.WindowContainerToken getImeTarget(int); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static java.util.List<android.app.ActivityManager.RunningTaskInfo> getRootTasks(int, @NonNull int[]); - method public void onBackPressedOnTaskRoot(@NonNull android.app.ActivityManager.RunningTaskInfo); - method public void onTaskAppeared(@NonNull android.app.ActivityManager.RunningTaskInfo); - method public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo); - method public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void registerOrganizer(int); + method @BinderThread public void onBackPressedOnTaskRoot(@NonNull android.app.ActivityManager.RunningTaskInfo); + method @BinderThread public void onTaskAppeared(@NonNull android.app.ActivityManager.RunningTaskInfo); + method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo); + method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer(int); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(boolean); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void setLaunchRoot(int, @NonNull android.window.WindowContainerToken); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void unregisterOrganizer(); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer(); } public final class WindowContainerToken implements android.os.Parcelable { diff --git a/cmds/idmap2/TEST_MAPPING b/cmds/idmap2/TEST_MAPPING index 26ccf038cba2..9e0fb84c7949 100644 --- a/cmds/idmap2/TEST_MAPPING +++ b/cmds/idmap2/TEST_MAPPING @@ -3,5 +3,10 @@ { "name" : "idmap2_tests" } + ], + "imports": [ + { + "path": "frameworks/base/services/core/java/com/android/server/om" + } ] } diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index e55ea6c00545..75fc7f714ce3 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -149,15 +149,21 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path, return error(idmap.GetErrorMessage()); } + // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap guarantees + // that existing memory maps will continue to be valid and unaffected. + unlink(idmap_path.c_str()); + umask(kIdmapFilePermissionMask); std::ofstream fout(idmap_path); if (fout.fail()) { return error("failed to open idmap path " + idmap_path); } + BinaryStreamVisitor visitor(fout); (*idmap)->accept(&visitor); fout.close(); if (fout.fail()) { + unlink(idmap_path.c_str()); return error("failed to write to idmap path " + idmap_path); } diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index d3d7e1d483e8..b3579045b6a5 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -113,17 +113,18 @@ cc_defaults { static_libs: [ "libbase", "libcutils", + "libgtest_prod", "libprotoutil", "libstatsmetadata", "libstatslog_statsd", "libsysutils", "libutils", + "statsd-aidl-ndk_platform", ], shared_libs: [ "libbinder_ndk", "libincident", "liblog", - "statsd-aidl-ndk_platform", ], } @@ -268,10 +269,11 @@ cc_binary { proto: { type: "lite", + static: true, }, + stl: "libc++_static", shared_libs: [ - "libgtest_prod", "libstatssocket", ], @@ -299,6 +301,8 @@ cc_test { "-Wno-unused-parameter", ], + require_root: true, + srcs: [ // atom_field_options.proto needs field_options.proto, but that is // not included in libprotobuf-cpp-lite, so compile it here. @@ -371,10 +375,6 @@ cc_test { include_dirs: ["external/protobuf/src"], }, - shared_libs: [ - "libprotobuf-cpp-lite", - ], - } //############################# diff --git a/cmds/statsd/TEST_MAPPING b/cmds/statsd/TEST_MAPPING new file mode 100644 index 000000000000..8dee073aca22 --- /dev/null +++ b/cmds/statsd/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit" : [ + { + "name" : "statsd_test" + } + ] +}
\ No newline at end of file diff --git a/cmds/statsd/benchmark/filter_value_benchmark.cpp b/cmds/statsd/benchmark/filter_value_benchmark.cpp index 28bf21ae52bf..743ccc4ed451 100644 --- a/cmds/statsd/benchmark/filter_value_benchmark.cpp +++ b/cmds/statsd/benchmark/filter_value_benchmark.cpp @@ -14,12 +14,14 @@ * limitations under the License. */ #include <vector> -#include "benchmark/benchmark.h" + #include "FieldValue.h" #include "HashableDimensionKey.h" +#include "benchmark/benchmark.h" #include "logd/LogEvent.h" -#include "stats_log_util.h" +#include "metric_util.h" #include "stats_event.h" +#include "stats_log_util.h" namespace android { namespace os { @@ -34,24 +36,13 @@ static void createLogEventAndMatcher(LogEvent* event, FieldMatcher* field_matche std::vector<int> attributionUids = {100, 100}; std::vector<string> attributionTags = {"LOCATION", "LOCATION"}; + writeAttribution(statsEvent, attributionUids, attributionTags); - vector<const char*> cTags(attributionTags.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = attributionTags[i].c_str(); - } - - AStatsEvent_writeAttributionChain(statsEvent, - reinterpret_cast<const uint32_t*>(attributionUids.data()), - cTags.data(), attributionUids.size()); AStatsEvent_writeFloat(statsEvent, 3.2f); AStatsEvent_writeString(statsEvent, "LOCATION"); AStatsEvent_writeInt64(statsEvent, 990); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - event->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, event); field_matcher->set_field(1); auto child = field_matcher->add_child(); diff --git a/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp b/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp index c7d01cc406fc..7a455650a31b 100644 --- a/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp +++ b/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp @@ -14,12 +14,14 @@ * limitations under the License. */ #include <vector> -#include "benchmark/benchmark.h" + #include "FieldValue.h" #include "HashableDimensionKey.h" +#include "benchmark/benchmark.h" #include "logd/LogEvent.h" -#include "stats_log_util.h" +#include "metric_util.h" #include "stats_event.h" +#include "stats_log_util.h" namespace android { namespace os { @@ -34,24 +36,13 @@ static void createLogEventAndLink(LogEvent* event, Metric2Condition *link) { std::vector<int> attributionUids = {100, 100}; std::vector<string> attributionTags = {"LOCATION", "LOCATION"}; + writeAttribution(statsEvent, attributionUids, attributionTags); - vector<const char*> cTags(attributionTags.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = attributionTags[i].c_str(); - } - - AStatsEvent_writeAttributionChain(statsEvent, - reinterpret_cast<const uint32_t*>(attributionUids.data()), - cTags.data(), attributionUids.size()); AStatsEvent_writeFloat(statsEvent, 3.2f); AStatsEvent_writeString(statsEvent, "LOCATION"); AStatsEvent_writeInt64(statsEvent, 990); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - event->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, event); link->conditionId = 1; diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp index 482d66fc7556..89fd3d9b29ab 100644 --- a/cmds/statsd/benchmark/metric_util.cpp +++ b/cmds/statsd/benchmark/metric_util.cpp @@ -247,21 +247,37 @@ FieldMatcher CreateDimensions(const int atomId, const std::vector<int>& fields) return dimensions; } +void writeAttribution(AStatsEvent* statsEvent, const vector<int>& attributionUids, + const vector<string>& attributionTags) { + vector<const char*> cTags(attributionTags.size()); + for (int i = 0; i < cTags.size(); i++) { + cTags[i] = attributionTags[i].c_str(); + } + + AStatsEvent_writeAttributionChain(statsEvent, + reinterpret_cast<const uint32_t*>(attributionUids.data()), + cTags.data(), attributionUids.size()); +} + +void parseStatsEventToLogEvent(AStatsEvent* statsEvent, LogEvent* logEvent) { + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + logEvent->parseBuffer(buf, size); + + AStatsEvent_release(statsEvent); +} + std::unique_ptr<LogEvent> CreateScreenStateChangedEvent( uint64_t timestampNs, const android::view::DisplayStateEnum state) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, util::SCREEN_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -272,24 +288,12 @@ std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent( AStatsEvent_setAtomId(statsEvent, util::SCHEDULED_JOB_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - vector<const char*> cTags(attributionTags.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = attributionTags[i].c_str(); - } - - AStatsEvent_writeAttributionChain(statsEvent, - reinterpret_cast<const uint32_t*>(attributionUids.data()), - cTags.data(), attributionUids.size()); + writeAttribution(statsEvent, attributionUids, attributionTags); AStatsEvent_writeString(statsEvent, jobName.c_str()); AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -319,24 +323,12 @@ std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(uint64_t timestampNs, AStatsEvent_setAtomId(statsEvent, util::SYNC_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - vector<const char*> cTags(attributionTags.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = attributionTags[i].c_str(); - } - - AStatsEvent_writeAttributionChain(statsEvent, - reinterpret_cast<const uint32_t*>(attributionUids.data()), - cTags.data(), attributionUids.size()); + writeAttribution(statsEvent, attributionUids, attributionTags); AStatsEvent_writeString(statsEvent, name.c_str()); AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } diff --git a/cmds/statsd/benchmark/metric_util.h b/cmds/statsd/benchmark/metric_util.h index c5fcf7c27440..3efaa850a921 100644 --- a/cmds/statsd/benchmark/metric_util.h +++ b/cmds/statsd/benchmark/metric_util.h @@ -18,6 +18,7 @@ #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "src/StatsLogProcessor.h" #include "src/logd/LogEvent.h" +#include "stats_event.h" #include "statslog.h" namespace android { @@ -92,6 +93,11 @@ FieldMatcher CreateAttributionUidAndTagDimensions(const int atomId, FieldMatcher CreateAttributionUidDimensions(const int atomId, const std::vector<Position>& positions); +void writeAttribution(AStatsEvent* statsEvent, const vector<int>& attributionUids, + const vector<string>& attributionTags); + +void parseStatsEventToLogEvent(AStatsEvent* statsEvent, LogEvent* logEvent); + // Create log event for screen state changed. std::unique_ptr<LogEvent> CreateScreenStateChangedEvent( uint64_t timestampNs, const android::view::DisplayStateEnum state); diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp index 4385964f7f0e..cfc1de49e259 100644 --- a/cmds/statsd/src/FieldValue.cpp +++ b/cmds/statsd/src/FieldValue.cpp @@ -120,9 +120,9 @@ bool isAttributionUidField(const FieldValue& value) { } int32_t getUidIfExists(const FieldValue& value) { - // the field is uid field if the field is the uid field in attribution node or marked as - // is_uid in atoms.proto - bool isUid = isAttributionUidField(value) || isUidField(value.mField, value.mValue); + // the field is uid field if the field is the uid field in attribution node + // or annotated as such in the atom + bool isUid = isAttributionUidField(value) || isUidField(value); return isUid ? value.mValue.int_value : -1; } @@ -134,16 +134,8 @@ bool isAttributionUidField(const Field& field, const Value& value) { return false; } -bool isUidField(const Field& field, const Value& value) { - auto it = android::util::AtomsInfo::kAtomsWithUidField.find(field.getTag()); - - if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) { - int uidField = it->second; // uidField is the field number in proto - return field.getDepth() == 0 && field.getPosAtDepth(0) == uidField && - value.getType() == INT; - } - - return false; +bool isUidField(const FieldValue& fieldValue) { + return fieldValue.mAnnotations.isUidField(); } Value::Value(const Value& from) { diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h index 3536e5a5c962..92e09ea0f8f9 100644 --- a/cmds/statsd/src/FieldValue.h +++ b/cmds/statsd/src/FieldValue.h @@ -367,7 +367,8 @@ public: enum { NESTED_POS = 0x0, PRIMARY_POS = 0x1, - EXCLUSIVE_POS = 0x2 + EXCLUSIVE_POS = 0x2, + UID_POS = 0x3 }; inline void setNested(bool nested) { setBitmaskAtPos(NESTED_POS, nested); } @@ -376,6 +377,8 @@ public: inline void setExclusiveState(bool exclusive) { setBitmaskAtPos(EXCLUSIVE_POS, exclusive); } + inline void setUidField(bool isUid) { setBitmaskAtPos(UID_POS, isUid); } + inline void setResetState(int resetState) { mResetState = resetState; } // Default value = false @@ -387,6 +390,9 @@ public: // Default value = false inline bool isExclusiveState() const { return getValueFromBitmask(EXCLUSIVE_POS); } + // Default value = false + inline bool isUidField() const { return getValueFromBitmask(UID_POS); } + // If a reset state is not sent in the StatsEvent, returns -1. Note that a // reset satate is only sent if and only if a reset should be triggered. inline int getResetState() const { return mResetState; } @@ -402,7 +408,7 @@ private: } // This is a bitmask over all annotations stored in boolean form. Because - // there are only 3 booleans, just one byte is required. + // there are only 4 booleans, just one byte is required. uint8_t mBooleanBitmask = 0; int mResetState = -1; @@ -449,7 +455,7 @@ int getUidIfExists(const FieldValue& value); void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output); bool isAttributionUidField(const Field& field, const Value& value); -bool isUidField(const Field& field, const Value& value); +bool isUidField(const FieldValue& fieldValue); bool equalDimensions(const std::vector<Matcher>& dimension_a, const std::vector<Matcher>& dimension_b); diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index 982a63e3e08c..325cbc7e80e5 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -138,13 +138,6 @@ void StatsLogProcessor::onPeriodicAlarmFired( } } -void updateUid(Value* value, int hostUid) { - int uid = value->int_value; - if (uid != hostUid) { - value->setInt(hostUid); - } -} - void StatsLogProcessor::mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const { if (android::util::AtomsInfo::kAtomsWithAttributionChain.find(event->GetTagId()) != android::util::AtomsInfo::kAtomsWithAttributionChain.end()) { @@ -154,22 +147,15 @@ void StatsLogProcessor::mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event } if (isAttributionUidField(value)) { const int hostUid = mUidMap->getHostUidOrSelf(value.mValue.int_value); - updateUid(&value.mValue, hostUid); + value.mValue.setInt(hostUid); } } } else { - auto it = android::util::AtomsInfo::kAtomsWithUidField.find(event->GetTagId()); - if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) { - int uidField = it->second; // uidField is the field number in proto, - // starting from 1 - if (uidField > 0 && (int)event->getValues().size() >= uidField && - (event->getValues())[uidField - 1].mValue.getType() == INT) { - Value& value = (*event->getMutableValues())[uidField - 1].mValue; - const int hostUid = mUidMap->getHostUidOrSelf(value.int_value); - updateUid(&value, hostUid); - } else { - ALOGE("Malformed log, uid not found. %s", event->ToString().c_str()); - } + int uidFieldIndex = event->getUidFieldIndex(); + if (uidFieldIndex != -1) { + Value& value = (*event->getMutableValues())[uidFieldIndex].mValue; + const int hostUid = mUidMap->getHostUidOrSelf(value.int_value); + value.setInt(hostUid); } } } diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 9169eb1778d9..dd1d40083a6b 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -1054,6 +1054,14 @@ Status StatsService::statsCompanionReady() { return Status::ok(); } +Status StatsService::bootCompleted() { + ENFORCE_UID(AID_SYSTEM); + + VLOG("StatsService::bootCompleted was called"); + + return Status::ok(); +} + void StatsService::Startup() { mConfigManager->Startup(); mProcessor->LoadActiveConfigsFromDisk(); @@ -1215,6 +1223,14 @@ Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) { return Status::ok(); } +Status StatsService::allPullersFromBootRegistered() { + ENFORCE_UID(AID_SYSTEM); + + VLOG("StatsService::allPullersFromBootRegistered was called"); + + return Status::ok(); +} + Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownMillis, int64_t timeoutMillis, const std::vector<int32_t>& additiveFields, diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 114c84f953c8..23d4c1bd199d 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -64,6 +64,7 @@ public: virtual Status systemRunning(); virtual Status statsCompanionReady(); + virtual Status bootCompleted(); virtual Status informAnomalyAlarmFired(); virtual Status informPollAlarmFired(); virtual Status informAlarmForSubscriberTriggeringFired(); @@ -165,6 +166,11 @@ public: virtual Status sendAppBreadcrumbAtom(int32_t label, int32_t state) override; /** + * Binder call to notify statsd that all pullers from boot have been registered. + */ + virtual Status allPullersFromBootRegistered(); + + /** * Binder call to register a callback function for a pulled atom. */ virtual Status registerPullAtomCallback( diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index bd15264c008f..1f090fda2ce7 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -384,12 +384,12 @@ message Atom { PerfettoUploaded perfetto_uploaded = 229 [(module) = "perfetto"]; VmsClientConnectionStateChanged vms_client_connection_state_changed = 230 [(module) = "car"]; - MediaProviderScanEvent media_provider_scan_event = 233 [(module) = "mediaprovider"]; - MediaProviderDeletionEvent media_provider_deletion_event = 234 [(module) = "mediaprovider"]; - MediaProviderPermissionEvent media_provider_permission_event = + MediaProviderScanOccurred media_provider_scan_occurred = 233 [(module) = "mediaprovider"]; + MediaContentDeleted media_content_deleted = 234 [(module) = "mediaprovider"]; + MediaProviderPermissionRequested media_provider_permission_requested = 235 [(module) = "mediaprovider"]; - MediaProviderSchemaChange media_provider_schema_change = 236 [(module) = "mediaprovider"]; - MediaProviderIdleMaintenance media_provider_idle_maintenance = + MediaProviderSchemaChanged media_provider_schema_changed = 236 [(module) = "mediaprovider"]; + MediaProviderIdleMaintenanceFinished media_provider_idle_maintenance_finished = 237 [(module) = "mediaprovider"]; RebootEscrowRecoveryReported reboot_escrow_recovery_reported = 238 [(module) = "framework"]; BootTimeEventDuration boot_time_event_duration_reported = 239 [(module) = "framework"]; @@ -418,7 +418,9 @@ message Atom { AppStandbyBucketChanged app_standby_bucket_changed = 258 [(module) = "framework"]; SharesheetStarted sharesheet_started = 259 [(module) = "framework"]; RankingSelected ranking_selected = 260 [(module) = "framework"]; - TvSettingsUIInteracted tvsettings_ui_interacted = 261; + TvSettingsUIInteracted tvsettings_ui_interacted = 261 [(module) = "tv_settings"]; + LauncherStaticLayout launcher_snapshot = 262 [(module) = "sysui"]; + PackageInstallerV2Reported package_installer_v2_reported = 263 [(module) = "framework"]; SdkExtensionStatus sdk_extension_status = 354; } @@ -2979,14 +2981,98 @@ message ExclusionRectStateChanged { optional int32 duration_millis = 7; } +/** + * Logs when Launcher (HomeScreen) UI has changed or was interacted. + * + * Logged from: + * packages/apps/Launcher3 + */ message LauncherUIChanged { - optional android.stats.launcher.LauncherAction action = 1; + optional android.stats.launcher.LauncherAction action = 1 [deprecated = true]; optional android.stats.launcher.LauncherState src_state = 2; optional android.stats.launcher.LauncherState dst_state = 3; - optional android.stats.launcher.LauncherExtension extension = 4 [(log_mode) = MODE_BYTES]; - optional bool is_swipe_up_enabled = 5; + optional android.stats.launcher.LauncherExtension extension = 4 [(log_mode) = MODE_BYTES, deprecated = true]; + optional bool is_swipe_up_enabled = 5 [deprecated = true]; + + // The event id (e.g., app launch, drag and drop, long press) + optional int32 event_id = 6; + // The event's source or target id (e.g., icon, task, button) + optional int32 target_id = 7; + // If the target needs to be tracked, use this id field + optional int32 instance_id = 8; + optional int32 uid = 9 [(is_uid) = true]; + optional string package_name = 10; + optional string component_name = 11; + + // (x, y) coordinate and the index information of the target on the container + optional int32 grid_x = 12; + optional int32 grid_y = 13; + optional int32 page_id = 14; + + // e.g., folder icon's (x, y) location and index information on the workspace + optional int32 grid_x_parent = 15; + optional int32 grid_y_parent = 16; + optional int32 page_id_parent = 17; + + // e.g., SEARCHBOX_ALLAPPS, FOLDER_WORKSPACE + optional int32 hierarchy = 18; + + optional bool is_work_profile = 19; + + // Used to store the predicted rank of the target + optional int32 rank = 20; + + // e.g., folderLabelState can be captured in the following two fields + optional int32 from_state = 21; + optional int32 to_state = 22; + + // e.g., autofilled or suggested texts that are not user entered + optional string edittext = 23; +} + +/** + * Used for snapshot of the HomeScreen UI elements + * + * Logged from: + * packages/apps/Launcher3 + */ +message LauncherStaticLayout { + // The event id (e.g., snapshot, drag and drop) + optional int32 event_id = 1; + // The event's source or target id (e.g., icon, shortcut, widget) + optional int32 target_id = 2; + // If the target needs to be tracked, use this id field + optional int32 instance_id = 3; + optional int32 uid = 4 [(is_uid) = true]; + optional string package_name = 5; + optional string component_name = 6; + + // (x, y) coordinate and the index information of the target on the container + optional int32 grid_x = 7; + optional int32 grid_y = 8; + optional int32 page_id = 9; + + // e.g., folder icon's (x, y) location and index information on the workspace + optional int32 grid_x_parent = 10; + optional int32 grid_y_parent = 11; + optional int32 page_id_parent = 12; + + // e.g., WORKSPACE, HOTSEAT, FOLDER_WORKSPACE, FOLDER_HOTSEAT + optional int32 hierarchy = 13; + + optional bool is_work_profile = 14; + + // e.g., PIN, WIDGET TRAY, APPS TRAY, PREDICTION + optional int32 origin = 15; } +/** + * Logs when Wallpaper or ThemePicker UI has changed. + * + * Logged from: + * packages/apps/ThemePicker + * packages/apps/WallpaperPicker2 + */ message StyleUIChanged { optional android.stats.style.Action action = 1; optional int32 color_package_hash = 2; @@ -4370,7 +4456,7 @@ message VmsClientConnectionStateChanged { * Logged from: * packages/providers/MediaProvider/src/com/android/providers/media/scan/ModernMediaScanner.java */ -message MediaProviderScanEvent { +message MediaProviderScanOccurred { enum Reason { // Scan triggered due to unknown reason UNKNOWN = 0; @@ -4404,15 +4490,13 @@ message MediaProviderScanEvent { * Logged from: * packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java */ -message MediaProviderDeletionEvent { +message MediaContentDeleted { // Volume type that this event pertains to optional android.stats.mediaprovider.VolumeType volume_type = 1; - // Device timestamp when this deletion event occurred - optional int64 timestamp_millis = 2; - // App that requested deletion - optional string package_name = 3; + // UID of app that requested deletion + optional int32 uid = 2 [(is_uid) = true]; // Number of items that were deleted - optional int32 item_count = 4; + optional int32 item_count = 3; } /** @@ -4421,7 +4505,7 @@ message MediaProviderDeletionEvent { * Logged from: * packages/providers/MediaProvider/src/com/android/providers/media/PermissionActivity.java */ -message MediaProviderPermissionEvent { +message MediaProviderPermissionRequested { enum Result { UNKNOWN = 0; USER_GRANTED = 1; @@ -4433,14 +4517,12 @@ message MediaProviderPermissionEvent { // Volume type that this event pertains to optional android.stats.mediaprovider.VolumeType volume_type = 1; - // Device timestamp when this permission event occurred - optional int64 timestamp_millis = 2; - // App that requested permission - optional string package_name = 3; + // UID of app that requested permission + optional int32 uid = 2 [(is_uid) = true]; // Number of items that were requested - optional int32 item_count = 4; + optional int32 item_count = 3; // Result of this request - optional Result result = 5; + optional Result result = 4; } /** @@ -4449,7 +4531,7 @@ message MediaProviderPermissionEvent { * Logged from: * packages/providers/MediaProvider/src/com/android/providers/media/DatabaseHelper.java */ -message MediaProviderSchemaChange { +message MediaProviderSchemaChanged { // Volume type that this event pertains to optional android.stats.mediaprovider.VolumeType volume_type = 1; // Old database version code @@ -4468,7 +4550,7 @@ message MediaProviderSchemaChange { * Logged from: * packages/providers/MediaProvider/src/com/android/providers/media/MediaProvider.java */ -message MediaProviderIdleMaintenance { +message MediaProviderIdleMaintenanceFinished { // Volume type that this event pertains to optional android.stats.mediaprovider.VolumeType volume_type = 1; @@ -9167,12 +9249,13 @@ message SharesheetStarted { optional bool is_workprofile = 7; enum SharesheetPreviewType { // Constants from ChooserActivity.java + CONTENT_PREVIEW_TYPE_UNKNOWN = 0; // Default for proto 2 / 3 compatibility. CONTENT_PREVIEW_IMAGE = 1; // The preview shown in the sharesheet is an image. CONTENT_PREVIEW_FILE = 2; // The preview shown in the sharesheet is a file. CONTENT_PREVIEW_TEXT = 3; // The preview shown in the sharesheet is text. } // How the sharesheet preview is presented. - optional SharesheetPreviewType previewType = 8; + optional SharesheetPreviewType preview_type = 8; enum ResolverActivityIntent { // Intents handled by ResolverActivity.java INTENT_DEFAULT = 0; @@ -9185,7 +9268,7 @@ message SharesheetStarted { INTENT_ACTION_MAIN = 7; } // The intent being processed (only SEND and SEND_MULTIPLE are system sharesheet) - optional ResolverActivityIntent intentType = 9; + optional ResolverActivityIntent intent_type = 9; } /** @@ -9223,6 +9306,25 @@ message TvSettingsUIInteracted { } /** + * Logs information about a package installation using package installer V2 APIs. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java + */ +message PackageInstallerV2Reported { + // Whether this installation uses Incremental File System + optional bool is_incremental = 1; + // Name of the package that is intended to be installed + optional string package_name = 2; + // The duration between when the install was requested to when the install has completed + optional int64 duration_millis = 3; + // Installation result in final integer, which are SystemApi's. + // Return_code 1 indicates success. + // For full list, see frameworks/base/core/java/android/content/pm/PackageManager.java + optional int32 return_code = 4; +} + +/** * Logs settings provider values. * * Use DeviceConfig.getProperties to get a list Setting key, query the data from content provider, diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp index 6d9c644bb40e..bbae3fef7934 100644 --- a/cmds/statsd/src/config/ConfigManager.cpp +++ b/cmds/statsd/src/config/ConfigManager.cpp @@ -43,20 +43,23 @@ using android::base::StringPrintf; using std::unique_ptr; struct ConfigReceiverDeathCookie { - ConfigReceiverDeathCookie(sp<ConfigManager> configManager, const ConfigKey& configKey, - const shared_ptr<IPendingIntentRef>& pir): - mConfigManager(configManager), - mConfigKey(configKey), - mPir(pir) {} + ConfigReceiverDeathCookie(const wp<ConfigManager>& configManager, const ConfigKey& configKey, + const shared_ptr<IPendingIntentRef>& pir) : + mConfigManager(configManager), mConfigKey(configKey), mPir(pir) { + } - sp<ConfigManager> mConfigManager; + wp<ConfigManager> mConfigManager; ConfigKey mConfigKey; shared_ptr<IPendingIntentRef> mPir; }; void ConfigManager::configReceiverDied(void* cookie) { auto cookie_ = static_cast<ConfigReceiverDeathCookie*>(cookie); - sp<ConfigManager>& thiz = cookie_->mConfigManager; + sp<ConfigManager> thiz = cookie_->mConfigManager.promote(); + if (!thiz) { + return; + } + ConfigKey& configKey = cookie_->mConfigKey; shared_ptr<IPendingIntentRef>& pir = cookie_->mPir; @@ -74,20 +77,23 @@ void ConfigManager::configReceiverDied(void* cookie) { } struct ActiveConfigChangedReceiverDeathCookie { - ActiveConfigChangedReceiverDeathCookie(sp<ConfigManager> configManager, const int uid, - const shared_ptr<IPendingIntentRef>& pir): - mConfigManager(configManager), - mUid(uid), - mPir(pir) {} + ActiveConfigChangedReceiverDeathCookie(const wp<ConfigManager>& configManager, const int uid, + const shared_ptr<IPendingIntentRef>& pir) : + mConfigManager(configManager), mUid(uid), mPir(pir) { + } - sp<ConfigManager> mConfigManager; + wp<ConfigManager> mConfigManager; int mUid; shared_ptr<IPendingIntentRef> mPir; }; void ConfigManager::activeConfigChangedReceiverDied(void* cookie) { auto cookie_ = static_cast<ActiveConfigChangedReceiverDeathCookie*>(cookie); - sp<ConfigManager>& thiz = cookie_->mConfigManager; + sp<ConfigManager> thiz = cookie_->mConfigManager.promote(); + if (!thiz) { + return; + } + int uid = cookie_->mUid; shared_ptr<IPendingIntentRef>& pir = cookie_->mPir; diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 79a7e8d318e2..ebe961014336 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -44,19 +44,23 @@ namespace statsd { // Stores the puller as a wp to avoid holding a reference in case it is unregistered and // pullAtomCallbackDied is never called. struct PullAtomCallbackDeathCookie { - PullAtomCallbackDeathCookie(sp<StatsPullerManager> pullerManager, const PullerKey& pullerKey, - const wp<StatsPuller>& puller) - : mPullerManager(pullerManager), mPullerKey(pullerKey), mPuller(puller) { + PullAtomCallbackDeathCookie(const wp<StatsPullerManager>& pullerManager, + const PullerKey& pullerKey, const wp<StatsPuller>& puller) : + mPullerManager(pullerManager), mPullerKey(pullerKey), mPuller(puller) { } - sp<StatsPullerManager> mPullerManager; + wp<StatsPullerManager> mPullerManager; PullerKey mPullerKey; wp<StatsPuller> mPuller; }; void StatsPullerManager::pullAtomCallbackDied(void* cookie) { PullAtomCallbackDeathCookie* cookie_ = static_cast<PullAtomCallbackDeathCookie*>(cookie); - sp<StatsPullerManager>& thiz = cookie_->mPullerManager; + sp<StatsPullerManager> thiz = cookie_->mPullerManager.promote(); + if (!thiz) { + return; + } + const PullerKey& pullerKey = cookie_->mPullerKey; wp<StatsPuller> puller = cookie_->mPuller; diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp index aee725698c30..90247cf9d68c 100644 --- a/cmds/statsd/src/external/puller_util.cpp +++ b/cmds/statsd/src/external/puller_util.cpp @@ -49,10 +49,14 @@ using namespace std; */ void mapAndMergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap, int tagId, const vector<int>& additiveFieldsVec) { - if ((android::util::AtomsInfo::kAtomsWithAttributionChain.find(tagId) == - android::util::AtomsInfo::kAtomsWithAttributionChain.end()) && - (android::util::AtomsInfo::kAtomsWithUidField.find(tagId) == - android::util::AtomsInfo::kAtomsWithUidField.end())) { + bool hasAttributionChain = (android::util::AtomsInfo::kAtomsWithAttributionChain.find(tagId) != + android::util::AtomsInfo::kAtomsWithAttributionChain.end()); + // To check if any LogEvent has a uid field, we can just check the first + // LogEvent because all atoms with this tagId should have the uid + // annotation. + bool hasUidField = (data[0]->getUidFieldIndex() != -1); + + if (!hasAttributionChain && !hasUidField) { VLOG("No uid or attribution chain to merge, atom %d", tagId); return; } @@ -75,19 +79,13 @@ void mapAndMergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const } } } else { - auto it = android::util::AtomsInfo::kAtomsWithUidField.find(tagId); - if (it != android::util::AtomsInfo::kAtomsWithUidField.end()) { - int uidField = it->second; // uidField is the field number in proto, - // starting from 1 - if (uidField > 0 && (int)event->getValues().size() >= uidField && - (event->getValues())[uidField - 1].mValue.getType() == INT) { - Value& value = (*event->getMutableValues())[uidField - 1].mValue; - const int hostUid = uidMap->getHostUidOrSelf(value.int_value); - value.setInt(hostUid); - } else { - ALOGE("Malformed log, uid not found. %s", event->ToString().c_str()); - return; - } + int uidFieldIndex = event->getUidFieldIndex(); + if (uidFieldIndex != -1) { + Value& value = (*event->getMutableValues())[uidFieldIndex].mValue; + const int hostUid = uidMap->getHostUidOrSelf(value.int_value); + value.setInt(hostUid); + } else { + ALOGE("Malformed log, uid not found. %s", event->ToString().c_str()); } } } diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index 96bf04f4f6d6..8b6a86464155 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -240,14 +240,20 @@ void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last, last[1] = last[2] = false; } +// Assumes that mValues is not empty +bool LogEvent::checkPreviousValueType(Type expected) { + return mValues[mValues.size() - 1].mValue.getType() == expected; +} + void LogEvent::parseIsUidAnnotation(uint8_t annotationType) { - if (mValues.empty() || annotationType != BOOL_TYPE) { + if (mValues.empty() || !checkPreviousValueType(INT) || annotationType != BOOL_TYPE) { mValid = false; return; } bool isUid = readNextValue<uint8_t>(); if (isUid) mUidFieldIndex = mValues.size() - 1; + mValues[mValues.size() - 1].mAnnotations.setUidField(isUid); } void LogEvent::parseTruncateTimestampAnnotation(uint8_t annotationType) { diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index 9e21c777e6ff..4eeb7d64a463 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -213,6 +213,7 @@ private: void parseExclusiveStateAnnotation(uint8_t annotationType); void parseTriggerStateResetAnnotation(uint8_t annotationType); void parseStateNestedAnnotation(uint8_t annotationType); + bool checkPreviousValueType(Type expected); /** * The below three variables are only valid during the execution of diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp index 1f8bbd7f528c..2b4c6a3cbf1e 100644 --- a/cmds/statsd/src/matchers/matcher_util.cpp +++ b/cmds/statsd/src/matchers/matcher_util.cpp @@ -81,18 +81,17 @@ bool combinationMatch(const vector<int>& children, const LogicalOperation& opera return matched; } -bool tryMatchString(const UidMap& uidMap, const Field& field, const Value& value, - const string& str_match) { - if (isAttributionUidField(field, value) || isUidField(field, value)) { - int uid = value.int_value; +bool tryMatchString(const UidMap& uidMap, const FieldValue& fieldValue, const string& str_match) { + if (isAttributionUidField(fieldValue) || isUidField(fieldValue)) { + int uid = fieldValue.mValue.int_value; auto aidIt = UidMap::sAidToUidMapping.find(str_match); if (aidIt != UidMap::sAidToUidMapping.end()) { return ((int)aidIt->second) == uid; } std::set<string> packageNames = uidMap.getAppNamesFromUid(uid, true /* normalize*/); return packageNames.find(str_match) != packageNames.end(); - } else if (value.getType() == STRING) { - return value.str_value == str_match; + } else if (fieldValue.mValue.getType() == STRING) { + return fieldValue.mValue.str_value == str_match; } return false; } @@ -228,8 +227,7 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, } case FieldValueMatcher::ValueMatcherCase::kEqString: { for (int i = start; i < end; i++) { - if (tryMatchString(uidMap, values[i].mField, values[i].mValue, - matcher.eq_string())) { + if (tryMatchString(uidMap, values[i], matcher.eq_string())) { return true; } } @@ -240,7 +238,7 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, for (int i = start; i < end; i++) { bool notEqAll = true; for (const auto& str : str_list.str_value()) { - if (tryMatchString(uidMap, values[i].mField, values[i].mValue, str)) { + if (tryMatchString(uidMap, values[i], str)) { notEqAll = false; break; } @@ -255,7 +253,7 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, const auto& str_list = matcher.eq_any_string(); for (int i = start; i < end; i++) { for (const auto& str : str_list.str_value()) { - if (tryMatchString(uidMap, values[i].mField, values[i].mValue, str)) { + if (tryMatchString(uidMap, values[i], str)) { return true; } } diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index ed98f50bcc48..f4247eca6e23 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -181,12 +181,15 @@ message GaugeBucketInfo { message GaugeMetricData { optional DimensionsValue dimensions_in_what = 1; - optional DimensionsValue dimensions_in_condition = 2 [deprecated = true]; + // Currently unsupported + repeated StateValue slice_by_state = 6; repeated GaugeBucketInfo bucket_info = 3; repeated DimensionsValue dimension_leaf_values_in_what = 4; + optional DimensionsValue dimensions_in_condition = 2 [deprecated = true]; + repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true]; } diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp index 0bf24f1d3606..f5ba8fd0d60d 100644 --- a/cmds/statsd/tests/FieldValue_test.cpp +++ b/cmds/statsd/tests/FieldValue_test.cpp @@ -41,22 +41,10 @@ void makeLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timest AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, timestamp); - vector<const char*> cTags(attributionTags.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = attributionTags[i].c_str(); - } - - AStatsEvent_writeAttributionChain(statsEvent, - reinterpret_cast<const uint32_t*>(attributionUids.data()), - cTags.data(), attributionUids.size()); + writeAttribution(statsEvent, attributionUids, attributionTags); AStatsEvent_writeString(statsEvent, name.c_str()); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } void makeLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp, @@ -66,22 +54,10 @@ void makeLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timest AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, timestamp); - vector<const char*> cTags(attributionTags.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = attributionTags[i].c_str(); - } - - AStatsEvent_writeAttributionChain(statsEvent, - reinterpret_cast<const uint32_t*>(attributionUids.data()), - cTags.data(), attributionUids.size()); + writeAttribution(statsEvent, attributionUids, attributionTags); AStatsEvent_writeInt32(statsEvent, value); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } } // anonymous namespace diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp index 6f4c8e48eff2..26423d464027 100644 --- a/cmds/statsd/tests/LogEntryMatcher_test.cpp +++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp @@ -18,6 +18,7 @@ #include <log/logprint.h> #include <stdio.h> +#include "annotations.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" #include "matchers/matcher_util.h" #include "stats_event.h" @@ -48,15 +49,9 @@ void makeIntLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t tim AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, timestamp); - AStatsEvent_writeInt32(statsEvent, value); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } void makeFloatLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp, @@ -64,15 +59,9 @@ void makeFloatLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t t AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, timestamp); - AStatsEvent_writeFloat(statsEvent, floatValue); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } void makeStringLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp, @@ -80,32 +69,20 @@ void makeStringLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, timestamp); - AStatsEvent_writeString(statsEvent, name.c_str()); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } -void makeIntStringLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp, - const int32_t value, const string& name) { +void makeIntWithBoolAnnotationLogEvent(LogEvent* logEvent, const int32_t atomId, + const int32_t field, const uint8_t annotationId, + const bool annotationValue) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); - AStatsEvent_overwriteTimestamp(statsEvent, timestamp); - - AStatsEvent_writeInt32(statsEvent, value); - AStatsEvent_writeString(statsEvent, name.c_str()); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); + AStatsEvent_writeInt32(statsEvent, field); + AStatsEvent_addBoolAnnotation(statsEvent, annotationId, annotationValue); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } void makeAttributionLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp, @@ -115,22 +92,10 @@ void makeAttributionLogEvent(LogEvent* logEvent, const int32_t atomId, const int AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, timestamp); - vector<const char*> cTags(attributionTags.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = attributionTags[i].c_str(); - } - - AStatsEvent_writeAttributionChain(statsEvent, - reinterpret_cast<const uint32_t*>(attributionUids.data()), - cTags.data(), attributionUids.size()); + writeAttribution(statsEvent, attributionUids, attributionTags); AStatsEvent_writeString(statsEvent, name.c_str()); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } void makeBoolLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp, @@ -141,13 +106,8 @@ void makeBoolLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t ti AStatsEvent_writeBool(statsEvent, bool1); AStatsEvent_writeBool(statsEvent, bool2); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } } // anonymous namespace @@ -416,21 +376,20 @@ TEST(AtomMatcherTest, TestUidFieldMatcher) { simpleMatcher->add_field_value_matcher()->set_field(1); simpleMatcher->mutable_field_value_matcher(0)->set_eq_string("pkg0"); - // Set up the event + // Make event without is_uid annotation. LogEvent event1(/*uid=*/0, /*pid=*/0); makeIntLogEvent(&event1, TAG_ID, 0, 1111); + EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1)); + // Make event with is_uid annotation. LogEvent event2(/*uid=*/0, /*pid=*/0); - makeIntStringLogEvent(&event2, TAG_ID_2, 0, 1111, "some value"); - - // Tag not in kAtomsWithUidField - EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1)); + makeIntWithBoolAnnotationLogEvent(&event2, TAG_ID_2, 1111, ANNOTATION_ID_IS_UID, true); - // Tag found in kAtomsWithUidField and has matching uid + // Event has is_uid annotation, so mapping from uid to package name occurs. simpleMatcher->set_atom_id(TAG_ID_2); EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2)); - // Tag found in kAtomsWithUidField but has non-matching uid + // Event has is_uid annotation, but uid maps to different package name. simpleMatcher->mutable_field_value_matcher(0)->set_eq_string("Pkg2"); EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2)); } diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp index 9e7b7c820e0d..d29394b1c5a6 100644 --- a/cmds/statsd/tests/StatsLogProcessor_test.cpp +++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp @@ -1564,7 +1564,7 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) { // Trigger Activation 1 for Metric 1. Should activate on boot. // Trigger Activation 4 for Metric 2. Should activate immediately. - long configAddedTimeNs = metricsManager1->mLastReportTimeNs; + int64_t configAddedTimeNs = metricsManager1->mLastReportTimeNs; std::vector<int> attributionUids = {111}; std::vector<string> attributionTags = {"App1"}; std::unique_ptr<LogEvent> event1 = CreateAcquireWakelockEvent( diff --git a/cmds/statsd/tests/StatsService_test.cpp b/cmds/statsd/tests/StatsService_test.cpp index 86f786ef4b15..cc38c4a4067a 100644 --- a/cmds/statsd/tests/StatsService_test.cpp +++ b/cmds/statsd/tests/StatsService_test.cpp @@ -65,7 +65,6 @@ TEST(StatsServiceTest, TestGetUidFromArgs) { args.push(String8("-1")); args.push(String8("0")); args.push(String8("1")); - args.push(String8("9999999999999999999999999999999999")); args.push(String8("a1")); args.push(String8("")); @@ -85,14 +84,11 @@ TEST(StatsServiceTest, TestGetUidFromArgs) { EXPECT_TRUE(service->getUidFromArgs(args, 2, uid)); EXPECT_EQ(1, uid); - // "999999999999999999" - EXPECT_FALSE(service->getUidFromArgs(args, 3, uid)); - // "a1" - EXPECT_FALSE(service->getUidFromArgs(args, 4, uid)); + EXPECT_FALSE(service->getUidFromArgs(args, 3, uid)); // "" - EXPECT_FALSE(service->getUidFromArgs(args, 5, uid)); + EXPECT_FALSE(service->getUidFromArgs(args, 4, uid)); // For a non-userdebug, uid "1" cannot be impersonated. service->mEngBuild = false; diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp index 7febb35355a3..ba5b032b80d0 100644 --- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp +++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp @@ -67,22 +67,12 @@ void makeWakeLockEvent(LogEvent* logEvent, uint32_t atomId, uint64_t timestamp, AStatsEvent_overwriteTimestamp(statsEvent, timestamp); vector<std::string> tags(uids.size()); // vector of empty strings - vector<const char*> cTags(uids.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = tags[i].c_str(); - } - AStatsEvent_writeAttributionChain(statsEvent, reinterpret_cast<const uint32_t*>(uids.data()), - cTags.data(), uids.size()); + writeAttribution(statsEvent, uids, tags); AStatsEvent_writeString(statsEvent, wl.c_str()); AStatsEvent_writeInt32(statsEvent, acquire); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } } // anonymous namespace diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp index 69326cb3b2d9..a5da9c8a6f56 100644 --- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp @@ -141,36 +141,38 @@ TEST(CountMetricE2eTest, TestSlicedState) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); - EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(3, countMetrics.data_size()); // For each CountMetricData, check StateValue info is correct and buckets // have correct counts. - auto data = reports.reports(0).metrics(0).count_metrics().data(0); + auto data = countMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value()); - EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, + data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - EXPECT_EQ(1, data.bucket_info(1).count()); - data = reports.reports(0).metrics(0).count_metrics().data(1); + data = countMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, - data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value()); + ASSERT_EQ(2, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); - data = reports.reports(0).metrics(0).count_metrics().data(2); + data = countMetrics.data(2); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value()); - EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value()); + ASSERT_EQ(2, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - EXPECT_EQ(2, data.bucket_info(1).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); } /** @@ -191,7 +193,9 @@ TEST(CountMetricE2eTest, TestSlicedStateWithMap) { auto syncStartMatcher = CreateSyncStartAtomMatcher(); *config.add_atom_matcher() = syncStartMatcher; - auto state = CreateScreenStateWithOnOffMap(); + int64_t screenOnId = 4444; + int64_t screenOffId = 9876; + auto state = CreateScreenStateWithOnOffMap(screenOnId, screenOffId); *config.add_state() = state; // Create count metric that slices by screen state with on/off map. @@ -321,11 +325,13 @@ TEST(CountMetricE2eTest, TestSlicedStateWithMap) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); - EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(3, countMetrics.data_size()); // For each CountMetricData, check StateValue info is correct and buckets // have correct counts. - auto data = reports.reports(0).metrics(0).count_metrics().data(0); + auto data = countMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -333,23 +339,23 @@ TEST(CountMetricE2eTest, TestSlicedStateWithMap) { EXPECT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(1); + data = countMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id()); EXPECT_EQ(2, data.bucket_info_size()); - EXPECT_EQ(4, data.bucket_info(0).count()); - EXPECT_EQ(2, data.bucket_info(1).count()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); - data = reports.reports(0).metrics(0).count_metrics().data(2); + data = countMetrics.data(2); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); EXPECT_EQ(2, data.bucket_info_size()); - EXPECT_EQ(1, data.bucket_info(0).count()); - EXPECT_EQ(1, data.bucket_info(1).count()); + EXPECT_EQ(4, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); } /** @@ -499,50 +505,52 @@ TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); - EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(5, countMetrics.data_size()); // For each CountMetricData, check StateValue info is correct and buckets // have correct counts. - auto data = reports.reports(0).metrics(0).count_metrics().data(0); + auto data = countMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(1); + data = countMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(2); + data = countMetrics.data(2); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(2, data.bucket_info(0).count()); + EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value()); + ASSERT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); - data = reports.reports(0).metrics(0).count_metrics().data(3); + data = countMetrics.data(3); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(2, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(4); + data = countMetrics.data(4); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value()); - EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - EXPECT_EQ(2, data.bucket_info(1).count()); } TEST(CountMetricE2eTest, TestMultipleSlicedStates) { @@ -554,7 +562,9 @@ TEST(CountMetricE2eTest, TestMultipleSlicedStates) { CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED); *config.add_atom_matcher() = appCrashMatcher; - auto state1 = CreateScreenStateWithOnOffMap(); + int64_t screenOnId = 4444; + int64_t screenOffId = 9876; + auto state1 = CreateScreenStateWithOnOffMap(screenOnId, screenOffId); *config.add_state() = state1; auto state2 = CreateUidProcessState(); *config.add_state() = state2; @@ -725,76 +735,78 @@ TEST(CountMetricE2eTest, TestMultipleSlicedStates) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); - EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size()); + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(6, countMetrics.data_size()); // For each CountMetricData, check StateValue info is correct and buckets // have correct counts. - auto data = reports.reports(0).metrics(0).count_metrics().data(0); + auto data = countMetrics.data(0); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); - EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(-1, data.slice_by_state(0).value()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(1); + data = countMetrics.data(1); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); - EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(-1, data.slice_by_state(0).value()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); - EXPECT_EQ(1, data.bucket_info_size()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(2); + data = countMetrics.data(2); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); - EXPECT_EQ(2, data.bucket_info_size()); - EXPECT_EQ(2, data.bucket_info(0).count()); - EXPECT_EQ(1, data.bucket_info(1).count()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(3); + data = countMetrics.data(3); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(4); + data = countMetrics.data(4); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(5); + data = countMetrics.data(5); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); + ASSERT_EQ(2, data.bucket_info_size()); EXPECT_EQ(2, data.bucket_info(0).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); } } // namespace statsd diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp index 2659944684e1..ba09a353e8b6 100644 --- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp @@ -98,8 +98,9 @@ TEST(DurationMetricE2eTest, TestOneBucket) { EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - const StatsLogReport::DurationMetricDataWrapper& durationMetrics = - reports.reports(0).metrics(0).duration_metrics(); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); EXPECT_EQ(1, durationMetrics.data_size()); DurationMetricData data = durationMetrics.data(0); @@ -180,8 +181,9 @@ TEST(DurationMetricE2eTest, TestTwoBuckets) { EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - const StatsLogReport::DurationMetricDataWrapper& durationMetrics = - reports.reports(0).metrics(0).duration_metrics(); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); EXPECT_EQ(1, durationMetrics.data_size()); DurationMetricData data = durationMetrics.data(0); @@ -350,8 +352,9 @@ TEST(DurationMetricE2eTest, TestWithActivation) { EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - const StatsLogReport::DurationMetricDataWrapper& durationMetrics = - reports.reports(0).metrics(0).duration_metrics(); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); EXPECT_EQ(1, durationMetrics.data_size()); DurationMetricData data = durationMetrics.data(0); @@ -433,9 +436,12 @@ TEST(DurationMetricE2eTest, TestWithCondition) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(1, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); // Validate bucket info. EXPECT_EQ(1, data.bucket_info_size()); @@ -532,9 +538,12 @@ TEST(DurationMetricE2eTest, TestWithSlicedCondition) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(1, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); // Validate dimension value. ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED, appUid); @@ -690,9 +699,12 @@ TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(1, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); // Validate dimension value. ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED, appUid); @@ -811,9 +823,12 @@ TEST(DurationMetricE2eTest, TestWithSlicedState) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - EXPECT_EQ(3, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(3, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -826,7 +841,7 @@ TEST(DurationMetricE2eTest, TestWithSlicedState) { EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(370 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(1); + data = durationMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -839,7 +854,7 @@ TEST(DurationMetricE2eTest, TestWithSlicedState) { EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(370 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(2); + data = durationMetrics.data(2); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -970,9 +985,12 @@ TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - EXPECT_EQ(3, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(3, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -985,7 +1003,7 @@ TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState) { EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(420 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(2); + data = durationMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -998,7 +1016,7 @@ TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState) { EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(420 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(1); + data = durationMetrics.data(2); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -1020,7 +1038,9 @@ TEST(DurationMetricE2eTest, TestWithSlicedStateMapped) { auto batterySaverModePredicate = CreateBatterySaverModePredicate(); *config.add_predicate() = batterySaverModePredicate; - auto screenStateWithMap = CreateScreenStateWithOnOffMap(); + int64_t screenOnId = 4444; + int64_t screenOffId = 9876; + auto screenStateWithMap = CreateScreenStateWithOnOffMap(screenOnId, screenOffId); *config.add_state() = screenStateWithMap; // Create duration metric that slices by mapped screen state. @@ -1123,13 +1143,16 @@ TEST(DurationMetricE2eTest, TestWithSlicedStateMapped) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - EXPECT_EQ(2, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(2, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id()); EXPECT_EQ(2, data.bucket_info_size()); EXPECT_EQ(130 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); @@ -1138,11 +1161,11 @@ TEST(DurationMetricE2eTest, TestWithSlicedStateMapped) { EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(500 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(1); + data = durationMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); EXPECT_EQ(2, data.bucket_info_size()); EXPECT_EQ(70 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); @@ -1314,117 +1337,120 @@ TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - EXPECT_EQ(9, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(9, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1, - "wakelock2"); + "wakelock1"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(1); + data = durationMetrics.data(1); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1, - "wakelock2"); + "wakelock1"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(140 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + ASSERT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(240 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos()); + EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(2); - ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, - "wakelock1"); + data = durationMetrics.data(2); + ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1, + "wakelock2"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, + data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(3); + data = durationMetrics.data(3); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1, - "wakelock1"); + "wakelock2"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(2, data.bucket_info_size()); - EXPECT_EQ(240 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(140 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos()); - EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); - EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(4); + data = durationMetrics.data(4); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, "wakelock1"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, - data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(5); + data = durationMetrics.data(5); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, - "wakelock2"); + "wakelock1"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE, + EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(2, data.bucket_info_size()); - EXPECT_EQ(180 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos()); - EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); - EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(6); + data = durationMetrics.data(6); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, "wakelock2"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(15 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(7); - ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1, - "wakelock1"); + data = durationMetrics.data(7); + ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, + "wakelock2"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, + EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + ASSERT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(180 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos()); + EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(8); + data = durationMetrics.data(8); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, "wakelock2"); EXPECT_EQ(1, data.slice_by_state_size()); @@ -1432,7 +1458,7 @@ TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset) { EXPECT_TRUE(data.slice_by_state(0).has_value()); EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(70 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp index 81e1c05c1cf4..60403f2a3e0f 100644 --- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp +++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp @@ -84,14 +84,9 @@ std::unique_ptr<LogEvent> CreateAppStartOccurredEvent( AStatsEvent_writeString(statsEvent, calling_pkg_name.c_str()); AStatsEvent_writeInt32(statsEvent, is_instant_app); AStatsEvent_writeInt32(statsEvent, activity_start_msec); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp index f1e2744181ce..ba8d283cabe1 100644 --- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp @@ -391,7 +391,6 @@ TEST(MetricActivationE2eTest, TestCountMetric) { backfillStartEndTimestamp(&reports); EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size()); StatsLogReport::CountMetricDataWrapper countMetrics; sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); @@ -699,7 +698,6 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { backfillStartEndTimestamp(&reports); EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); StatsLogReport::CountMetricDataWrapper countMetrics; sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); @@ -1033,7 +1031,6 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { backfillStartEndTimestamp(&reports); EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); StatsLogReport::CountMetricDataWrapper countMetrics; sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); @@ -1257,7 +1254,6 @@ TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation) { backfillStartEndTimestamp(&reports); EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); StatsLogReport::CountMetricDataWrapper countMetrics; sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); @@ -1695,8 +1691,6 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { backfillStartEndTimestamp(&reports); EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(2, reports.reports(0).metrics_size()); - EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); - EXPECT_EQ(5, reports.reports(0).metrics(1).count_metrics().data_size()); StatsLogReport::CountMetricDataWrapper countMetrics; diff --git a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp index 6aff9ef80a71..4b9bac127dc8 100644 --- a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp +++ b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp @@ -190,13 +190,13 @@ TEST_F(StatsCallbackPullerTest, RegisterAndTimeout) { int32_t uid = 123; values.push_back(value); - StatsPullerManager pullerManager; - pullerManager.RegisterPullAtomCallback(uid, pullTagId, pullCoolDownNs, pullTimeoutNs, - vector<int32_t>(), cb); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + pullerManager->RegisterPullAtomCallback(uid, pullTagId, pullCoolDownNs, pullTimeoutNs, + vector<int32_t>(), cb); vector<shared_ptr<LogEvent>> dataHolder; int64_t startTimeNs = getElapsedRealtimeNs(); // Returns false, since StatsPuller code will evaluate the timeout. - EXPECT_FALSE(pullerManager.Pull(pullTagId, {uid}, &dataHolder)); + EXPECT_FALSE(pullerManager->Pull(pullTagId, {uid}, &dataHolder)); int64_t endTimeNs = getElapsedRealtimeNs(); int64_t actualPullDurationNs = endTimeNs - startTimeNs; diff --git a/cmds/statsd/tests/external/StatsPuller_test.cpp b/cmds/statsd/tests/external/StatsPuller_test.cpp index e8200d5c7f52..504335845cab 100644 --- a/cmds/statsd/tests/external/StatsPuller_test.cpp +++ b/cmds/statsd/tests/external/StatsPuller_test.cpp @@ -64,16 +64,10 @@ std::unique_ptr<LogEvent> createSimpleEvent(int64_t eventTimeNs, int64_t value) AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, pullTagId); AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs); - AStatsEvent_writeInt64(statsEvent, value); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp index 15425d8810dc..c2cfb371d329 100644 --- a/cmds/statsd/tests/external/puller_util_test.cpp +++ b/cmds/statsd/tests/external/puller_util_test.cpp @@ -21,8 +21,10 @@ #include <vector> #include "../metrics/metrics_test_helper.h" +#include "annotations.h" #include "stats_event.h" #include "statslog_statsdtest.h" +#include "tests/statsd_test_util.h" #ifdef __ANDROID__ @@ -52,15 +54,15 @@ int hostNonAdditiveData = 22; void extractIntoVector(vector<shared_ptr<LogEvent>> events, vector<vector<int>>& ret) { - ret.clear(); - status_t err; - for (const auto& event : events) { - vector<int> vec; - vec.push_back(event->GetInt(1, &err)); - vec.push_back(event->GetInt(2, &err)); - vec.push_back(event->GetInt(3, &err)); - ret.push_back(vec); - } + ret.clear(); + status_t err; + for (const auto& event : events) { + vector<int> vec; + vec.push_back(event->GetInt(1, &err)); + vec.push_back(event->GetInt(2, &err)); + vec.push_back(event->GetInt(3, &err)); + ret.push_back(vec); + } } std::shared_ptr<LogEvent> makeUidLogEvent(uint64_t timestampNs, int uid, int data1, int data2) { @@ -69,16 +71,12 @@ std::shared_ptr<LogEvent> makeUidLogEvent(uint64_t timestampNs, int uid, int dat AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); AStatsEvent_writeInt32(statsEvent, uid); + AStatsEvent_addBoolAnnotation(statsEvent, ANNOTATION_ID_IS_UID, true); AStatsEvent_writeInt32(statsEvent, data1); AStatsEvent_writeInt32(statsEvent, data2); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::shared_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -86,16 +84,10 @@ std::shared_ptr<LogEvent> makeNonUidAtomLogEvent(uint64_t timestampNs, int data1 AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, nonUidAtomTagId); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_writeInt32(statsEvent, data1); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::shared_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } diff --git a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp index 6dc041f9fb6e..a15f95bef358 100644 --- a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp +++ b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp @@ -21,6 +21,7 @@ #include <thread> #include "stats_event.h" +#include "tests/statsd_test_util.h" namespace android { namespace os { @@ -37,14 +38,9 @@ std::unique_ptr<LogEvent> makeLogEvent(uint64_t timestampNs) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, 10); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp index d55996cb1b7a..65f8de69711d 100644 --- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp @@ -46,26 +46,17 @@ void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId, string uid) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_writeString(statsEvent, uid.c_str()); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } } // namespace diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp index 6143dc0dc5d1..30f815962160 100644 --- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp @@ -26,6 +26,7 @@ #include "src/condition/ConditionWizard.h" #include "src/stats_log_util.h" #include "stats_event.h" +#include "tests/statsd_test_util.h" using namespace android::os::statsd; using namespace testing; @@ -48,12 +49,8 @@ void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } } // namespace diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp index e58bbb7893d7..97647a7e0867 100644 --- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp @@ -43,14 +43,9 @@ void makeLogEvent(LogEvent* logEvent, int32_t atomId, int64_t timestampNs, strin AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_writeString(statsEvent, str.c_str()); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } } // anonymous namespace diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp index 2fe05a4430c3..42d0d5d8c530 100644 --- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp @@ -64,14 +64,9 @@ shared_ptr<LogEvent> makeLogEvent(int32_t atomId, int64_t timestampNs, int32_t v AStatsEvent_writeInt32(statsEvent, value1); AStatsEvent_writeString(statsEvent, str1.c_str()); AStatsEvent_writeInt32(statsEvent, value2); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); - + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } } // anonymous namespace diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index b623a0978f18..3b4d646f0f2f 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -611,7 +611,7 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) { vector<shared_ptr<LogEvent>> allData; allData.clear(); - allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 110)); + allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8}); @@ -656,7 +656,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) { valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10); + CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); @@ -665,14 +665,14 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) { EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs); LogEvent event2(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 1, 10); + CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 10); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs); // Next value should create a new bucket. LogEvent event3(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 65 * NS_PER_SEC, 1, 10); + CreateRepeatedValueLogEvent(&event3, tagId, bucketStartTimeNs + 65 * NS_PER_SEC, 10); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, valueProducer.mCurrentBucketStartTimeNs); @@ -812,10 +812,10 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10); + CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10); LogEvent event2(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20); + CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); // has one slice @@ -856,7 +856,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { valueProducer.mCondition = ConditionState::kFalse; LogEvent event1(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10); + CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); // has 1 slice EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size()); @@ -864,7 +864,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15); LogEvent event2(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20); + CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); // has one slice @@ -875,7 +875,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { EXPECT_EQ(20, curInterval.value.long_value); LogEvent event3(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 30, 1, 30); + CreateRepeatedValueLogEvent(&event3, tagId, bucketStartTimeNs + 30, 30); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); // has one slice @@ -886,7 +886,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) { valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35); LogEvent event4(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event4, tagId, bucketStartTimeNs + 40, 1, 40); + CreateRepeatedValueLogEvent(&event4, tagId, bucketStartTimeNs + 40, 40); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4); // has one slice @@ -1195,10 +1195,10 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) { valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10); + CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10); LogEvent event2(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20); + CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); // has one slice @@ -1238,10 +1238,10 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) { valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10); + CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10); LogEvent event2(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20); + CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); // has one slice @@ -1283,10 +1283,10 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) { valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10); + CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10); LogEvent event2(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 15); + CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 15); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); @@ -1331,10 +1331,10 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) { valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10); + CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10); LogEvent event2(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 15); + CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 15); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); @@ -1374,10 +1374,10 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { valueProducer.prepareFirstBucket(); LogEvent event1(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10); + CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10); LogEvent event2(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 15, 1, 15); + CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 15, 15); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); // has one slice EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); @@ -1398,7 +1398,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { // no change in data. LogEvent event3(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event3, tagId, bucket2StartTimeNs + 10, 1, 15); + CreateRepeatedValueLogEvent(&event3, tagId, bucket2StartTimeNs + 10, 15); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -1408,7 +1408,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) { EXPECT_EQ(true, curInterval.hasValue); LogEvent event4(/*uid=*/0, /*pid=*/0); - CreateTwoValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 1, 15); + CreateRepeatedValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 15); valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4); EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size()); curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0]; @@ -2166,7 +2166,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed) // Bucket start. vector<shared_ptr<LogEvent>> allData; allData.clear(); - allData.push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 1, 1, 110)); + allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 110)); valueProducer->onDataPulled(allData, /** succeed */ false, bucketStartTimeNs); valueProducer->onConditionChanged(false, bucketStartTimeNs + 2); @@ -2174,7 +2174,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed) // Bucket end. allData.clear(); - allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 140)); + allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 140)); valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1); @@ -3726,7 +3726,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { return true; })); - const StateMap& stateMap = CreateScreenStateOnOffMap(); + const StateMap& stateMap = + CreateScreenStateOnOffMap(/*screen on id=*/321, /*screen off id=*/123); const StateMap_StateGroup screenOnGroup = stateMap.group(0); const StateMap_StateGroup screenOffGroup = stateMap.group(1); diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp index ac3ad690f81e..7b952d7a392e 100644 --- a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp +++ b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp @@ -171,13 +171,9 @@ shared_ptr<LogEvent> makeCpuActiveTimeAtom(int32_t uid, int64_t timeMillis) { AStatsEvent_overwriteTimestamp(statsEvent, 1111L); AStatsEvent_writeInt32(statsEvent, uid); AStatsEvent_writeInt64(statsEvent, timeMillis); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp index a5b8e1c50c33..78c80bc8307c 100644 --- a/cmds/statsd/tests/state/StateTracker_test.cpp +++ b/cmds/statsd/tests/state/StateTracker_test.cpp @@ -62,7 +62,7 @@ int getStateInt(StateManager& mgr, int atomId, const HashableDimensionKey& query // START: build event functions. // Incorrect event - missing fields -std::shared_ptr<LogEvent> buildIncorrectOverlayEvent(int uid, const std::string& packageName, +std::unique_ptr<LogEvent> buildIncorrectOverlayEvent(int uid, const std::string& packageName, int state) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, util::OVERLAY_STATE_CHANGED); @@ -72,14 +72,9 @@ std::shared_ptr<LogEvent> buildIncorrectOverlayEvent(int uid, const std::string& AStatsEvent_writeString(statsEvent, packageName.c_str()); // Missing field 3 - using_alert_window. AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -93,14 +88,9 @@ std::unique_ptr<LogEvent> buildOverlayEventBadStateType(int uid, const std::stri AStatsEvent_writeString(statsEvent, packageName.c_str()); AStatsEvent_writeInt32(statsEvent, true); // using_alert_window AStatsEvent_writeString(statsEvent, "string"); // exclusive state: string instead of int - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } // END: build event functions. diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index 7d765d3fbbf5..687014f6a298 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -324,40 +324,29 @@ State CreateOverlayState() { return state; } -State CreateScreenStateWithOnOffMap() { +State CreateScreenStateWithOnOffMap(int64_t screenOnId, int64_t screenOffId) { State state; state.set_id(StringToId("ScreenStateOnOff")); state.set_atom_id(util::SCREEN_STATE_CHANGED); - auto map = CreateScreenStateOnOffMap(); + auto map = CreateScreenStateOnOffMap(screenOnId, screenOffId); *state.mutable_map() = map; return state; } -State CreateScreenStateWithInDozeMap() { - State state; - state.set_id(StringToId("ScreenStateInDoze")); - state.set_atom_id(util::SCREEN_STATE_CHANGED); - - auto map = CreateScreenStateInDozeMap(); - *state.mutable_map() = map; - - return state; -} - -StateMap_StateGroup CreateScreenStateOnGroup() { +StateMap_StateGroup CreateScreenStateOnGroup(int64_t screenOnId) { StateMap_StateGroup group; - group.set_group_id(StringToId("SCREEN_ON")); + group.set_group_id(screenOnId); group.add_value(2); group.add_value(5); group.add_value(6); return group; } -StateMap_StateGroup CreateScreenStateOffGroup() { +StateMap_StateGroup CreateScreenStateOffGroup(int64_t screenOffId) { StateMap_StateGroup group; - group.set_group_id(StringToId("SCREEN_OFF")); + group.set_group_id(screenOffId); group.add_value(0); group.add_value(1); group.add_value(3); @@ -365,36 +354,10 @@ StateMap_StateGroup CreateScreenStateOffGroup() { return group; } -StateMap CreateScreenStateOnOffMap() { - StateMap map; - *map.add_group() = CreateScreenStateOnGroup(); - *map.add_group() = CreateScreenStateOffGroup(); - return map; -} - -StateMap_StateGroup CreateScreenStateInDozeGroup() { - StateMap_StateGroup group; - group.set_group_id(StringToId("SCREEN_DOZE")); - group.add_value(3); - group.add_value(4); - return group; -} - -StateMap_StateGroup CreateScreenStateNotDozeGroup() { - StateMap_StateGroup group; - group.set_group_id(StringToId("SCREEN_NOT_DOZE")); - group.add_value(0); - group.add_value(1); - group.add_value(2); - group.add_value(5); - group.add_value(6); - return group; -} - -StateMap CreateScreenStateInDozeMap() { +StateMap CreateScreenStateOnOffMap(int64_t screenOnId, int64_t screenOffId) { StateMap map; - *map.add_group() = CreateScreenStateInDozeGroup(); - *map.add_group() = CreateScreenStateNotDozeGroup(); + *map.add_group() = CreateScreenStateOnGroup(screenOnId); + *map.add_group() = CreateScreenStateOffGroup(screenOffId); return map; } @@ -507,23 +470,26 @@ void getPartialWakelockKey(int uid, HashableDimensionKey* key) { } // END: get primary key functions -shared_ptr<LogEvent> CreateTwoValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value1, - int32_t value2) { - AStatsEvent* statsEvent = AStatsEvent_obtain(); - AStatsEvent_setAtomId(statsEvent, atomId); - AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs); +void writeAttribution(AStatsEvent* statsEvent, const vector<int>& attributionUids, + const vector<string>& attributionTags) { + vector<const char*> cTags(attributionTags.size()); + for (int i = 0; i < cTags.size(); i++) { + cTags[i] = attributionTags[i].c_str(); + } - AStatsEvent_writeInt32(statsEvent, value1); - AStatsEvent_writeInt32(statsEvent, value2); + AStatsEvent_writeAttributionChain(statsEvent, + reinterpret_cast<const uint32_t*>(attributionUids.data()), + cTags.data(), attributionUids.size()); +} + +void parseStatsEventToLogEvent(AStatsEvent* statsEvent, LogEvent* logEvent) { AStatsEvent_build(statsEvent); size_t size; uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0); logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); - return logEvent; + AStatsEvent_release(statsEvent); } void CreateTwoValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs, int32_t value1, @@ -534,31 +500,14 @@ void CreateTwoValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs, AStatsEvent_writeInt32(statsEvent, value1); AStatsEvent_writeInt32(statsEvent, value2); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } -shared_ptr<LogEvent> CreateThreeValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value1, - int32_t value2, int32_t value3) { - AStatsEvent* statsEvent = AStatsEvent_obtain(); - AStatsEvent_setAtomId(statsEvent, atomId); - AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs); - - AStatsEvent_writeInt32(statsEvent, value1); - AStatsEvent_writeInt32(statsEvent, value2); - AStatsEvent_writeInt32(statsEvent, value3); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); +shared_ptr<LogEvent> CreateTwoValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value1, + int32_t value2) { shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); - + CreateTwoValueLogEvent(logEvent.get(), atomId, eventTimeNs, value1, value2); return logEvent; } @@ -571,29 +520,14 @@ void CreateThreeValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeN AStatsEvent_writeInt32(statsEvent, value1); AStatsEvent_writeInt32(statsEvent, value2); AStatsEvent_writeInt32(statsEvent, value3); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } -shared_ptr<LogEvent> CreateRepeatedValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value) { - AStatsEvent* statsEvent = AStatsEvent_obtain(); - AStatsEvent_setAtomId(statsEvent, atomId); - AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs); - - AStatsEvent_writeInt32(statsEvent, value); - AStatsEvent_writeInt32(statsEvent, value); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); +shared_ptr<LogEvent> CreateThreeValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value1, + int32_t value2, int32_t value3) { shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); - + CreateThreeValueLogEvent(logEvent.get(), atomId, eventTimeNs, value1, value2, value3); return logEvent; } @@ -605,26 +539,13 @@ void CreateRepeatedValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTi AStatsEvent_writeInt32(statsEvent, value); AStatsEvent_writeInt32(statsEvent, value); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); } -shared_ptr<LogEvent> CreateNoValuesLogEvent(int atomId, int64_t eventTimeNs) { - AStatsEvent* statsEvent = AStatsEvent_obtain(); - AStatsEvent_setAtomId(statsEvent, atomId); - AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); +shared_ptr<LogEvent> CreateRepeatedValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value) { shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); - + CreateRepeatedValueLogEvent(logEvent.get(), atomId, eventTimeNs, value); return logEvent; } @@ -632,12 +553,14 @@ void CreateNoValuesLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs) AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, atomId); AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs); - AStatsEvent_build(statsEvent); - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent); +} + +shared_ptr<LogEvent> CreateNoValuesLogEvent(int atomId, int64_t eventTimeNs) { + shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0); + CreateNoValuesLogEvent(logEvent.get(), atomId, eventTimeNs); + return logEvent; } std::unique_ptr<LogEvent> CreateScreenStateChangedEvent( @@ -645,16 +568,10 @@ std::unique_ptr<LogEvent> CreateScreenStateChangedEvent( AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, util::SCREEN_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -662,16 +579,10 @@ std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, util::BATTERY_SAVER_MODE_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::ON); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -679,16 +590,10 @@ std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs) { AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, util::BATTERY_SAVER_MODE_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::OFF); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -696,16 +601,10 @@ std::unique_ptr<LogEvent> CreateBatteryStateChangedEvent(const uint64_t timestam AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, util::PLUGGED_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -713,16 +612,10 @@ std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampN AStatsEvent* statsEvent = AStatsEvent_obtain(); AStatsEvent_setAtomId(statsEvent, util::SCREEN_BRIGHTNESS_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - AStatsEvent_writeInt32(statsEvent, level); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -733,24 +626,12 @@ std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent( AStatsEvent_setAtomId(statsEvent, util::SCHEDULED_JOB_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - vector<const char*> cTags(attributionTags.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = attributionTags[i].c_str(); - } - - AStatsEvent_writeAttributionChain(statsEvent, - reinterpret_cast<const uint32_t*>(attributionUids.data()), - cTags.data(), attributionUids.size()); + writeAttribution(statsEvent, attributionUids, attributionTags); AStatsEvent_writeString(statsEvent, jobName.c_str()); AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -780,25 +661,13 @@ std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(uint64_t timestampNs, AStatsEvent_setAtomId(statsEvent, util::WAKELOCK_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - vector<const char*> cTags(attributionTags.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = attributionTags[i].c_str(); - } - - AStatsEvent_writeAttributionChain(statsEvent, - reinterpret_cast<const uint32_t*>(attributionUids.data()), - cTags.data(), attributionUids.size()); + writeAttribution(statsEvent, attributionUids, attributionTags); AStatsEvent_writeInt32(statsEvent, android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK); AStatsEvent_writeString(statsEvent, wakelockName.c_str()); AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -828,14 +697,9 @@ std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent( AStatsEvent_writeString(statsEvent, "pkg_name"); AStatsEvent_writeString(statsEvent, "class_name"); AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -858,24 +722,12 @@ std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(uint64_t timestampNs, AStatsEvent_setAtomId(statsEvent, util::SYNC_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - vector<const char*> cTags(attributionTags.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = attributionTags[i].c_str(); - } - - AStatsEvent_writeAttributionChain(statsEvent, - reinterpret_cast<const uint32_t*>(attributionUids.data()), - cTags.data(), attributionUids.size()); + writeAttribution(statsEvent, attributionUids, attributionTags); AStatsEvent_writeString(statsEvent, name.c_str()); AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -904,14 +756,9 @@ std::unique_ptr<LogEvent> CreateProcessLifeCycleStateChangedEvent( AStatsEvent_writeInt32(statsEvent, uid); AStatsEvent_writeString(statsEvent, ""); AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -928,14 +775,9 @@ std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, cons AStatsEvent_writeInt32(statsEvent, uid); AStatsEvent_writeString(statsEvent, "eventType"); AStatsEvent_writeString(statsEvent, "processName"); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -948,14 +790,9 @@ std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(uint64_t timestampNs, in AStatsEvent_writeInt32(statsEvent, hostUid); AStatsEvent_writeInt32(statsEvent, isolatedUid); AStatsEvent_writeInt32(statsEvent, is_create); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -967,14 +804,9 @@ std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent( AStatsEvent_writeInt32(statsEvent, uid); AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -988,26 +820,14 @@ std::unique_ptr<LogEvent> CreateBleScanStateChangedEvent(uint64_t timestampNs, AStatsEvent_setAtomId(statsEvent, util::BLE_SCAN_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); - vector<const char*> cTags(attributionTags.size()); - for (int i = 0; i < cTags.size(); i++) { - cTags[i] = attributionTags[i].c_str(); - } - - AStatsEvent_writeAttributionChain(statsEvent, - reinterpret_cast<const uint32_t*>(attributionUids.data()), - cTags.data(), attributionUids.size()); + writeAttribution(statsEvent, attributionUids, attributionTags); AStatsEvent_writeInt32(statsEvent, state); AStatsEvent_writeInt32(statsEvent, filtered); // filtered AStatsEvent_writeInt32(statsEvent, firstMatch); // first match AStatsEvent_writeInt32(statsEvent, opportunistic); // opportunistic - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -1023,14 +843,9 @@ std::unique_ptr<LogEvent> CreateOverlayStateChangedEvent(int64_t timestampNs, co AStatsEvent_writeString(statsEvent, packageName.c_str()); AStatsEvent_writeInt32(statsEvent, usingAlertWindow); AStatsEvent_writeInt32(statsEvent, state); - AStatsEvent_build(statsEvent); - - size_t size; - uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); - logEvent->parseBuffer(buf, size); - AStatsEvent_release(statsEvent); + parseStatsEventToLogEvent(statsEvent, logEvent.get()); return logEvent; } @@ -1186,6 +1001,27 @@ bool EqualsTo(const DimensionsValue& s1, const DimensionsValue& s2) { } } +bool LessThan(const google::protobuf::RepeatedPtrField<StateValue>& s1, + const google::protobuf::RepeatedPtrField<StateValue>& s2) { + if (s1.size() != s2.size()) { + return s1.size() < s2.size(); + } + for (int i = 0; i < s1.size(); i++) { + const StateValue& state1 = s1[i]; + const StateValue& state2 = s2[i]; + if (state1.atom_id() != state2.atom_id()) { + return state1.atom_id() < state2.atom_id(); + } + if (state1.value() != state2.value()) { + return state1.value() < state2.value(); + } + if (state1.group_id() != state2.group_id()) { + return state1.group_id() < state2.group_id(); + } + } + return false; +} + bool LessThan(const DimensionsValue& s1, const DimensionsValue& s2) { if (s1.field() != s2.field()) { return s1.field() < s2.field(); @@ -1234,7 +1070,7 @@ bool LessThan(const DimensionsPair& s1, const DimensionsPair& s2) { return false; } - return LessThan(s1.dimInCondition, s2.dimInCondition); + return LessThan(s1.stateValues, s2.stateValues); } void backfillStringInDimension(const std::map<uint64_t, string>& str_map, diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h index f24705a0c89f..37b98891797a 100644 --- a/cmds/statsd/tests/statsd_test_util.h +++ b/cmds/statsd/tests/statsd_test_util.h @@ -25,6 +25,7 @@ #include "src/hash.h" #include "src/logd/LogEvent.h" #include "src/stats_log_util.h" +#include "stats_event.h" #include "statslog_statsdtest.h" namespace android { @@ -137,27 +138,16 @@ State CreateUidProcessState(); // Create State proto for overlay state atom. State CreateOverlayState(); -State CreateScreenStateWithOnOffMap(); - -State CreateScreenStateWithInDozeMap(); +State CreateScreenStateWithOnOffMap(int64_t screenOnId, int64_t screenOffId); // Create StateGroup proto for ScreenState ON group -StateMap_StateGroup CreateScreenStateOnGroup(); +StateMap_StateGroup CreateScreenStateOnGroup(int64_t screenOnId); // Create StateGroup proto for ScreenState OFF group -StateMap_StateGroup CreateScreenStateOffGroup(); +StateMap_StateGroup CreateScreenStateOffGroup(int64_t screenOffId); // Create StateMap proto for ScreenState ON/OFF map -StateMap CreateScreenStateOnOffMap(); - -// Create StateGroup proto for ScreenState IN DOZE group -StateMap_StateGroup CreateScreenStateInDozeGroup(); - -// Create StateGroup proto for ScreenState NOT IN DOZE group -StateMap_StateGroup CreateScreenStateNotDozeGroup(); - -// Create StateMap proto for ScreenState IN DOZE map -StateMap CreateScreenStateInDozeMap(); +StateMap CreateScreenStateOnOffMap(int64_t screenOnId, int64_t screenOffId); // Add a predicate to the predicate combination. void addPredicateToPredicateCombination(const Predicate& predicate, Predicate* combination); @@ -189,6 +179,12 @@ void getPartialWakelockKey(int uid, const std::string& tag, HashableDimensionKey void getPartialWakelockKey(int uid, HashableDimensionKey* key); // END: get primary key functions +void writeAttribution(AStatsEvent* statsEvent, const vector<int>& attributionUids, + const vector<string>& attributionTags); + +// Builds statsEvent to get buffer that is parsed into logEvent then releases statsEvent. +void parseStatsEventToLogEvent(AStatsEvent* statsEvent, LogEvent* logEvent); + shared_ptr<LogEvent> CreateTwoValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value1, int32_t value2); @@ -312,12 +308,14 @@ void ValidateAttributionUidAndTagDimension( const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag); struct DimensionsPair { - DimensionsPair(DimensionsValue m1, DimensionsValue m2) : dimInWhat(m1), dimInCondition(m2){}; + DimensionsPair(DimensionsValue m1, google::protobuf::RepeatedPtrField<StateValue> m2) + : dimInWhat(m1), stateValues(m2){}; DimensionsValue dimInWhat; - DimensionsValue dimInCondition; + google::protobuf::RepeatedPtrField<StateValue> stateValues; }; +bool LessThan(const StateValue& s1, const StateValue& s2); bool LessThan(const DimensionsValue& s1, const DimensionsValue& s2); bool LessThan(const DimensionsPair& s1, const DimensionsPair& s2); @@ -386,7 +384,7 @@ void sortMetricDataByDimensionsValue(const T& metricData, T* sortedMetricData) { for (int i = 0; i < metricData.data_size(); ++i) { dimensionIndexMap.insert( std::make_pair(DimensionsPair(metricData.data(i).dimensions_in_what(), - metricData.data(i).dimensions_in_condition()), + metricData.data(i).slice_by_state()), i)); } for (const auto& itr : dimensionIndexMap) { diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java index 2a7cfd306174..54a744b654cb 100644 --- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java +++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java @@ -64,10 +64,12 @@ public class TestDrive { "AID_LMKD", "com.android.managedprovisioning", "AID_MEDIA", - "AID_NETWORK_STACK" + "AID_NETWORK_STACK", + "com.google.android.providers.media.module", }; private static final String[] DEFAULT_PULL_SOURCES = { "AID_SYSTEM", + "AID_RADIO" }; private static final Logger LOGGER = Logger.getLogger(TestDrive.class.getName()); diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java index 3180b77f5700..957ebfbef799 100644 --- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java +++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java @@ -24,6 +24,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; +import android.sysprop.InitProperties; public class PowerCommand extends Svc.Command { private static final int FORCE_SUSPEND_DELAY_DEFAULT_MILLIS = 0; @@ -103,6 +104,8 @@ public class PowerCommand extends Svc.Command { pm.reboot(false, mode, true); } catch (RemoteException e) { maybeLogRemoteException("Failed to reboot."); + } catch (Exception e) { + System.err.println("Failed to reboot: " + e.getMessage()); } return; } else if ("shutdown".equals(args[1])) { @@ -138,7 +141,9 @@ public class PowerCommand extends Svc.Command { // if it is already in shutdown flow. private void maybeLogRemoteException(String msg) { String powerProp = SystemProperties.get("sys.powerctl"); - if (powerProp.isEmpty()) { + // Also check if userspace reboot is ongoing, since in case of userspace reboot value of the + // sys.powerctl property will be reset. + if (powerProp.isEmpty() && !InitProperties.userspace_reboot_in_progress().orElse(false)) { System.err.println(msg); } } diff --git a/core/java/android/annotation/NonNull.java b/core/java/android/annotation/NonNull.java index a95bf3b8061e..c5aff9d6794e 100644 --- a/core/java/android/annotation/NonNull.java +++ b/core/java/android/annotation/NonNull.java @@ -30,8 +30,8 @@ import java.lang.annotation.Target; * <p> * This is a marker annotation and it has no specific attributes. * - * @paramDoc This value must never be {@code null}. - * @returnDoc This value will never be {@code null}. + * @paramDoc This value cannot be {@code null}. + * @returnDoc This value cannot be {@code null}. * @hide */ @Retention(SOURCE) diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index b6d519ae5d2b..fd73632632ff 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -69,6 +69,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Singleton; @@ -1597,6 +1598,39 @@ public class ActivityManager { + " resizeMode: " + ActivityInfo.resizeModeToString(mResizeMode) + " minWidth: " + mMinWidth + " minHeight: " + mMinHeight; } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TaskDescription)) { + return false; + } + + TaskDescription other = (TaskDescription) obj; + return TextUtils.equals(mLabel, other.mLabel) + && TextUtils.equals(mIconFilename, other.mIconFilename) + && mIcon == other.mIcon + && mColorPrimary == other.mColorPrimary + && mColorBackground == other.mColorBackground + && mStatusBarColor == other.mStatusBarColor + && mNavigationBarColor == other.mNavigationBarColor + && mEnsureStatusBarContrastWhenTransparent + == other.mEnsureStatusBarContrastWhenTransparent + && mEnsureNavigationBarContrastWhenTransparent + == other.mEnsureNavigationBarContrastWhenTransparent + && mResizeMode == other.mResizeMode + && mMinWidth == other.mMinWidth + && mMinHeight == other.mMinHeight; + } + + /** @hide */ + public static boolean equals(TaskDescription td1, TaskDescription td2) { + if (td1 == null && td2 == null) { + return true; + } else if (td1 != null && td2 != null) { + return td1.equals(td2); + } + return false; + } } /** diff --git a/core/java/android/app/AppOps.md b/core/java/android/app/AppOps.md index bee701addca8..ad1a30146663 100644 --- a/core/java/android/app/AppOps.md +++ b/core/java/android/app/AppOps.md @@ -116,14 +116,27 @@ for app-ops. It also delays the changes by a _settle time_. This delay is needed can fluctuate when switching apps. By delaying the change the appops service is not affected by those. -The proc state is used for two use cases: Firstly, Tracking remembers the proc state for each -tracked event. Secondly, `noteOp`/`checkOp` calls for app-op that are set to `MODE_FOREGROUND` are -translated using the `AppOpsService.UidState.evalMode` method into `MODE_ALLOWED` when the app is -counted as foreground and `MODE_IGNORED` when the app is counted as background. `checkOpRaw` -calls are not affected. - -The current proc state for an app can be read from `dumpsys appops`. The tracking information can -be read from `dumpsys appops` +In addition to proc state, the `AppOpsService` also receives process capability update from the +`ActivityManagerService`. Proc capability specifies what while-in-use(`MODE_FOREGROUND`) operations + the proc is allowed to perform in its current proc state. There are three proc capabilities + defined so far: +`PROCESS_CAPABILITY_FOREGROUND_LOCATION`, `PROCESS_CAPABILITY_FOREGROUND_CAMERA` and +`PROCESS_CAPABILITY_FOREGROUND_MICROPHONE`, they correspond to the while-in-use operation of +location, camera and microphone (microphone is `RECORD_AUDIO`). + +In `ActivityManagerService`, `PROCESS_STATE_TOP` and `PROCESS_STATE_PERSISTENT` have all +three capabilities, `PROCESS_STATE_FOREGROUND_SERVICE` has capabilities defined by + `foregroundServiceType` that is specified in foreground service's manifest file. A client process + can pass its capabilities to service using `BIND_INCLUDE_CAPABILITIES` flag. + +The proc state and capability are used for two use cases: Firstly, Tracking remembers the proc state + for each tracked event. Secondly, `noteOp`/`checkOp` calls for app-op that are set to + `MODE_FOREGROUND` are translated using the `AppOpsService.UidState.evalMode` method into + `MODE_ALLOWED` when the app has the capability and `MODE_IGNORED` when the app does not have the + capability. `checkOpRaw` calls are not affected. + +The current proc state and capability for an app can be read from `dumpsys appops`. +The tracking information can be read from `dumpsys appops` ``` Uid u0a118: diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 46b06fb64b80..3a708a6f699b 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1395,6 +1395,7 @@ public class AppOpsManager { public static final String OPSTR_QUERY_ALL_PACKAGES = "android:query_all_packages"; /** @hide Access all external storage */ @SystemApi + @TestApi public static final String OPSTR_MANAGE_EXTERNAL_STORAGE = "android:manage_external_storage"; diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index e476993f003f..b7ceb6ae1b4c 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -299,7 +299,6 @@ interface IActivityTaskManager { in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations); void suppressResizeConfigChanges(boolean suppress); - void moveTasksToFullscreenStack(int fromStackId, boolean onTop); boolean moveTopActivityToPinnedStack(int stackId, in Rect bounds); boolean isInMultiWindowMode(in IBinder token); boolean isInPictureInPictureMode(in IBinder token); diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 78d3581a7012..9d0364eba39f 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -78,10 +78,9 @@ interface INotificationManager boolean shouldHideSilentStatusIcons(String callingPkg); void setHideSilentStatusIcons(boolean hide); - void setBubblesAllowed(String pkg, int uid, boolean allowed); + void setBubblesAllowed(String pkg, int uid, int bubblePreference); boolean areBubblesAllowed(String pkg); - boolean areBubblesAllowedForPackage(String pkg, int uid); - boolean hasUserApprovedBubblesForPackage(String pkg, int uid); + int getBubblePreferenceForPackage(String pkg, int uid); void createNotificationChannelGroups(String pkg, in ParceledListSlice channelGroupList); void createNotificationChannels(String pkg, in ParceledListSlice channelsList); diff --git a/core/java/android/app/IWindowToken.aidl b/core/java/android/app/IWindowToken.aidl index 8ea881fba09c..3627b0f13a7f 100644 --- a/core/java/android/app/IWindowToken.aidl +++ b/core/java/android/app/IWindowToken.aidl @@ -30,4 +30,6 @@ import android.view.IWindow; */ oneway interface IWindowToken { void onConfigurationChanged(in Configuration newConfig, int newDisplayId); + + void onWindowTokenRemoved(); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 7a593498e967..8edf03d033f8 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -3594,20 +3594,42 @@ public class Notification implements Parcelable } /** - * If this notification is duplicative of a Launcher shortcut, sets the - * {@link ShortcutInfo#getId() id} of the shortcut, in case the Launcher wants to hide - * the shortcut. - * - * This field will be ignored by Launchers that don't support badging, don't show - * notification content, or don't show {@link android.content.pm.ShortcutManager shortcuts}. + * From Android 11, messaging notifications (those that use {@link MessagingStyle}) that + * use this method to link to a published long-lived sharing shortcut may appear in a + * dedicated Conversation section of the shade and may show configuration options that + * are unique to conversations. This behavior should be reserved for person to person(s) + * conversations where there is a likely social obligation for an individual to respond. + * <p> + * For example, the following are some examples of notifications that belong in the + * conversation space: + * <ul> + * <li>1:1 conversations between two individuals</li> + * <li>Group conversations between individuals where everyone can contribute</li> + * </ul> + * And the following are some examples of notifications that do not belong in the + * conversation space: + * <ul> + * <li>Advertisements from a bot (even if personal and contextualized)</li> + * <li>Engagement notifications from a bot</li> + * <li>Directional conversations where there is an active speaker and many passive + * individuals</li> + * <li>Stream / posting updates from other individuals</li> + * </ul> + * </p> * + * <p> + * Additionally, this method can be used for all types of notifications to mark this + * notification as duplicative of a Launcher shortcut. Launchers that show badges or + * notification content may then suppress the shortcut in favor of the content of this + * notification. + * <p> * If this notification has {@link BubbleMetadata} attached that was created with * a shortcutId a check will be performed to ensure the shortcutId supplied to bubble * metadata matches the shortcutId set here, if one was set. If the shortcutId's were * specified but do not match, an exception is thrown. * * @param shortcutId the {@link ShortcutInfo#getId() id} of the shortcut this notification - * supersedes + * is linked to * * @see Notification.BubbleMetadata.Builder#Builder(String) */ @@ -7589,10 +7611,8 @@ public class Notification implements Parcelable >= Build.VERSION_CODES.P; boolean isOneToOne; CharSequence nameReplacement = null; - Icon avatarReplacement = null; if (!atLeastP) { isOneToOne = TextUtils.isEmpty(conversationTitle); - avatarReplacement = mBuilder.mN.mLargeIcon; if (hasOnlyWhiteSpaceSenders()) { isOneToOne = true; nameReplacement = conversationTitle; @@ -7641,7 +7661,7 @@ public class Notification implements Parcelable contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsCollapsed", isCollapsed); contentView.setIcon(R.id.status_bar_latest_event_content, "setAvatarReplacement", - avatarReplacement); + mBuilder.mN.mLargeIcon); contentView.setCharSequence(R.id.status_bar_latest_event_content, "setNameReplacement", nameReplacement); contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsOneToOne", diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index d1d67f0d81d8..2feb9277775c 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -102,7 +102,7 @@ public final class NotificationChannel implements Parcelable { private static final String ATT_FG_SERVICE_SHOWN = "fgservice"; private static final String ATT_GROUP = "group"; private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system"; - private static final String ATT_ALLOW_BUBBLE = "can_bubble"; + private static final String ATT_ALLOW_BUBBLE = "allow_bubble"; private static final String ATT_ORIG_IMP = "orig_imp"; private static final String ATT_PARENT_CHANNEL = "parent"; private static final String ATT_CONVERSATION_ID = "conv_id"; @@ -168,7 +168,7 @@ public final class NotificationChannel implements Parcelable { NotificationManager.IMPORTANCE_UNSPECIFIED; private static final boolean DEFAULT_DELETED = false; private static final boolean DEFAULT_SHOW_BADGE = true; - private static final boolean DEFAULT_ALLOW_BUBBLE = true; + private static final boolean DEFAULT_ALLOW_BUBBLE = false; @UnsupportedAppUsage private String mId; @@ -545,15 +545,8 @@ public final class NotificationChannel implements Parcelable { } /** - * Sets whether notifications posted to this channel can appear outside of the notification - * shade, floating over other apps' content as a bubble. - * - * <p>This value will be ignored for channels that aren't allowed to pop on screen (that is, - * channels whose {@link #getImportance() importance} is < - * {@link NotificationManager#IMPORTANCE_HIGH}.</p> - * - * <p>Only modifiable before the channel is submitted to - * * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.</p> + * As of Android 11 this value is no longer respected. + * @see #canBubble() * @see Notification#getBubbleMetadata() */ public void setAllowBubbles(boolean allowBubbles) { @@ -702,8 +695,10 @@ public final class NotificationChannel implements Parcelable { } /** - * Returns whether notifications posted to this channel can display outside of the notification - * shade, in a floating window on top of other apps. + * Returns whether notifications posted to this channel are allowed to display outside of the + * notification shade, in a floating window on top of other apps. + * + * @see Notification#getBubbleMetadata() */ public boolean canBubble() { return mAllowBubbles; diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 0e97e3fe06ce..d6df400f86b6 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -452,6 +452,19 @@ public class NotificationManager { */ public static final int IMPORTANCE_MAX = 5; + /** + * @hide + */ + public static final int BUBBLE_PREFERENCE_NONE = 0; + /** + * @hide + */ + public static final int BUBBLE_PREFERENCE_ALL = 1; + /** + * @hide + */ + public static final int BUBBLE_PREFERENCE_SELECTED = 2; + @UnsupportedAppUsage private static INotificationManager sService; @@ -1213,7 +1226,7 @@ public class NotificationManager { /** - * Sets whether notifications posted by this app can appear outside of the + * Gets whether all notifications posted by this app can appear outside of the * notification shade, floating over other apps' content. * * <p>This value will be ignored for notifications that are posted to channels that do not diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java index eaee0602f4b7..7a18b8120d7e 100644 --- a/core/java/android/app/Presentation.java +++ b/core/java/android/app/Presentation.java @@ -19,6 +19,7 @@ package android.app; import static android.content.Context.DISPLAY_SERVICE; import static android.content.Context.WINDOW_SERVICE; import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; +import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -191,12 +192,16 @@ public class Presentation extends Dialog { mDisplay = display; mDisplayManager = (DisplayManager)getContext().getSystemService(DISPLAY_SERVICE); + final int windowType = + (display.getFlags() & Display.FLAG_PRIVATE) != 0 ? TYPE_PRIVATE_PRESENTATION + : TYPE_PRESENTATION; + final Window w = getWindow(); final WindowManager.LayoutParams attr = w.getAttributes(); attr.token = mToken; w.setAttributes(attr); w.setGravity(Gravity.FILL); - w.setType(TYPE_PRESENTATION); + w.setType(windowType); setCanceledOnTouchOutside(false); } diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index d00366bd38f4..47ccc2f0badb 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -344,7 +344,7 @@ public class ResourcesManager { ApkAssets apkAssets = null; if (mLoadedApkAssets != null) { apkAssets = mLoadedApkAssets.get(newKey); - if (apkAssets != null) { + if (apkAssets != null && apkAssets.isUpToDate()) { return apkAssets; } } @@ -353,7 +353,7 @@ public class ResourcesManager { final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey); if (apkAssetsRef != null) { apkAssets = apkAssetsRef.get(); - if (apkAssets != null) { + if (apkAssets != null && apkAssets.isUpToDate()) { if (mLoadedApkAssets != null) { mLoadedApkAssets.put(newKey, apkAssets); } @@ -1121,7 +1121,9 @@ public class ResourcesManager { daj = new DisplayAdjustments(daj); daj.setCompatibilityInfo(compat); } - daj.setConfiguration(config); + if (displayId == Display.DEFAULT_DISPLAY) { + daj.setConfiguration(config); + } DisplayMetrics dm = getDisplayMetrics(displayId, daj); if (displayId != Display.DEFAULT_DISPLAY) { applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 91a857225324..e599a5ce81ef 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -1658,6 +1658,9 @@ public final class SystemServiceRegistry { public final T getService(ContextImpl ctx) { final Object[] cache = ctx.mServiceCache; final int[] gates = ctx.mServiceInitializationStateArray; + boolean interrupted = false; + + T ret = null; for (;;) { boolean doInitialize = false; @@ -1665,7 +1668,8 @@ public final class SystemServiceRegistry { // Return it if we already have a cached instance. T service = (T) cache[mCacheIndex]; if (service != null || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) { - return service; + ret = service; + break; // exit the for (;;) } // If we get here, there's no cached instance. @@ -1708,24 +1712,33 @@ public final class SystemServiceRegistry { cache.notifyAll(); } } - return service; + ret = service; + break; // exit the for (;;) } // The other threads will wait for the first thread to call notifyAll(), // and go back to the top and retry. synchronized (cache) { + // Repeat until the state becomes STATE_READY or STATE_NOT_FOUND. + // We can't respond to interrupts here; just like we can't in the "doInitialize" + // path, so we remember the interrupt state here and re-interrupt later. while (gates[mCacheIndex] < ContextImpl.STATE_READY) { try { + // Clear the interrupt state. + interrupted |= Thread.interrupted(); cache.wait(); } catch (InterruptedException e) { // This shouldn't normally happen, but if someone interrupts the // thread, it will. - Slog.wtf(TAG, "getService() interrupted"); - Thread.currentThread().interrupt(); - return null; + Slog.w(TAG, "getService() interrupted"); + interrupted = true; } } } } + if (interrupted) { + Thread.currentThread().interrupt(); + } + return ret; } public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException; diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java index 878993ebcd19..3a06c9d79fee 100644 --- a/core/java/android/app/WindowContext.java +++ b/core/java/android/app/WindowContext.java @@ -28,6 +28,8 @@ import android.view.IWindowManager; import android.view.WindowManagerGlobal; import android.view.WindowManagerImpl; +import com.android.internal.annotations.VisibleForTesting; + import java.lang.ref.Reference; /** @@ -75,8 +77,6 @@ public class WindowContext extends ContextWrapper { // config back to the client. result = mWms.addWindowTokenWithOptions( mToken, type, getDisplayId(), options, getPackageName()); - - // TODO(window-context): remove token with a DeathObserver } catch (RemoteException e) { mOwnsToken = false; throw e.rethrowFromSystemServer(); @@ -100,6 +100,13 @@ public class WindowContext extends ContextWrapper { @Override protected void finalize() throws Throwable { + release(); + super.finalize(); + } + + /** Used for test to invoke because we can't invoke finalize directly. */ + @VisibleForTesting + public void release() { if (mOwnsToken) { try { mWms.removeWindowToken(mToken, getDisplayId()); @@ -108,6 +115,12 @@ public class WindowContext extends ContextWrapper { throw e.rethrowFromSystemServer(); } } - super.finalize(); + destroy(); + } + + void destroy() { + final ContextImpl impl = (ContextImpl) getBaseContext(); + impl.scheduleFinalCleanup(getClass().getName(), "WindowContext"); + Reference.reachabilityFence(this); } } diff --git a/core/java/android/app/WindowTokenClient.java b/core/java/android/app/WindowTokenClient.java index ed0179bb9839..b5d103959818 100644 --- a/core/java/android/app/WindowTokenClient.java +++ b/core/java/android/app/WindowTokenClient.java @@ -20,6 +20,9 @@ import android.content.Context; import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; +import android.view.WindowManagerGlobal; + +import java.lang.ref.WeakReference; /** * Client implementation of {@link IWindowToken}. It can receive configuration change callbacks from @@ -31,9 +34,9 @@ import android.os.IBinder; public class WindowTokenClient extends IWindowToken.Stub { /** * Attached {@link Context} for this window token to update configuration and resources. - * Initialized by {@link #attachContext(Context)}. + * Initialized by {@link #attachContext(WindowContext)}. */ - private Context mContext = null; + private WeakReference<WindowContext> mContextRef = null; private final ResourcesManager mResourcesManager = ResourcesManager.getInstance(); @@ -47,30 +50,44 @@ public class WindowTokenClient extends IWindowToken.Stub { * @param context context to be attached * @throws IllegalStateException if attached context has already existed. */ - void attachContext(@NonNull Context context) { - if (mContext != null) { + void attachContext(@NonNull WindowContext context) { + if (mContextRef != null) { throw new IllegalStateException("Context is already attached."); } - mContext = context; - ContextImpl impl = ContextImpl.getImpl(mContext); + mContextRef = new WeakReference<>(context); + final ContextImpl impl = ContextImpl.getImpl(context); impl.setResources(impl.createWindowContextResources()); } @Override public void onConfigurationChanged(Configuration newConfig, int newDisplayId) { - final int currentDisplayId = mContext.getDisplayId(); + final Context context = mContextRef.get(); + if (context == null) { + return; + } + final int currentDisplayId = context.getDisplayId(); final boolean displayChanged = newDisplayId != currentDisplayId; - final Configuration config = new Configuration(mContext.getResources() - .getConfiguration()); - final boolean configChanged = config.isOtherSeqNewer(newConfig) - && config.updateFrom(newConfig) != 0; + final Configuration config = context.getResources().getConfiguration(); + final boolean configChanged = config.diff(newConfig) != 0; if (displayChanged || configChanged) { // TODO(ag/9789103): update resource manager logic to track non-activity tokens - mResourcesManager.updateResourcesForActivity(asBinder(), config, newDisplayId, + mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId, displayChanged); } if (displayChanged) { - mContext.updateDisplay(newDisplayId); + context.updateDisplay(newDisplayId); + } + } + + @Override + public void onWindowTokenRemoved() { + final WindowContext context = mContextRef.get(); + if (context != null) { + context.destroy(); + mContextRef.clear(); } + // If a secondary display is detached, release all views attached to this token. + WindowManagerGlobal.getInstance().closeAll(this, mContextRef.getClass().getName(), + "WindowContext"); } } diff --git a/core/java/android/app/admin/DevicePolicyKeyguardService.java b/core/java/android/app/admin/DevicePolicyKeyguardService.java index db833ec478bd..473725f40cf1 100644 --- a/core/java/android/app/admin/DevicePolicyKeyguardService.java +++ b/core/java/android/app/admin/DevicePolicyKeyguardService.java @@ -16,12 +16,15 @@ package android.app.admin; +import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.RemoteException; import android.util.Log; import android.view.SurfaceControlViewHost; @@ -41,27 +44,34 @@ import android.view.SurfaceControlViewHost; @SystemApi public class DevicePolicyKeyguardService extends Service { private static final String TAG = "DevicePolicyKeyguardService"; + private final Handler mHandler = new Handler(Looper.getMainLooper()); private IKeyguardCallback mCallback; private final IKeyguardClient mClient = new IKeyguardClient.Stub() { + @MainThread @Override public void onCreateKeyguardSurface(@Nullable IBinder hostInputToken, - IKeyguardCallback callback) { + @NonNull IKeyguardCallback callback) { mCallback = callback; - SurfaceControlViewHost.SurfacePackage surfacePackage = - DevicePolicyKeyguardService.this.onCreateKeyguardSurface(hostInputToken); + mHandler.post(() -> { + SurfaceControlViewHost.SurfacePackage surfacePackage = + DevicePolicyKeyguardService.this.onCreateKeyguardSurface(hostInputToken); - if (mCallback != null) { try { mCallback.onRemoteContentReady(surfacePackage); } catch (RemoteException e) { Log.e(TAG, "Failed to return created SurfacePackage", e); } - } + }); } }; @Override + public void onDestroy() { + mHandler.removeCallbacksAndMessages(null); + } + + @Override @Nullable public final IBinder onBind(@Nullable Intent intent) { return mClient.asBinder(); @@ -97,6 +107,10 @@ public class DevicePolicyKeyguardService extends Service { */ @Nullable public void dismiss() { + if (mCallback == null) { + Log.w(TAG, "KeyguardCallback was unexpectedly null"); + return; + } try { mCallback.onDismiss(); } catch (RemoteException e) { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index faf9ec61ffde..fb9adb730314 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -8606,7 +8606,7 @@ public class DevicePolicyManager { * <p> * This method may be called on the {@code DevicePolicyManager} instance returned from * {@link #getParentProfileInstance(ComponentName)}. Note that only a profile owner on - * an organization-deviced can affect account types on the parent profile instance. + * an organization-owned device can affect account types on the parent profile instance. * * @return a list of account types for which account management has been disabled. * diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index 80fa87152d78..41f04f73aa87 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -176,19 +176,31 @@ public abstract class DevicePolicyManagerInternal { * for cross-profile communication, via {@link * DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)}.</li> * <li>The default package names that are allowed to request user consent for cross-profile - * communication without being explicitly enabled by the admin , via {@link - * DevicePolicyManager#setDefaultCrossProfilePackages(ComponentName, UserHandle, Set)}.</li> + * communication without being explicitly enabled by the admin, via + * {@link com.android.internal.R.array#cross_profile_apps} and + * {@link com.android.internal.R.array#vendor_cross_profile_apps}.</li> * </ul> * * @return the combined set of whitelisted package names set via * {@link DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)} and - * {@link DevicePolicyManager#setDefaultCrossProfilePackages(ComponentName, UserHandle, Set)} + * {@link com.android.internal.R.array#cross_profile_apps} and + * {@link com.android.internal.R.array#vendor_cross_profile_apps} * * @hide */ public abstract List<String> getAllCrossProfilePackages(); /** + * Returns the default package names set by the OEM that are allowed to request user consent for + * cross-profile communication without being explicitly enabled by the admin, via + * {@link com.android.internal.R.array#cross_profile_apps} and + * {@link com.android.internal.R.array#vendor_cross_profile_apps}. + * + * @hide + */ + public abstract List<String> getDefaultCrossProfilePackages(); + + /** * Sends the {@code intent} to the packages with cross profile capabilities. * * <p>This means the application must have the {@code crossProfile} property and the diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index 6d674ae7df14..9ab6e7fc9f58 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -186,8 +186,8 @@ public class LaunchActivityItem extends ClientTransactionItem { && Objects.equals(mOverrideConfig, other.mOverrideConfig) && Objects.equals(mCompatInfo, other.mCompatInfo) && Objects.equals(mReferrer, other.mReferrer) - && mProcState == other.mProcState && areBundlesEqual(mState, other.mState) - && areBundlesEqual(mPersistentState, other.mPersistentState) + && mProcState == other.mProcState && areBundlesEqualRoughly(mState, other.mState) + && areBundlesEqualRoughly(mPersistentState, other.mPersistentState) && Objects.equals(mPendingResults, other.mPendingResults) && Objects.equals(mPendingNewIntents, other.mPendingNewIntents) && mIsForward == other.mIsForward @@ -205,8 +205,8 @@ public class LaunchActivityItem extends ClientTransactionItem { result = 31 * result + Objects.hashCode(mCompatInfo); result = 31 * result + Objects.hashCode(mReferrer); result = 31 * result + Objects.hashCode(mProcState); - result = 31 * result + (mState != null ? mState.size() : 0); - result = 31 * result + (mPersistentState != null ? mPersistentState.size() : 0); + result = 31 * result + getRoughBundleHashCode(mState); + result = 31 * result + getRoughBundleHashCode(mPersistentState); result = 31 * result + Objects.hashCode(mPendingResults); result = 31 * result + Objects.hashCode(mPendingNewIntents); result = 31 * result + (mIsForward ? 1 : 0); @@ -225,25 +225,19 @@ public class LaunchActivityItem extends ClientTransactionItem { && Objects.equals(mInfo.getComponentName(), other.getComponentName()); } - private static boolean areBundlesEqual(BaseBundle extras, BaseBundle newExtras) { - if (extras == null || newExtras == null) { - return extras == newExtras; - } - - if (extras.size() != newExtras.size()) { - return false; - } + /** + * This method may be used to compare a parceled item with another unparceled item, and the + * parceled bundle may contain customized class that will raise BadParcelableException when + * unparceling if a customized class loader is not set to the bundle. So the hash code is + * simply determined by the bundle is empty or not. + */ + private static int getRoughBundleHashCode(BaseBundle bundle) { + return (bundle == null || bundle.isDefinitelyEmpty()) ? 0 : 1; + } - for (String key : extras.keySet()) { - if (key != null) { - final Object value = extras.get(key); - final Object newValue = newExtras.get(key); - if (!Objects.equals(value, newValue)) { - return false; - } - } - } - return true; + /** Compares the bundles without unparceling them (avoid BadParcelableException). */ + private static boolean areBundlesEqualRoughly(BaseBundle a, BaseBundle b) { + return getRoughBundleHashCode(a) == getRoughBundleHashCode(b); } @Override diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index e446f4fa5eb4..0a4627da223a 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -687,6 +687,19 @@ public abstract class ContentResolver implements ContentInterface { public static final int NOTIFY_DELETE = 1 << 4; /** + * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: typically set + * by a {@link ContentProvider} to indicate that this notification should + * not be subject to any delays when dispatching to apps running in the + * background. + * <p> + * Using this flag may negatively impact system health and performance, and + * should be used sparingly. + * + * @hide + */ + public static final int NOTIFY_NO_DELAY = 1 << 15; + + /** * No exception, throttled by app standby normally. * @hide */ diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index f951d2b89958..745add174582 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -17,6 +17,7 @@ package android.content; import android.annotation.IntDef; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; @@ -40,6 +41,7 @@ import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -766,16 +768,30 @@ public class IntentFilter implements Parcelable { * @return True if the action is listed in the filter. */ public final boolean matchAction(String action) { - return matchAction(action, false); + return matchAction(action, false /*wildcardSupported*/, null /*ignoreActions*/); } /** * Variant of {@link #matchAction(String)} that allows a wildcard for the provided action. * @param wildcardSupported if true, will allow action to use wildcards - */ - private boolean matchAction(String action, boolean wildcardSupported) { - if (wildcardSupported && !mActions.isEmpty() && WILDCARD.equals(action)) { - return true; + * @param ignoreActions if not null, the set of actions to should not be considered valid while + * calculating the match + */ + private boolean matchAction(String action, boolean wildcardSupported, + @Nullable Collection<String> ignoreActions) { + if (wildcardSupported && WILDCARD.equals(action)) { + if (ignoreActions == null) { + return !mActions.isEmpty(); + } + for (int i = mActions.size() - 1; i >= 0; i--) { + if (!ignoreActions.contains(mActions.get(i))) { + return true; + } + } + return false; + } + if (ignoreActions != null && ignoreActions.contains(action)) { + return false; } return hasAction(action); } @@ -1779,17 +1795,24 @@ public class IntentFilter implements Parcelable { */ public final int match(String action, String type, String scheme, Uri data, Set<String> categories, String logTag) { - return match(action, type, scheme, data, categories, logTag, false /*supportWildcards*/); + return match(action, type, scheme, data, categories, logTag, false /*supportWildcards*/, + null /*ignoreActions*/); } /** * Variant of {@link #match(ContentResolver, Intent, boolean, String)} that supports wildcards * in the action, type, scheme, host and path. - * @hide if true, will allow supported parameters to use wildcards to match this filter + * @param supportWildcards if true, will allow supported parameters to use wildcards to match + * this filter + * @param ignoreActions a collection of actions that, if not null should be ignored and not used + * if provided as the matching action or the set of actions defined by this + * filter + * @hide */ public final int match(String action, String type, String scheme, - Uri data, Set<String> categories, String logTag, boolean supportWildcards) { - if (action != null && !matchAction(action, supportWildcards)) { + Uri data, Set<String> categories, String logTag, boolean supportWildcards, + @Nullable Collection<String> ignoreActions) { + if (action != null && !matchAction(action, supportWildcards, ignoreActions)) { if (false) Log.v( logTag, "No matching action " + action + " for " + this); return NO_MATCH_ACTION; diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java index 7578ede2648d..144a07eb4ea3 100644 --- a/core/java/android/content/pm/CrossProfileApps.java +++ b/core/java/android/content/pm/CrossProfileApps.java @@ -435,6 +435,9 @@ public class CrossProfileApps { * <p>This differs from {@link #canConfigureInteractAcrossProfiles(String)} since it will * not return {@code false} if the app is not whitelisted or not installed in the other profile. * + * <p>Note that platform-signed apps that are automatically granted the permission and are not + * whitelisted by the OEM will not be included in this list. + * * @hide */ public boolean canUserAttemptToConfigureInteractAcrossProfiles(String packageName) { diff --git a/core/java/android/content/pm/FileSystemControlParcel.aidl b/core/java/android/content/pm/FileSystemControlParcel.aidl index f00feaeb2f5a..92df16ced8a3 100644 --- a/core/java/android/content/pm/FileSystemControlParcel.aidl +++ b/core/java/android/content/pm/FileSystemControlParcel.aidl @@ -17,6 +17,7 @@ package android.content.pm; import android.content.pm.IPackageInstallerSessionFileSystemConnector; +import android.os.incremental.IIncrementalServiceConnector; import android.os.incremental.IncrementalFileSystemControlParcel; /** @@ -26,6 +27,8 @@ import android.os.incremental.IncrementalFileSystemControlParcel; parcelable FileSystemControlParcel { // Incremental FS control descriptors. @nullable IncrementalFileSystemControlParcel incremental; + // Incremental FS service. + @nullable IIncrementalServiceConnector service; // Callback-based installation connector. @nullable IPackageInstallerSessionFileSystemConnector callback; } diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index b0b2c33e0ddd..37baae35734b 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -55,4 +55,6 @@ interface IPackageInstaller { in IntentSender statusReceiver, int userId, in List<String> whiteListedPermissions); void setPermissionsResult(int sessionId, boolean accepted); + + void bypassNextStagedInstallerCheck(boolean value); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index f48d78ac9cc3..9ca2db970eb7 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1542,6 +1542,24 @@ public abstract class PackageManager { */ public static final int INSTALL_FAILED_PROCESS_NOT_DEFINED = -122; + /** + * Installation parse return code: system is in a minimal boot state, and the parser only + * allows the package with {@code coreApp} manifest attribute to be a valid application. + * + * @hide + */ + public static final int INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED = -123; + + /** + * Installation failed return code: the {@code resources.arsc} of one of the APKs being + * installed is compressed or not aligned on a 4-byte boundary. Resource tables that cannot be + * memory mapped exert excess memory pressure on the system and drastically slow down + * construction of {@link Resources} objects. + * + * @hide + */ + public static final int INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED = -124; + /** @hide */ @IntDef(flag = true, prefix = { "DELETE_" }, value = { DELETE_KEEP_DATA, diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index 12328cf32fb3..c61362feaeae 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -21,7 +21,8 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; import static android.os.Build.VERSION_CODES.DONUT; import static android.os.Build.VERSION_CODES.O; @@ -229,7 +230,8 @@ public class ParsingPackageUtils { final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir, 0); if (mOnlyCoreApps && !lite.coreApp) { - return input.error("Not a coreApp: " + packageDir); + return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED, + "Not a coreApp: " + packageDir); } // Build the split dependency tree. @@ -251,10 +253,8 @@ public class ParsingPackageUtils { final File baseApk = new File(lite.baseCodePath); ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk, lite.codePath, assets, flags); - // TODO(b/135203078): Pass original error up? if (result.isError()) { - return input.error(INSTALL_PARSE_FAILED_NOT_APK, - "Failed to parse base APK: " + baseApk); + return input.error(result); } ParsingPackage pkg = result.getResult(); @@ -291,7 +291,8 @@ public class ParsingPackageUtils { final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile, flags); if (mOnlyCoreApps && !lite.coreApp) { - return input.error("Not a coreApp: " + apkFile); + return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED, + "Not a coreApp: " + apkFile); } final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); @@ -344,7 +345,20 @@ public class ParsingPackageUtils { + result.getErrorMessage()); } - ParsingPackage pkg = result.getResult(); + final ParsingPackage pkg = result.getResult(); + if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.R + && assets.containsAllocatedTable()) { + final ParseResult<?> deferResult = input.deferError( + "Targeting R+ (version" + Build.VERSION_CODES.R + " and above) requires the" + + " resources.arsc of installed APKs to be stored uncompressed and" + + " aligned on a 4-byte boundary", + DeferredError.RESOURCES_ARSC_COMPRESSED); + if (deferResult.isError()) { + return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED, + deferResult.getErrorMessage()); + } + } + ApkAssets apkAssets = assets.getApkAssets()[0]; if (apkAssets.definesOverlayable()) { SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers(); diff --git a/core/java/android/content/pm/parsing/result/ParseInput.java b/core/java/android/content/pm/parsing/result/ParseInput.java index 538510049e04..6b659bea84f1 100644 --- a/core/java/android/content/pm/parsing/result/ParseInput.java +++ b/core/java/android/content/pm/parsing/result/ParseInput.java @@ -59,6 +59,16 @@ public interface ParseInput { @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) public static final long EMPTY_INTENT_ACTION_CATEGORY = 151163173; + + /** + * The {@code resources.arsc} of one of the APKs being installed is compressed or not + * aligned on a 4-byte boundary. Resource tables that cannot be memory mapped exert excess + * memory pressure on the system and drastically slow down construction of + * {@link android.content.res.Resources} objects. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + public static final long RESOURCES_ARSC_COMPRESSED = 132742131; } <ResultType> ParseResult<ResultType> success(ResultType result); diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index d2103af1d247..15a184f0e5ef 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -819,6 +819,19 @@ public final class AssetManager implements AutoCloseable { } } + /** + * Returns whether the {@code resources.arsc} of any loaded apk assets is allocated in RAM + * (not mmapped). + * + * @hide + */ + public boolean containsAllocatedTable() { + synchronized (this) { + ensureValidLocked(); + return nativeContainsAllocatedTable(mObject); + } + } + CharSequence getPooledStringForCookie(int cookie, int id) { // Cookies map to ApkAssets starting at 1. return getApkAssets()[cookie - 1].getStringFromPool(id); @@ -1482,6 +1495,7 @@ public final class AssetManager implements AutoCloseable { long ptr, boolean includeOverlays, boolean includeLoaders); // File native methods. + private static native boolean nativeContainsAllocatedTable(long ptr); private static native @Nullable String[] nativeList(long ptr, @NonNull String path) throws IOException; private static native long nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode); diff --git a/core/java/android/database/sqlite/SQLiteCantOpenDatabaseException.java b/core/java/android/database/sqlite/SQLiteCantOpenDatabaseException.java index 6f01796c93c2..5d4b48dac46b 100644 --- a/core/java/android/database/sqlite/SQLiteCantOpenDatabaseException.java +++ b/core/java/android/database/sqlite/SQLiteCantOpenDatabaseException.java @@ -22,4 +22,9 @@ public class SQLiteCantOpenDatabaseException extends SQLiteException { public SQLiteCantOpenDatabaseException(String error) { super(error); } + + /** @hide */ + public SQLiteCantOpenDatabaseException(String error, Throwable cause) { + super(error, cause); + } } diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index bcb3934a5b08..f7c96a3a02c1 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -36,6 +36,9 @@ import dalvik.system.CloseGuard; import java.io.File; import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -215,12 +218,31 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } private void open() { + final String file = mConfiguration.path; final int cookie = mRecentOperations.beginOperation("open", null, null); try { - mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags, + mConnectionPtr = nativeOpen(file, mConfiguration.openFlags, mConfiguration.label, NoPreloadHolder.DEBUG_SQL_STATEMENTS, NoPreloadHolder.DEBUG_SQL_TIME, mConfiguration.lookasideSlotSize, mConfiguration.lookasideSlotCount); + } catch (SQLiteCantOpenDatabaseException e) { + String message = String.format("Cannot open database '%s'", file); + + final Path path = FileSystems.getDefault().getPath(file); + final Path dir = path.getParent(); + + if (!Files.isDirectory(dir)) { + message += ": Directory " + dir + " doesn't exist"; + } else if (!Files.exists(path)) { + message += ": File " + path + " doesn't exist"; + } else if (!Files.isReadable(path)) { + message += ": File " + path + " is not readable"; + } else if (Files.isDirectory(path)) { + message += ": Path " + path + " is a directory"; + } else { + message += ": Unknown reason"; + } + throw new SQLiteCantOpenDatabaseException(message, e); } finally { mRecentOperations.endOperation(cookie); } diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 91dae66d08ae..aa75f6042db8 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -17,6 +17,7 @@ package android.hardware.camera2; import android.annotation.NonNull; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; @@ -100,6 +101,8 @@ public abstract class CameraMetadata<TKey> { * * @hide */ + @UnsupportedAppUsage(publicAlternatives = "This method is exposed for native " + + "{@code ACameraMetadata_fromCameraMetadata} in {@code libcamera2ndk}.") public long getNativeMetadataPtr() { if (mNativeInstance == null) { return 0; diff --git a/core/java/android/hardware/camera2/params/Capability.java b/core/java/android/hardware/camera2/params/Capability.java index 6f59c5fdcb53..ebb534a48955 100644 --- a/core/java/android/hardware/camera2/params/Capability.java +++ b/core/java/android/hardware/camera2/params/Capability.java @@ -16,8 +16,8 @@ package android.hardware.camera2.params; -import static com.android.internal.util.Preconditions.checkArgumentInRange; import static com.android.internal.util.Preconditions.checkArgumentNonnegative; +import static com.android.internal.util.Preconditions.checkArgumentPositive; import android.annotation.NonNull; import android.hardware.camera2.CameraCharacteristics; @@ -64,9 +64,15 @@ public final class Capability { "maxStreamingWidth must be nonnegative"); mMaxStreamingHeight = checkArgumentNonnegative(maxStreamingHeight, "maxStreamingHeight must be nonnegative"); - mMinZoomRatio = checkArgumentInRange(minZoomRatio, 0.0f, 1.0f, - "minZoomRatio must be between 0.0f and 1.0f"); - mMaxZoomRatio = maxZoomRatio; + + if (minZoomRatio > maxZoomRatio) { + throw new IllegalArgumentException("minZoomRatio " + minZoomRatio + + " is greater than maxZoomRatio " + maxZoomRatio); + } + mMinZoomRatio = checkArgumentPositive(minZoomRatio, + "minZoomRatio must be positive"); + mMaxZoomRatio = checkArgumentPositive(maxZoomRatio, + "maxZoomRatio must be positive"); } /** diff --git a/core/java/android/hardware/display/DeviceProductInfo.java b/core/java/android/hardware/display/DeviceProductInfo.java index ed50d7cae8cc..94c5dd884eab 100644 --- a/core/java/android/hardware/display/DeviceProductInfo.java +++ b/core/java/android/hardware/display/DeviceProductInfo.java @@ -19,6 +19,7 @@ package android.hardware.display; import android.os.Parcel; import android.os.Parcelable; +import java.util.Arrays; import java.util.Objects; /** @@ -33,18 +34,21 @@ public final class DeviceProductInfo implements Parcelable { private final String mProductId; private final Integer mModelYear; private final ManufactureDate mManufactureDate; + private final int[] mRelativeAddress; public DeviceProductInfo( String name, String manufacturerPnpId, String productId, Integer modelYear, - ManufactureDate manufactureDate) { + ManufactureDate manufactureDate, + int[] relativeAddress) { this.mName = name; this.mManufacturerPnpId = manufacturerPnpId; this.mProductId = productId; this.mModelYear = modelYear; this.mManufactureDate = manufactureDate; + this.mRelativeAddress = relativeAddress; } private DeviceProductInfo(Parcel in) { @@ -53,6 +57,7 @@ public final class DeviceProductInfo implements Parcelable { mProductId = (String) in.readValue(null); mModelYear = (Integer) in.readValue(null); mManufactureDate = (ManufactureDate) in.readValue(null); + mRelativeAddress = in.createIntArray(); } /** @@ -92,6 +97,14 @@ public final class DeviceProductInfo implements Parcelable { return mManufactureDate; } + /** + * @return Relative address in the display network. For example, for HDMI connected devices this + * can be its physical address. Each component of the address is in the range [0, 255]. + */ + public int[] getRelativeAddress() { + return mRelativeAddress; + } + @Override public String toString() { return "DeviceProductInfo{" @@ -105,6 +118,8 @@ public final class DeviceProductInfo implements Parcelable { + mModelYear + ", manufactureDate=" + mManufactureDate + + ", relativeAddress=" + + Arrays.toString(mRelativeAddress) + '}'; } @@ -117,12 +132,14 @@ public final class DeviceProductInfo implements Parcelable { && Objects.equals(mManufacturerPnpId, that.mManufacturerPnpId) && Objects.equals(mProductId, that.mProductId) && Objects.equals(mModelYear, that.mModelYear) - && Objects.equals(mManufactureDate, that.mManufactureDate); + && Objects.equals(mManufactureDate, that.mManufactureDate) + && Arrays.equals(mRelativeAddress, that.mRelativeAddress); } @Override public int hashCode() { - return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate); + return Objects.hash(mName, mManufacturerPnpId, mProductId, mModelYear, mManufactureDate, + mRelativeAddress); } public static final Creator<DeviceProductInfo> CREATOR = @@ -150,6 +167,7 @@ public final class DeviceProductInfo implements Parcelable { dest.writeValue(mProductId); dest.writeValue(mModelYear); dest.writeValue(mManufactureDate); + dest.writeIntArray(mRelativeAddress); } /** diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index c42dacc187a9..65e772cb5ebb 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -25,12 +25,14 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Bundle; +import android.os.ConditionVariable; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; @@ -556,12 +558,12 @@ public abstract class NetworkAgent { @NonNull public Network register() { if (VDBG) log("Registering NetworkAgent"); - final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context - .getSystemService(Context.CONNECTIVITY_SERVICE); synchronized (mRegisterLock) { if (mNetwork != null) { throw new IllegalStateException("Agent already registered"); } + final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context + .getSystemService(Context.CONNECTIVITY_SERVICE); mNetwork = cm.registerNetworkAgent(new Messenger(mHandler), new NetworkInfo(mInitialConfiguration.info), mInitialConfiguration.properties, mInitialConfiguration.capabilities, @@ -572,6 +574,37 @@ public abstract class NetworkAgent { } /** + * Register this network agent with a testing harness. + * + * The returned Messenger sends messages to the Handler. This allows a test to send + * this object {@code CMD_*} messages as if they came from ConnectivityService, which + * is useful for testing the behavior. + * + * @hide + */ + public Messenger registerForTest(final Network network) { + log("Registering NetworkAgent for test"); + synchronized (mRegisterLock) { + mNetwork = network; + mInitialConfiguration = null; + } + return new Messenger(mHandler); + } + + /** + * Waits for the handler to be idle. + * This is useful for testing, and has smaller scope than an accessor to mHandler. + * TODO : move the implementation in common library with the tests + * @hide + */ + @VisibleForTesting + public boolean waitForIdle(final long timeoutMs) { + final ConditionVariable cv = new ConditionVariable(false); + mHandler.post(cv::open); + return cv.block(timeoutMs); + } + + /** * @return The Network associated with this agent, or null if it's not registered yet. */ @Nullable @@ -812,7 +845,7 @@ public abstract class NetworkAgent { * this is the destination the probes are being redirected to, otherwise {@code null}. */ public void onValidationStatus(@ValidationStatus int status, @Nullable Uri redirectUri) { - networkStatus(status, redirectUri.toString()); + networkStatus(status, null == redirectUri ? "" : redirectUri.toString()); } /** @hide TODO delete once subclasses have moved to onValidationStatus */ protected void networkStatus(int status, String redirectUrl) { diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 73c6b3daf2ec..52d6fdfbd529 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -680,11 +680,13 @@ public final class NetworkCapabilities implements Parcelable { public void restrictCapabilitesForTestNetwork() { final long originalCapabilities = mNetworkCapabilities; final NetworkSpecifier originalSpecifier = mNetworkSpecifier; + final int originalSignalStrength = mSignalStrength; clearAll(); // Reset the transports to only contain TRANSPORT_TEST. mTransportTypes = (1 << TRANSPORT_TEST); mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES; mNetworkSpecifier = originalSpecifier; + mSignalStrength = originalSignalStrength; } /** diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java index 2041cfb22ea8..c87b8279c4d6 100644 --- a/core/java/android/net/VpnManager.java +++ b/core/java/android/net/VpnManager.java @@ -75,7 +75,7 @@ public class VpnManager { } /** - * Create an instance of the VpnManger with the given context. + * Create an instance of the VpnManager with the given context. * * <p>Internal only. Applications are expected to obtain an instance of the VpnManager via the * {@link Context.getSystemService()} method call. diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index b8e1aa88c3a3..be2de0edda2d 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -1483,12 +1483,25 @@ public final class PowerManager { return mInteractiveCache.query(null); } + + /** + * Returns {@code true} if this device supports rebooting userspace. + * + * <p>This method exists solely for the sake of re-using same logic between {@code PowerManager} + * and {@code PowerManagerService}. + * + * @hide + */ + public static boolean isRebootingUserspaceSupportedImpl() { + return InitProperties.is_userspace_reboot_supported().orElse(false); + } + /** * Returns {@code true} if this device supports rebooting userspace. */ // TODO(b/138605180): add link to documentation once it's ready. public boolean isRebootingUserspaceSupported() { - return InitProperties.is_userspace_reboot_supported().orElse(false); + return isRebootingUserspaceSupportedImpl(); } /** diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java index 51f01cac8138..653a5594f495 100644 --- a/core/java/android/os/PowerManagerInternal.java +++ b/core/java/android/os/PowerManagerInternal.java @@ -102,9 +102,9 @@ public abstract class PowerManagerInternal { * * This method must only be called by the window manager. * - * @param brightness The overridden brightness, or -1 to disable the override. + * @param brightness The overridden brightness, or Float.NaN to disable the override. */ - public abstract void setScreenBrightnessOverrideFromWindowManager(int brightness); + public abstract void setScreenBrightnessOverrideFromWindowManager(float brightness); /** * Used by the window manager to override the user activity timeout based on the diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index b7b3c4fc8add..5d2c9d18c00c 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -607,6 +607,9 @@ public class Process { * started. * @param pkgDataInfoMap Map from related package names to private data directory * volume UUID and inode number. + * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory + * volume UUID and inode number. + * @param bindMountAppsData whether zygote needs to mount CE and DE data. * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data. * @param zygoteArgs Additional arguments to supply to the zygote process. * @return An object that describes the result of the attempt to start the process. @@ -631,13 +634,17 @@ public class Process { @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, + @Nullable Map<String, Pair<String, Long>> + whitelistedDataInfoMap, + boolean bindMountAppsData, boolean bindMountAppStorageDirs, @Nullable String[] zygoteArgs) { return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges, - pkgDataInfoMap, bindMountAppStorageDirs, zygoteArgs); + pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData, + bindMountAppStorageDirs, zygoteArgs); } /** @hide */ @@ -661,7 +668,8 @@ public class Process { runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, /*isTopApp=*/ false, - disabledCompatChanges, /* pkgDataInfoMap */ null, false, zygoteArgs); + disabledCompatChanges, /* pkgDataInfoMap */ null, + /* whitelistedDataInfoMap */ null, false, false, zygoteArgs); } /** diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 5f3f14facd75..a4c99c006d80 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -333,6 +333,9 @@ public class ZygoteProcess { * started. * @param pkgDataInfoMap Map from related package names to private data directory * volume UUID and inode number. + * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory + * volume UUID and inode number. + * @param bindMountAppsData whether zygote needs to mount CE and DE data. * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data. * * @param zygoteArgs Additional arguments to supply to the Zygote process. @@ -355,6 +358,9 @@ public class ZygoteProcess { @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, + @Nullable Map<String, Pair<String, Long>> + whitelistedDataInfoMap, + boolean bindMountAppsData, boolean bindMountAppStorageDirs, @Nullable String[] zygoteArgs) { // TODO (chriswailes): Is there a better place to check this value? @@ -367,7 +373,8 @@ public class ZygoteProcess { runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false, packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges, - pkgDataInfoMap, bindMountAppStorageDirs, zygoteArgs); + pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData, + bindMountAppStorageDirs, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); @@ -608,6 +615,9 @@ public class ZygoteProcess { * @param disabledCompatChanges a list of disabled compat changes for the process being started. * @param pkgDataInfoMap Map from related package names to private data directory volume UUID * and inode number. + * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory + * volume UUID and inode number. + * @param bindMountAppsData whether zygote needs to mount CE and DE data. * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data. * @param extraArgs Additional arguments to supply to the zygote process. * @return An object that describes the result of the attempt to start the process. @@ -631,6 +641,9 @@ public class ZygoteProcess { @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, + @Nullable Map<String, Pair<String, Long>> + whitelistedDataInfoMap, + boolean bindMountAppsData, boolean bindMountAppStorageDirs, @Nullable String[] extraArgs) throws ZygoteStartFailedEx { @@ -728,11 +741,33 @@ public class ZygoteProcess { } argsForZygote.add(sb.toString()); } + if (whitelistedDataInfoMap != null && whitelistedDataInfoMap.size() > 0) { + StringBuilder sb = new StringBuilder(); + sb.append(Zygote.WHITELISTED_DATA_INFO_MAP); + sb.append("="); + boolean started = false; + for (Map.Entry<String, Pair<String, Long>> entry : whitelistedDataInfoMap.entrySet()) { + if (started) { + sb.append(','); + } + started = true; + sb.append(entry.getKey()); + sb.append(','); + sb.append(entry.getValue().first); + sb.append(','); + sb.append(entry.getValue().second); + } + argsForZygote.add(sb.toString()); + } if (bindMountAppStorageDirs) { argsForZygote.add(Zygote.BIND_MOUNT_APP_STORAGE_DIRS); } + if (bindMountAppsData) { + argsForZygote.add(Zygote.BIND_MOUNT_APP_DATA_DIRS); + } + if (disabledCompatChanges != null && disabledCompatChanges.length > 0) { StringBuilder sb = new StringBuilder(); sb.append("--disabled-compat-changes="); @@ -1291,6 +1326,7 @@ public class ZygoteProcess { true /* startChildZygote */, null /* packageName */, ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */, null /* disabledCompatChanges */, null /* pkgDataInfoMap */, + null /* whitelistedDataInfoMap */, false /* bindMountAppsData*/, /* bindMountAppStorageDirs */ false, extraArgs); } catch (ZygoteStartFailedEx ex) { diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl index d8308c7c3362..25cb0400a38d 100644 --- a/core/java/android/os/incremental/IIncrementalService.aidl +++ b/core/java/android/os/incremental/IIncrementalService.aidl @@ -38,13 +38,6 @@ interface IIncrementalService { int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode); /** - * Changes storage params. Returns 0 on success, and -errno on failure. - * Use enableReadLogs to switch pages read logs reporting on and off. - * Returns 0 on success, and - errno on failure: permission check or remount. - */ - int setStorageParams(int storageId, boolean enableReadLogs); - - /** * Bind-mounts a path under a storage to a full path. Can be permanent or temporary. */ const int BIND_TEMPORARY = 0; @@ -116,4 +109,9 @@ interface IIncrementalService { * Setting up native library directories and extract native libs onto a storage. */ boolean configureNativeBinaries(int storageId, in @utf8InCpp String apkFullPath, in @utf8InCpp String libDirRelativePath, in @utf8InCpp String abi); + + /** + * Waits until all native library extraction is done for the storage + */ + boolean waitForNativeBinariesExtraction(int storageId); } diff --git a/core/java/android/os/incremental/IIncrementalServiceConnector.aidl b/core/java/android/os/incremental/IIncrementalServiceConnector.aidl new file mode 100644 index 000000000000..5800ecf63a1e --- /dev/null +++ b/core/java/android/os/incremental/IIncrementalServiceConnector.aidl @@ -0,0 +1,27 @@ +/* + * 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 android.os.incremental; + +/** @hide */ +interface IIncrementalServiceConnector { + /** + * Changes storage params. Returns 0 on success, and -errno on failure. + * Use enableReadLogs to switch pages read logs reporting on and off. + * Returns 0 on success, and - errno on failure: permission check or remount. + */ + int setStorageParams(boolean enableReadLogs); +} diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java index 5f01408944e8..35518db32829 100644 --- a/core/java/android/os/incremental/IncrementalManager.java +++ b/core/java/android/os/incremental/IncrementalManager.java @@ -19,13 +19,11 @@ package android.os.incremental; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.content.Context; import android.content.pm.DataLoaderParams; import android.content.pm.IDataLoaderStatusListener; import android.os.RemoteException; -import android.system.ErrnoException; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; @@ -321,23 +319,6 @@ public final class IncrementalManager { return nativeUnsafeGetFileSignature(path); } - /** - * Sets storage parameters. - * - * @param enableReadLogs - enables or disables read logs. Caller has to have a permission. - */ - @RequiresPermission(android.Manifest.permission.LOADER_USAGE_STATS) - public void setStorageParams(int storageId, boolean enableReadLogs) throws ErrnoException { - try { - int res = mService.setStorageParams(storageId, enableReadLogs); - if (res < 0) { - throw new ErrnoException("setStorageParams", -res); - } - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - /* Native methods */ private static native boolean nativeIsEnabled(); private static native boolean nativeIsIncrementalPath(@NonNull String path); diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java index 7092751c0d7e..70ebbaa326b8 100644 --- a/core/java/android/os/incremental/IncrementalStorage.java +++ b/core/java/android/os/incremental/IncrementalStorage.java @@ -480,4 +480,18 @@ public final class IncrementalStorage { return false; } } + + /** + * Waits for all native binary extraction operations to complete on the storage. + * + * @return Success of not. + */ + public boolean waitForNativeBinariesExtraction() { + try { + return mService.waitForNativeBinariesExtraction(mId); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + return false; + } + } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 920302c75011..fe340c46e3c4 100644..100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1870,6 +1870,24 @@ public final class Settings { public static final String EXTRA_APP_UID = "app_uid"; /** + * Activity Action: Show power menu settings. + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_POWER_MENU_SETTINGS = + "android.settings.ACTION_POWER_MENU_SETTINGS"; + + /** + * Activity Action: Show controls settings. + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_DEVICE_CONTROLS_SETTINGS = + "android.settings.ACTION_DEVICE_CONTROLS_SETTINGS"; + + /** * Activity Action: Show a dialog with disabled by policy message. * <p> If an user action is disabled by policy, this dialog can be triggered to let * the user know about this. @@ -4730,6 +4748,14 @@ public final class Settings { public static final String SHOW_BATTERY_PERCENT = "status_bar_show_battery_percent"; /** + * Whether or not to enable multiple audio focus. + * When enabled, requires more management by user over application playback activity, + * for instance pausing media apps when another starts. + * @hide + */ + public static final String MULTI_AUDIO_FOCUS_ENABLED = "multi_audio_focus_enabled"; + + /** * IMPORTANT: If you add a new public settings you also have to add it to * PUBLIC_SETTINGS below. If the new setting is hidden you have to add * it to PRIVATE_SETTINGS below. Also add a validator that can validate diff --git a/core/java/android/service/autofill/IInlineSuggestionRenderService.aidl b/core/java/android/service/autofill/IInlineSuggestionRenderService.aidl index dd434b440af4..bf0bb9e2a41f 100644 --- a/core/java/android/service/autofill/IInlineSuggestionRenderService.aidl +++ b/core/java/android/service/autofill/IInlineSuggestionRenderService.aidl @@ -17,6 +17,7 @@ package android.service.autofill; import android.os.IBinder; +import android.os.RemoteCallback; import android.service.autofill.IInlineSuggestionUiCallback; import android.service.autofill.InlinePresentation; @@ -29,4 +30,5 @@ oneway interface IInlineSuggestionRenderService { void renderSuggestion(in IInlineSuggestionUiCallback callback, in InlinePresentation presentation, int width, int height, in IBinder hostInputToken, int displayId); + void getInlineSuggestionsRendererInfo(in RemoteCallback callback); } diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java index cba6608db1b8..e3ed21ff556d 100644 --- a/core/java/android/service/autofill/InlineSuggestionRenderService.java +++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java @@ -30,6 +30,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.RemoteCallback; import android.os.RemoteException; import android.util.Log; import android.view.Display; @@ -128,6 +129,11 @@ public abstract class InlineSuggestionRenderService extends Service { } } + private void handleGetInlineSuggestionsRendererInfo(@NonNull RemoteCallback callback) { + final Bundle rendererInfo = onGetInlineSuggestionsRendererInfo(); + callback.sendResult(rendererInfo); + } + private void sendResult(@NonNull IInlineSuggestionUiCallback callback, @Nullable SurfaceControlViewHost.SurfacePackage surface) { try { @@ -151,6 +157,13 @@ public abstract class InlineSuggestionRenderService extends Service { InlineSuggestionRenderService.this, callback, presentation, width, height, hostInputToken, displayId)); } + + @Override + public void getInlineSuggestionsRendererInfo(@NonNull RemoteCallback callback) { + mHandler.sendMessage(obtainMessage( + InlineSuggestionRenderService::handleGetInlineSuggestionsRendererInfo, + InlineSuggestionRenderService.this, callback)); + } }.asBinder(); } diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java index 1efa3dd0c865..b47b2b41bdd9 100644 --- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java +++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java @@ -31,6 +31,7 @@ import android.content.ComponentName; import android.content.Intent; import android.graphics.Rect; import android.os.Build; +import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; @@ -558,9 +559,10 @@ public abstract class AugmentedAutofillService extends Service { } } - void reportResult(@Nullable List<Dataset> inlineSuggestionsData) { + void reportResult(@Nullable List<Dataset> inlineSuggestionsData, + @Nullable Bundle clientState) { try { - mCallback.onSuccess(inlineSuggestionsData); + mCallback.onSuccess(inlineSuggestionsData, clientState); } catch (RemoteException e) { Log.e(TAG, "Error calling back with the inline suggestions data: " + e); } diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java index 526a749c95a1..21738d80f2d3 100644 --- a/core/java/android/service/autofill/augmented/FillCallback.java +++ b/core/java/android/service/autofill/augmented/FillCallback.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.os.Bundle; import android.service.autofill.Dataset; import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy; import android.util.Log; @@ -55,14 +56,15 @@ public final class FillCallback { if (response == null) { mProxy.logEvent(AutofillProxy.REPORT_EVENT_NO_RESPONSE); - mProxy.reportResult(/* inlineSuggestionsData */ null); + mProxy.reportResult(/* inlineSuggestionsData */ null, /* clientState */ null); return; } List<Dataset> inlineSuggestions = response.getInlineSuggestions(); + Bundle clientState = response.getClientState(); if (inlineSuggestions != null && !inlineSuggestions.isEmpty()) { mProxy.logEvent(AutofillProxy.REPORT_EVENT_INLINE_RESPONSE); - mProxy.reportResult(inlineSuggestions); + mProxy.reportResult(inlineSuggestions, clientState); return; } diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl index 24af1e51dd56..609e382e2b96 100644 --- a/core/java/android/service/autofill/augmented/IFillCallback.aidl +++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl @@ -30,7 +30,7 @@ import java.util.List; */ interface IFillCallback { void onCancellable(in ICancellationSignal cancellation); - void onSuccess(in @nullable List<Dataset> inlineSuggestionsData); + void onSuccess(in @nullable List<Dataset> inlineSuggestionsData, in @nullable Bundle clientState); boolean isCompleted(); void cancel(); } diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index ef55f0615ec7..46cb65babc1c 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -747,7 +747,7 @@ public abstract class ContentCaptureService extends Service { void initializeForDelegate(DataShareReadAdapterDelegate delegate, DataShareReadAdapter adapter, Executor executor) { mDataShareReadAdapterHardReferences.put(delegate, adapter); - mExecutorHardReferences.remove(delegate, executor); + mExecutorHardReferences.put(delegate, executor); } Executor getExecutor(DataShareReadAdapterDelegate delegate) { diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java index 05877a59368a..60373ace2d8a 100644 --- a/core/java/android/service/dataloader/DataLoaderService.java +++ b/core/java/android/service/dataloader/DataLoaderService.java @@ -21,7 +21,6 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.Service; -import android.content.Context; import android.content.Intent; import android.content.pm.DataLoaderParams; import android.content.pm.DataLoaderParamsParcel; @@ -32,11 +31,11 @@ import android.content.pm.InstallationFile; import android.content.pm.InstallationFileParcel; import android.os.IBinder; import android.os.ParcelFileDescriptor; -import android.os.incremental.IncrementalManager; -import android.system.ErrnoException; import android.util.ExceptionUtils; import android.util.Slog; +import libcore.io.IoUtils; + import java.io.IOException; import java.util.Collection; @@ -118,22 +117,10 @@ public abstract class DataLoaderService extends Service { destroy(id); throw new RuntimeException(ex); } finally { - // Closing FDs. if (control.incremental != null) { - if (control.incremental.cmd != null) { - try { - control.incremental.cmd.close(); - } catch (IOException e) { - Slog.e(TAG, "Failed to close IncFs CMD file descriptor " + e); - } - } - if (control.incremental.log != null) { - try { - control.incremental.log.close(); - } catch (IOException e) { - Slog.e(TAG, "Failed to close IncFs LOG file descriptor " + e); - } - } + IoUtils.closeQuietly(control.incremental.cmd); + IoUtils.closeQuietly(control.incremental.pendingReads); + IoUtils.closeQuietly(control.incremental.log); } } } @@ -211,25 +198,6 @@ public abstract class DataLoaderService extends Service { private final long mNativeInstance; } - /* Used by native FileSystemConnector. */ - private boolean setStorageParams(int storageId, boolean enableReadLogs) { - IncrementalManager incrementalManager = (IncrementalManager) getSystemService( - Context.INCREMENTAL_SERVICE); - if (incrementalManager == null) { - Slog.e(TAG, "Failed to obtain incrementalManager: " + storageId); - return false; - } - try { - // This has to be done directly in incrementalManager as the storage - // might be missing still. - incrementalManager.setStorageParams(storageId, enableReadLogs); - } catch (ErrnoException e) { - Slog.e(TAG, "Failed to set params for storage: " + storageId, e); - return false; - } - return true; - } - /* Native methods */ private native boolean nativeCreateDataLoader(int storageId, @NonNull FileSystemControlParcel control, diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 0db97718b693..3f0787350075 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -900,10 +900,11 @@ public class DreamService extends Service implements Window.Callback { public final void finish() { if (mDebug) Slog.v(TAG, "finish(): mFinished=" + mFinished); - if (mActivity != null) { - if (!mActivity.isFinishing()) { + Activity activity = mActivity; + if (activity != null) { + if (!activity.isFinishing()) { // In case the activity is not finished yet, do it now. - mActivity.finishAndRemoveTask(); + activity.finishAndRemoveTask(); } return; } @@ -1106,6 +1107,7 @@ public class DreamService extends Service implements Window.Callback { @Override public void onViewDetachedFromWindow(View v) { + mActivity = null; finish(); } }); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index f531e12b0748..f944dd78dc3d 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -55,6 +55,7 @@ import android.view.InputChannel; import android.view.InputDevice; import android.view.InputEvent; import android.view.InputEventReceiver; +import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.MotionEvent; import android.view.SurfaceControl; @@ -190,6 +191,7 @@ public abstract class WallpaperService extends Service { new DisplayCutout.ParcelableWrapper(); DisplayCutout mDispatchedDisplayCutout = DisplayCutout.NO_CUTOUT; final InsetsState mInsetsState = new InsetsState(); + final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0]; final MergedConfiguration mMergedConfiguration = new MergedConfiguration(); private final Point mSurfaceSize = new Point(); @@ -878,7 +880,7 @@ public abstract class WallpaperService extends Service { if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE, mDisplay.getDisplayId(), mWinFrame, mContentInsets, mStableInsets, mDisplayCutout, inputChannel, - mInsetsState) < 0) { + mInsetsState, mTempControls) < 0) { Log.w(TAG, "Failed to add window while updating wallpaper surface."); return; } @@ -903,7 +905,7 @@ public abstract class WallpaperService extends Service { View.VISIBLE, 0, -1, mWinFrame, mContentInsets, mVisibleInsets, mStableInsets, mBackdropFrame, mDisplayCutout, mMergedConfiguration, mSurfaceControl, - mInsetsState, mSurfaceSize, mTmpSurfaceControl); + mInsetsState, mTempControls, mSurfaceSize, mTmpSurfaceControl); if (mSurfaceControl.isValid()) { mSurfaceHolder.mSurface.copyFrom(mSurfaceControl); mSurfaceControl.release(); diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 0ccb1e055c46..4469fdbb12ec 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -253,12 +253,14 @@ public final class Display { * @hide */ @UnsupportedAppUsage + @TestApi public static final int TYPE_UNKNOWN = 0; /** * Display type: Physical display connected through an internal port. * @hide */ + @TestApi public static final int TYPE_INTERNAL = 1; /** @@ -266,6 +268,7 @@ public final class Display { * @hide */ @UnsupportedAppUsage + @TestApi public static final int TYPE_EXTERNAL = 2; /** @@ -273,12 +276,14 @@ public final class Display { * @hide */ @UnsupportedAppUsage + @TestApi public static final int TYPE_WIFI = 3; /** * Display type: Overlay display. * @hide */ + @TestApi public static final int TYPE_OVERLAY = 4; /** @@ -286,6 +291,7 @@ public final class Display { * @hide */ @UnsupportedAppUsage + @TestApi public static final int TYPE_VIRTUAL = 5; /** @@ -569,6 +575,7 @@ public final class Display { * @hide */ @UnsupportedAppUsage + @TestApi public int getType() { return mType; } diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl index 071c2593f522..b6ce9f52e0c3 100644 --- a/core/java/android/view/IPinnedStackListener.aidl +++ b/core/java/android/view/IPinnedStackListener.aidl @@ -37,13 +37,9 @@ oneway interface IPinnedStackListener { /** * Called when the window manager has detected a change that would cause the movement bounds - * to be changed (ie. after configuration change, aspect ratio change, etc). It then provides - * the components that allow the listener to calculate the movement bounds itself. - * The {@param animatingBounds} are provided to indicate the current target bounds of the - * pinned stack (the final bounds if animating, the current bounds if not), - * which may be helpful in calculating dependent animation bounds. + * to be changed (ie. after configuration change, aspect ratio change, etc). */ - void onMovementBoundsChanged(in Rect animatingBounds, boolean fromImeAdjustment); + void onMovementBoundsChanged(boolean fromImeAdjustment); /** * Called when window manager decides to adjust the pinned stack bounds because of the IME, or diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl index a60a5cca08bd..983ab2eedf5c 100644 --- a/core/java/android/view/IRecentsAnimationController.aidl +++ b/core/java/android/view/IRecentsAnimationController.aidl @@ -114,4 +114,16 @@ interface IRecentsAnimationController { * animation is cancelled through fail safe mechanism. */ void setWillFinishToHome(boolean willFinishToHome); + + /** + * Stops controlling a task that is currently controlled by this recents animation. + * + * This method should be called when a task that has been received via {@link #onAnimationStart} + * or {@link #onTaskAppeared} is no longer needed. After calling this method, the task will + * either disappear from the screen, or jump to its final position in case it was the top task. + * + * @param taskId Id of the Task target to remove + * @return {@code true} when target removed successfully, {@code false} otherwise. + */ + boolean removeTask(int taskId); } diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl index 6eb90fc54286..925786f82e00 100644 --- a/core/java/android/view/IRecentsAnimationRunner.aidl +++ b/core/java/android/view/IRecentsAnimationRunner.aidl @@ -56,4 +56,10 @@ oneway interface IRecentsAnimationRunner { void onAnimationStart(in IRecentsAnimationController controller, in RemoteAnimationTarget[] apps, in RemoteAnimationTarget[] wallpapers, in Rect homeContentInsets, in Rect minimizedHomeBounds) = 2; + + /** + * Called when the task of an activity that has been started while the recents animation + * was running becomes ready for control. + */ + void onTaskAppeared(in RemoteAnimationTarget app) = 3; } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 84ac90bae258..b0bacb955f80 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -124,13 +124,20 @@ interface IWindowManager * @param type Window type to be used with this token. * @param options A bundle used to pass window-related options. * @param displayId The ID of the display where this token should be added. - * @param packageName The name of package to request to add window token. + * @param packageName The name of package to request to add window token. Could be {@code null} + * if callers holds the MANAGE_APP_TOKENS permission. * @return {@link WindowManagerGlobal#ADD_OKAY} if the addition was successful, an error code * otherwise. */ int addWindowTokenWithOptions(IBinder token, int type, int displayId, in Bundle options, String packageName); void addWindowToken(IBinder token, int type, int displayId); + /** + * Remove window token on a specific display. + * + * @param token Token to be removed + * @displayId The ID of the display where this token should be removed. + */ void removeWindowToken(IBinder token, int displayId); void prepareAppTransition(int transit, boolean alwaysKeepCurrent); @@ -735,4 +742,11 @@ interface IWindowManager * Called to show global actions. */ void showGlobalActions(); + + /** + * Sets layer tracing flags for SurfaceFlingerTrace. + * + * @param flags see definition in SurfaceTracing.cpp + */ + void setLayerTracingFlags(int flags); } diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 45e51f756489..a0527b7434fc 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -29,6 +29,7 @@ import android.view.IWindow; import android.view.IWindowId; import android.view.MotionEvent; import android.view.WindowManager; +import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.Surface; import android.view.SurfaceControl; @@ -46,7 +47,12 @@ interface IWindowSession { in int viewVisibility, in int layerStackId, out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets, out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel, - out InsetsState insetsState); + out InsetsState insetsState, out InsetsSourceControl[] activeControls); + int addToDisplayAsUser(IWindow window, int seq, in WindowManager.LayoutParams attrs, + in int viewVisibility, in int layerStackId, in int userId, + out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets, + out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel, + out InsetsState insetsState, out InsetsSourceControl[] activeControls); int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out Rect outContentInsets, out Rect outStableInsets, out InsetsState insetsState); @@ -106,8 +112,8 @@ interface IWindowSession { out Rect outBackdropFrame, out DisplayCutout.ParcelableWrapper displayCutout, out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl, - out InsetsState insetsState, out Point outSurfaceSize, - out SurfaceControl outBlastSurfaceControl); + out InsetsState insetsState, out InsetsSourceControl[] activeControls, + out Point outSurfaceSize, out SurfaceControl outBlastSurfaceControl); /* * Notify the window manager that an application is relaunching and diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index 69bab4df2cae..6cb93746a9a4 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -91,6 +91,8 @@ public class InsetsSourceConsumer { if (mSourceControl == control) { return; } + SurfaceControl oldLeash = mSourceControl != null ? mSourceControl.getLeash() : null; + final InsetsSourceControl lastControl = mSourceControl; mSourceControl = control; @@ -116,6 +118,12 @@ public class InsetsSourceConsumer { // However make sure that the leash visibility is still up to date. if (applyLocalVisibilityOverride()) { mController.notifyVisibilityChanged(); + } + + // If we have a new leash, make sure visibility is up-to-date, even though we + // didn't want to run an animation above. + SurfaceControl newLeash = mSourceControl.getLeash(); + if (oldLeash == null || newLeash == null || !oldLeash.isSameSurface(newLeash)) { applyHiddenToControl(); } } diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java index f3ec65f997ba..e001b668f71a 100644 --- a/core/java/android/view/InsetsSourceControl.java +++ b/core/java/android/view/InsetsSourceControl.java @@ -44,8 +44,7 @@ public class InsetsSourceControl implements Parcelable { public InsetsSourceControl(InsetsSourceControl other) { mType = other.mType; if (other.mLeash != null) { - mLeash = new SurfaceControl(); - mLeash.copyFrom(other.mLeash); + mLeash = new SurfaceControl(other.mLeash); } else { mLeash = null; } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index a37c1cbc76ad..1086774fc8ff 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -32,6 +32,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; import android.graphics.ColorSpace; @@ -215,6 +216,10 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetFrameRate( long transactionObj, long nativeObject, float frameRate, int compatibility); + private static native long nativeGetHandle(long nativeObject); + + private static native long nativeAcquireFrameRateFlexibilityToken(); + private static native void nativeReleaseFrameRateFlexibilityToken(long token); private final CloseGuard mCloseGuard = CloseGuard.get(); private String mName; @@ -222,6 +227,7 @@ public final class SurfaceControl implements Parcelable { * @hide */ public long mNativeObject; + private long mNativeHandle; // TODO: Move this to native. private final Object mSizeLock = new Object(); @@ -424,12 +430,13 @@ public final class SurfaceControl implements Parcelable { mCloseGuard.open("release"); } mNativeObject = nativeObject; + mNativeHandle = mNativeObject != 0 ? nativeGetHandle(nativeObject) : 0; } /** * @hide */ - public void copyFrom(SurfaceControl other) { + public void copyFrom(@NonNull SurfaceControl other) { mName = other.mName; mWidth = other.mWidth; mHeight = other.mHeight; @@ -849,23 +856,19 @@ public final class SurfaceControl implements Parcelable { throw new OutOfResourcesException( "Couldn't allocate SurfaceControl native object"); } - + mNativeHandle = nativeGetHandle(mNativeObject); mCloseGuard.open("release"); } - /** This is a transfer constructor, useful for transferring a live SurfaceControl native - * object to another Java wrapper which could have some different behavior, e.g. - * event logging. + /** + * Copy constructor. Creates a new native object pointing to the same surface as {@code other}. + * + * @param other The object to copy the surface from. * @hide */ - public SurfaceControl(SurfaceControl other) { - mName = other.mName; - mWidth = other.mWidth; - mHeight = other.mHeight; - mNativeObject = other.mNativeObject; - other.mCloseGuard.close(); - other.mNativeObject = 0; - mCloseGuard.open("release"); + @TestApi + public SurfaceControl(@NonNull SurfaceControl other) { + copyFrom(other); } private SurfaceControl(Parcel in) { @@ -917,6 +920,18 @@ public final class SurfaceControl implements Parcelable { } /** + * Checks whether two {@link SurfaceControl} objects represent the same surface. + * + * @param other The other object to check + * @return {@code true} if these two {@link SurfaceControl} objects represent the same surface. + * @hide + */ + @TestApi + public boolean isSameSurface(@NonNull SurfaceControl other) { + return other.mNativeHandle == mNativeHandle; + } + + /** * Write to a protocol buffer output stream. Protocol buffer message definition is at {@link * android.view.SurfaceControlProto}. * @@ -973,6 +988,7 @@ public final class SurfaceControl implements Parcelable { if (mNativeObject != 0) { nativeRelease(mNativeObject); mNativeObject = 0; + mNativeHandle = 0; mCloseGuard.close(); } } @@ -2868,4 +2884,25 @@ public final class SurfaceControl implements Parcelable { } } } + + /** + * Acquire a frame rate flexibility token, which allows surface flinger to freely switch display + * frame rates. This is used by CTS tests to put the device in a consistent state. See + * ISurfaceComposer::acquireFrameRateFlexibilityToken(). The caller must have the + * ACCESS_SURFACE_FLINGER permission, or else the call will fail, returning 0. + * @hide + */ + @TestApi + public static long acquireFrameRateFlexibilityToken() { + return nativeAcquireFrameRateFlexibilityToken(); + } + + /** + * Release a frame rate flexibility token. + * @hide + */ + @TestApi + public static void releaseFrameRateFlexibilityToken(long token) { + nativeReleaseFrameRateFlexibilityToken(token); + } } diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 174165c5ba59..cfceb031539f 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -50,6 +50,22 @@ public class SurfaceControlViewHost { * elements. It's expected to get this object from * {@link SurfaceControlViewHost#getSurfacePackage} afterwards it can be embedded within * a SurfaceView by calling {@link SurfaceView#setChildSurfacePackage}. + * + * Note that each {@link SurfacePackage} must be released by calling + * {@link SurfacePackage#release}. However, if you use the recommended flow, + * the framework will automatically handle the lifetime for you. + * + * 1. When sending the package to the remote process, return it from an AIDL method + * or manually use FLAG_WRITE_RETURN_VALUE in writeToParcel. This will automatically + * release the package in the local process. + * 2. In the remote process, consume the package using SurfaceView. This way the + * SurfaceView will take over the lifetime and call {@link SurfacePackage#release} + * for the user. + * + * One final note: The {@link SurfacePackage} lifetime is totally de-coupled + * from the lifetime of the underlying {@link SurfaceControlViewHost}. Regardless + * of the lifetime of the package the user should still call + * {@link SurfaceControlViewHost#release} when finished. */ public static final class SurfacePackage implements Parcelable { private SurfaceControl mSurfaceControl; diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index b677ccd9a618..9880ea096cf2 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -1650,11 +1650,24 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall /** * Display the view-hierarchy embedded within a {@link SurfaceControlViewHost.SurfacePackage} - * within this SurfaceView. If this SurfaceView is above it's host Surface (see + * within this SurfaceView. + * + * This can be called independently of the SurfaceView lifetime callbacks. SurfaceView + * will internally manage reparenting the package to our Surface as it is created + * and destroyed. + * + * If this SurfaceView is above its host Surface (see * {@link #setZOrderOnTop} then the embedded Surface hierarchy will be able to receive - * input. This will take ownership of the SurfaceControl contained inside the SurfacePackage + * input. + * + * This will take ownership of the SurfaceControl contained inside the SurfacePackage * and free the caller of the obligation to call - * {@link SurfaceControlViewHost.SurfacePackage#release}. + * {@link SurfaceControlViewHost.SurfacePackage#release}. However, note that + * {@link SurfaceControlViewHost.SurfacePackage#release} and + * {@link SurfaceControlViewHost#release} are not the same. While the ownership + * of this particular {@link SurfaceControlViewHost.SurfacePackage} will be taken by the + * SurfaceView the underlying {@link SurfaceControlViewHost} remains managed by it's original + * remote-owner. * * @param p The SurfacePackage to embed. */ diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index da186087a34a..8abe72fc91e8 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -14684,17 +14684,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } } - if (isAccessibilityPane()) { - if (isVisible != oldVisible) { + + if (isVisible != oldVisible) { + if (isAccessibilityPane()) { notifyViewAccessibilityStateChangedIfNeeded(isVisible ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); } - } - notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); - if (!getSystemGestureExclusionRects().isEmpty() && isVisible != oldVisible) { - postUpdateSystemGestureExclusionRects(); + notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); + + if (!getSystemGestureExclusionRects().isEmpty()) { + postUpdateSystemGestureExclusionRects(); + } } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 1e96a1c21ac3..ed1edc3bd526 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -21,6 +21,7 @@ import static android.view.Display.INVALID_DISPLAY; import static android.view.InputDevice.SOURCE_CLASS_NONE; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; +import static android.view.InsetsState.LAST_TYPE; import static android.view.View.PFLAG_DRAW_ANIMATION; import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN; import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; @@ -110,6 +111,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; +import android.os.UserHandle; import android.sysprop.DisplayProperties; import android.util.AndroidRuntimeException; import android.util.DisplayMetrics; @@ -558,7 +560,8 @@ public final class ViewRootImpl implements ViewParent, final DisplayCutout.ParcelableWrapper mPendingDisplayCutout = new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT); boolean mPendingAlwaysConsumeSystemBars; - private InsetsState mTempInsets = new InsetsState(); + private final InsetsState mTempInsets = new InsetsState(); + private final InsetsSourceControl[] mTempControls = new InsetsSourceControl[LAST_TYPE + 1]; final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets = new ViewTreeObserver.InternalInsetsInfo(); @@ -891,6 +894,14 @@ public final class ViewRootImpl implements ViewParent, * We have one child */ public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { + setView(view, attrs, panelParentView, UserHandle.myUserId()); + } + + /** + * We have one child + */ + public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, + int userId) { synchronized (this) { if (mView == null) { mView = view; @@ -999,11 +1010,11 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); adjustLayoutParamsForCompatibility(mWindowAttributes); - res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, - getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, + res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes, + getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mDisplayCutout, inputChannel, - mTempInsets); + mTempInsets, mTempControls); setFrame(mTmpFrame); } catch (RemoteException e) { mAdded = false; @@ -1028,6 +1039,7 @@ public final class ViewRootImpl implements ViewParent, (res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0; mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars; mInsetsController.onStateChanged(mTempInsets); + mInsetsController.onControlsChanged(mTempControls); if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow); if (res < WindowManagerGlobal.ADD_OKAY) { mAttachInfo.mRootView = null; @@ -1072,6 +1084,9 @@ public final class ViewRootImpl implements ViewParent, throw new WindowManager.InvalidDisplayException("Unable to add window " + mWindow + " -- the specified window type " + mWindowAttributes.type + " is not valid"); + case WindowManagerGlobal.ADD_INVALID_USER: + throw new WindowManager.BadTokenException("Unable to add Window " + + mWindow + " -- requested userId is not valid"); } throw new RuntimeException( "Unable to add window -- unknown error code " + res); @@ -3014,6 +3029,10 @@ public final class ViewRootImpl implements ViewParent, if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { reportNextDraw(); } + if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC) != 0) { + reportNextDraw(); + setUseBLASTSyncTransaction(); + } boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; @@ -3722,7 +3741,7 @@ public final class ViewRootImpl implements ViewParent, if (needFrameCompleteCallback) { final Handler handler = mAttachInfo.mHandler; mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> { - finishBLASTSync(); + finishBLASTSync(!reportNextDraw); handler.postAtFrontOfQueue(() -> { if (reportNextDraw) { // TODO: Use the frame number @@ -3756,7 +3775,7 @@ public final class ViewRootImpl implements ViewParent, if (usingAsyncReport && !canUseAsync) { mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null); usingAsyncReport = false; - finishBLASTSync(); + finishBLASTSync(true /* apply */); } } finally { mIsDrawing = false; @@ -7356,7 +7375,7 @@ public final class ViewRootImpl implements ViewParent, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber, mTmpFrame, mTmpRect, mTmpRect, mTmpRect, mPendingBackDropFrame, mPendingDisplayCutout, mPendingMergedConfiguration, mSurfaceControl, mTempInsets, - mSurfaceSize, mBlastSurfaceControl); + mTempControls, mSurfaceSize, mBlastSurfaceControl); if (mSurfaceControl.isValid()) { if (!mUseBLASTAdapter) { mSurface.copyFrom(mSurfaceControl); @@ -7386,6 +7405,7 @@ public final class ViewRootImpl implements ViewParent, } setFrame(mTmpFrame); mInsetsController.onStateChanged(mTempInsets); + mInsetsController.onControlsChanged(mTempControls); return relayoutResult; } @@ -9572,10 +9592,15 @@ public final class ViewRootImpl implements ViewParent, mNextDrawUseBLASTSyncTransaction = true; } - private void finishBLASTSync() { + private void finishBLASTSync(boolean apply) { if (mNextReportConsumeBLAST) { mNextReportConsumeBLAST = false; - mRtBLASTSyncTransaction.apply(); + + if (apply) { + mRtBLASTSyncTransaction.apply(); + } else { + mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction); + } } } diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index ca3dd04fd756..aad1c60d7b7e 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -473,6 +473,12 @@ public final class WindowInsets { /** * Returns the display cutout if there is one. * + * <p>Note: the display cutout will already be {@link #consumeDisplayCutout consumed} during + * dispatch to {@link View#onApplyWindowInsets}, unless the window has requested a + * {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode} other than + * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER never} or + * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT default}. + * * @return the display cutout or null if there is none * @see DisplayCutout */ @@ -1424,7 +1430,13 @@ public final class WindowInsets { /** * Returns an insets type representing the area that used by {@link DisplayCutout}. * - * <p>This is equivalent to the safe insets on {@link #getDisplayCutout()}.</p> + * <p>This is equivalent to the safe insets on {@link #getDisplayCutout()}. + * + * <p>Note: During dispatch to {@link View#onApplyWindowInsets}, if the window is using + * the {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT default} + * {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode}, {@link #getDisplayCutout()} + * will return {@code null} even if the window overlaps a display cutout area, in which case + * the {@link #displayCutout() displayCutout() inset} will still report the accurate value. * * @see DisplayCutout#getSafeInsetLeft() * @see DisplayCutout#getSafeInsetTop() diff --git a/core/java/android/view/WindowInsetsAnimationController.java b/core/java/android/view/WindowInsetsAnimationController.java index c191a54283fb..fb9d05e2d730 100644 --- a/core/java/android/view/WindowInsetsAnimationController.java +++ b/core/java/android/view/WindowInsetsAnimationController.java @@ -141,7 +141,10 @@ public interface WindowInsetsAnimationController { /** * Finishes the animation, and leaves the windows shown or hidden. * <p> - * After invoking {@link #finish(boolean)}, this instance is no longer {@link #isReady ready}. + * After invoking {@link #finish}, this instance is no longer {@link #isReady ready}. + * <p> + * Note: Finishing an animation implicitly {@link #setInsetsAndAlpha sets insets and alpha} + * according to the requested end state without any further animation. * * @param shown if {@code true}, the windows will be shown after finishing the * animation. Otherwise they will be hidden. diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 410d9afe73da..fba6a55ef6db 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -102,6 +102,14 @@ public final class WindowManagerGlobal { public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 0x40; /** + * This flag indicates the client should not directly submit it's next frame, + * but instead should pass it in the postDrawTransaction of + * {@link WindowManagerService#finishDrawing}. This is used by the WM + * BLASTSyncEngine to synchronize rendering of multiple windows. + */ + public static final int RELAYOUT_RES_BLAST_SYNC = 0x80; + + /** * Flag for relayout: the client will be later giving * internal insets; as a result, the window will not impact other window * layouts until the insets are given. @@ -136,6 +144,7 @@ public final class WindowManagerGlobal { public static final int ADD_PERMISSION_DENIED = -8; public static final int ADD_INVALID_DISPLAY = -9; public static final int ADD_INVALID_TYPE = -10; + public static final int ADD_INVALID_USER = -11; @UnsupportedAppUsage private static WindowManagerGlobal sDefaultWindowManager; @@ -317,7 +326,7 @@ public final class WindowManagerGlobal { } public void addView(View view, ViewGroup.LayoutParams params, - Display display, Window parentWindow) { + Display display, Window parentWindow, int userId) { if (view == null) { throw new IllegalArgumentException("view must not be null"); } @@ -394,7 +403,7 @@ public final class WindowManagerGlobal { // do this last because it fires off messages to start doing things try { - root.setView(view, wparams, panelParentView); + root.setView(view, wparams, panelParentView, userId); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 316a5f2c88d2..2975d5ee8e1c 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -104,7 +104,8 @@ public final class WindowManagerImpl implements WindowManager { @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); - mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow); + mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow, + mContext.getUserId()); } @Override diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 144f8e3a7108..ec5130143086 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -104,7 +104,7 @@ public class WindowlessWindowManager implements IWindowSession { int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, - InsetsState outInsetsState) { + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession) .setParent(mRootSurface) .setFormat(attrs.format) @@ -130,6 +130,20 @@ public class WindowlessWindowManager implements IWindowSession { return WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE; } + /** + * IWindowSession implementation. Currently this class doesn't need to support for multi-user. + */ + @Override + public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs, + int viewVisibility, int displayId, int userId, Rect outFrame, + Rect outContentInsets, Rect outStableInsets, + DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { + return addToDisplay(window, seq, attrs, viewVisibility, displayId, + outFrame, outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, + outInsetsState, outActiveControls); + } + @Override public int addToDisplayWithoutInputChannel(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs, int viewVisibility, int layerStackId, @@ -179,7 +193,8 @@ public class WindowlessWindowManager implements IWindowSession { Rect outStableInsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl, InsetsState outInsetsState, - Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) { + InsetsSourceControl[] outActiveControls, Point outSurfaceSize, + SurfaceControl outBLASTSurfaceControl) { final State state; synchronized (this) { state = mStateForWindow.get(window.asBinder()); diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index edc6b1251f2c..4519aefe65fe 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -832,7 +832,7 @@ public final class ContentCaptureManager { void initializeForDelegate(DataShareAdapterDelegate delegate, DataShareWriteAdapter adapter, Executor executor) { mWriteAdapterHardReferences.put(delegate, adapter); - mExecutorHardReferences.remove(delegate, executor); + mExecutorHardReferences.put(delegate, executor); } Executor getExecutor(DataShareAdapterDelegate delegate) { diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 482d5b25e9da..71dd6653f6a6 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1968,6 +1968,38 @@ public final class InputMethodManager { return true; } + /** + * An empty method only to avoid crashes of apps that call this method via reflection and do not + * handle {@link NoSuchMethodException} in a graceful manner. + * + * @deprecated This is an empty method. No framework method must call this method. + * @hide + */ + @Deprecated + @UnsupportedAppUsage(trackingBug = 37122102, maxTargetSdk = Build.VERSION_CODES.Q, + publicAlternatives = "{@code androidx.activity.ComponentActivity}") + public void windowDismissed(IBinder appWindowToken) { + // Intentionally empty. + // + // It seems that some applications call this method via reflection to null clear the + // following fields that used to exist in InputMethodManager: + // * InputMethodManager#mCurRootView + // * InputMethodManager#mServedView + // * InputMethodManager#mNextServedView + // so that these objects can be garbage-collected when an Activity gets dismissed. + // + // It is indeed true that older versions of InputMethodManager had issues that prevented + // these fields from being null-cleared when it should have been, but the understanding of + // the engineering team is that all known issues have already been fixed as of Android 10. + // + // For older devices, developers can work around the object leaks by using + // androidx.activity.ComponentActivity. + // See https://issuetracker.google.com/u/1/issues/37122102 for details. + // + // If you believe InputMethodManager is leaking objects in API 24 or any later version, + // please file a bug at https://issuetracker.google.com/issues/new?component=192705. + } + private int getStartInputFlags(View focusedView, int startInputFlags) { startInputFlags |= StartInputFlags.VIEW_HAS_FOCUS; if (focusedView.onCheckIsTextEditor()) { diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java index 842ba2975b3b..6ad5cb913553 100644 --- a/core/java/android/view/textclassifier/ConversationActions.java +++ b/core/java/android/view/textclassifier/ConversationActions.java @@ -27,8 +27,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.SpannedString; -import com.android.internal.util.Preconditions; - import java.lang.annotation.Retention; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @@ -491,7 +489,11 @@ public final class ConversationActions implements Parcelable { */ @NonNull public Builder setMaxSuggestions(@IntRange(from = -1) int maxSuggestions) { - mMaxSuggestions = Preconditions.checkArgumentNonnegative(maxSuggestions); + if (maxSuggestions < -1) { + throw new IllegalArgumentException("maxSuggestions has to be greater than or " + + "equal to -1."); + } + mMaxSuggestions = maxSuggestions; return this; } diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java index 71ccb595278b..849488d42bcf 100644 --- a/core/java/android/widget/RadioGroup.java +++ b/core/java/android/widget/RadioGroup.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.View; @@ -484,21 +485,21 @@ public class RadioGroup extends LinearLayout { super.onInitializeAccessibilityNodeInfo(info); if (this.getOrientation() == HORIZONTAL) { info.setCollectionInfo(AccessibilityNodeInfo.CollectionInfo.obtain(1, - getVisibleChildCount(), false, + getVisibleChildWithTextCount(), false, AccessibilityNodeInfo.CollectionInfo.SELECTION_MODE_SINGLE)); } else { info.setCollectionInfo( - AccessibilityNodeInfo.CollectionInfo.obtain(getVisibleChildCount(), + AccessibilityNodeInfo.CollectionInfo.obtain(getVisibleChildWithTextCount(), 1, false, AccessibilityNodeInfo.CollectionInfo.SELECTION_MODE_SINGLE)); } } - private int getVisibleChildCount() { + private int getVisibleChildWithTextCount() { int count = 0; for (int i = 0; i < getChildCount(); i++) { if (this.getChildAt(i) instanceof RadioButton) { - if (((RadioButton) this.getChildAt(i)).getVisibility() == VISIBLE) { + if (isVisibleWithText((RadioButton) this.getChildAt(i))) { count++; } } @@ -513,15 +514,19 @@ public class RadioGroup extends LinearLayout { int index = 0; for (int i = 0; i < getChildCount(); i++) { if (this.getChildAt(i) instanceof RadioButton) { - RadioButton radioButton = (RadioButton) this.getChildAt(i); - if (radioButton == child) { + RadioButton button = (RadioButton) this.getChildAt(i); + if (button == child) { return index; } - if (radioButton.getVisibility() == VISIBLE) { + if (isVisibleWithText(button)) { index++; } } } return -1; } + + private boolean isVisibleWithText(RadioButton button) { + return button.getVisibility() == VISIBLE && !TextUtils.isEmpty(button.getText()); + } }
\ No newline at end of file diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java index eee222b9bf4c..6ae70b779960 100644 --- a/core/java/android/window/DisplayAreaOrganizer.java +++ b/core/java/android/window/DisplayAreaOrganizer.java @@ -33,8 +33,8 @@ public class DisplayAreaOrganizer extends WindowOrganizer { public static final int FEATURE_SYSTEM_FIRST = 0; // The Root display area on a display public static final int FEATURE_ROOT = FEATURE_SYSTEM_FIRST; - // Display area hosting the task container. - public static final int FEATURE_TASK_CONTAINER = FEATURE_SYSTEM_FIRST + 1; + // Display area hosting the default task container. + public static final int FEATURE_DEFAULT_TASK_CONTAINER = FEATURE_SYSTEM_FIRST + 1; // Display area hosting non-activity window tokens. public static final int FEATURE_WINDOW_TOKENS = FEATURE_SYSTEM_FIRST + 2; diff --git a/core/java/android/window/TaskEmbedder.java b/core/java/android/window/TaskEmbedder.java index 45ab310c5148..2ead37a9397d 100644 --- a/core/java/android/window/TaskEmbedder.java +++ b/core/java/android/window/TaskEmbedder.java @@ -26,7 +26,6 @@ import android.app.ActivityTaskManager; import android.app.ActivityView; import android.app.IActivityTaskManager; import android.app.PendingIntent; -import android.app.TaskStackListener; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -129,7 +128,6 @@ public abstract class TaskEmbedder { protected SurfaceControl.Transaction mTransaction; protected SurfaceControl mSurfaceControl; - protected TaskStackListener mTaskStackListener; protected Listener mListener; protected boolean mOpened; // Protected by mGuard. @@ -170,13 +168,6 @@ public abstract class TaskEmbedder { if (!onInitialize()) { return false; } - - mTaskStackListener = createTaskStackListener(); - try { - mActivityTaskManager.registerTaskStackListener(mTaskStackListener); - } catch (RemoteException e) { - Log.e(TAG, "Failed to register task stack listener", e); - } if (mListener != null && isInitialized()) { mListener.onInitialized(); } @@ -187,11 +178,6 @@ public abstract class TaskEmbedder { } /** - * @return the task stack listener for this embedder - */ - public abstract TaskStackListener createTaskStackListener(); - - /** * Whether this container has been initialized. * * @return true if initialized @@ -420,16 +406,6 @@ public abstract class TaskEmbedder { mSurfaceControl.release(); boolean reportReleased = onRelease(); - - if (mTaskStackListener != null) { - try { - mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); - } catch (RemoteException e) { - Log.e(TAG, "Failed to unregister task stack listener", e); - } - mTaskStackListener = null; - } - if (mListener != null && reportReleased) { mListener.onReleased(); } diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index 5098b4440070..f661d9af5999 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -16,6 +16,7 @@ package android.window; +import android.annotation.BinderThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -39,7 +40,7 @@ public class TaskOrganizer extends WindowOrganizer { * and receive taskVanished callbacks in the process. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - public void registerOrganizer(int windowingMode) { + public final void registerOrganizer(int windowingMode) { try { getController().registerTaskOrganizer(mInterface, windowingMode); } catch (RemoteException e) { @@ -49,7 +50,7 @@ public class TaskOrganizer extends WindowOrganizer { /** Unregisters a previously registered task organizer. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - public void unregisterOrganizer() { + public final void unregisterOrganizer() { try { getController().unregisterTaskOrganizer(mInterface); } catch (RemoteException e) { @@ -57,13 +58,17 @@ public class TaskOrganizer extends WindowOrganizer { } } + @BinderThread public void onTaskAppeared(@NonNull ActivityManager.RunningTaskInfo taskInfo) {} + @BinderThread public void onTaskVanished(@NonNull ActivityManager.RunningTaskInfo taskInfo) {} - public void onTaskInfoChanged(@NonNull ActivityManager.RunningTaskInfo info) {} + @BinderThread + public void onTaskInfoChanged(@NonNull ActivityManager.RunningTaskInfo taskInfo) {} - public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo info) {} + @BinderThread + public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo taskInfo) {} /** Creates a persistent root task in WM for a particular windowing-mode. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java index 2091c9398e95..b63741ec69c4 100644 --- a/core/java/android/window/TaskOrganizerTaskEmbedder.java +++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java @@ -21,7 +21,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import android.app.ActivityManager; import android.app.ActivityOptions; -import android.app.ActivityView; import android.app.TaskStackListener; import android.content.Context; import android.graphics.Rect; @@ -55,11 +54,6 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { super(context, host); } - @Override - public TaskStackListener createTaskStackListener() { - return new TaskStackListenerImpl(); - } - /** * Whether this container has been initialized. * @@ -219,29 +213,6 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { Log.d(TAG, "[" + System.identityHashCode(this) + "] " + msg); } - /** - * A task change listener that detects background color change of the topmost stack on our - * virtual display and updates the background of the surface view. This background will be shown - * when surface view is resized, but the app hasn't drawn its content in new size yet. - * It also calls StateCallback.onTaskMovedToFront to notify interested parties that the stack - * associated with the {@link ActivityView} has had a Task moved to the front. This is useful - * when needing to also bring the host Activity to the foreground at the same time. - */ - private class TaskStackListenerImpl extends TaskStackListener { - - @Override - public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo) { - if (!isInitialized()) { - return; - } - if (taskInfo.taskId == mTaskInfo.taskId) { - mTaskInfo.taskDescription = taskInfo.taskDescription; - mHost.onTaskBackgroundColorChanged(TaskOrganizerTaskEmbedder.this, - taskInfo.taskDescription.getBackgroundColor()); - } - } - } - private class TaskOrganizerImpl extends TaskOrganizer { @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) { @@ -249,12 +220,13 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { log("taskAppeared: " + taskInfo.taskId); } - // TODO: Ensure visibility/alpha of the leash in its initial state? mTaskInfo = taskInfo; mTaskToken = taskInfo.token; mTaskLeash = mTaskToken.getLeash(); mTransaction.reparent(mTaskLeash, mSurfaceControl) - .show(mSurfaceControl).apply(); + .show(mTaskLeash) + .show(mSurfaceControl) + .apply(); if (mPendingNotifyBoundsChanged) { // TODO: Either defer show or hide and synchronize show with the resize notifyBoundsChanged(); @@ -268,6 +240,13 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { } @Override + public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { + mTaskInfo.taskDescription = taskInfo.taskDescription; + mHost.post(() -> mHost.onTaskBackgroundColorChanged(TaskOrganizerTaskEmbedder.this, + taskInfo.taskDescription.getBackgroundColor())); + } + + @Override public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { if (DEBUG) { log("taskVanished: " + taskInfo.taskId); diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java index 1afbfeb96fc3..70164692032f 100644 --- a/core/java/android/window/VirtualDisplayTaskEmbedder.java +++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java @@ -16,7 +16,6 @@ package android.window; -import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; @@ -68,6 +67,7 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { private VirtualDisplay mVirtualDisplay; private Insets mForwardedInsets; private DisplayMetrics mTmpDisplayMetrics; + private TaskStackListener mTaskStackListener; /** * Constructs a new TaskEmbedder. @@ -83,11 +83,6 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { mSingleTaskInstance = singleTaskInstance; } - @Override - public TaskStackListener createTaskStackListener() { - return new TaskStackListenerImpl(); - } - /** * Whether this container has been initialized. * @@ -125,6 +120,9 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { .setDisplayToSingleTaskInstance(displayId); } setForwardedInsets(mForwardedInsets); + + mTaskStackListener = new TaskStackListenerImpl(); + mActivityTaskManager.registerTaskStackListener(mTaskStackListener); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } @@ -143,6 +141,15 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { // Clear tap-exclude region (if any) for this window. clearTapExcludeRegion(); + if (mTaskStackListener != null) { + try { + mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); + } catch (RemoteException e) { + Log.e(TAG, "Failed to unregister task stack listener", e); + } + mTaskStackListener = null; + } + if (isInitialized()) { mVirtualDisplay.release(); mVirtualDisplay = null; @@ -247,7 +254,6 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { protected ActivityOptions prepareActivityOptions(ActivityOptions options) { options = super.prepareActivityOptions(options); options.setLaunchDisplayId(getDisplayId()); - options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW); return options; } diff --git a/core/java/android/window/WindowContainerToken.java b/core/java/android/window/WindowContainerToken.java index dde98dae4057..3316d0e5b71f 100644 --- a/core/java/android/window/WindowContainerToken.java +++ b/core/java/android/window/WindowContainerToken.java @@ -84,4 +84,17 @@ public final class WindowContainerToken implements Parcelable { public int describeContents() { return 0; } + + @Override + public int hashCode() { + return mRealToken.asBinder().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof WindowContainerToken)) { + return false; + } + return mRealToken.asBinder() == ((WindowContainerToken) obj).asBinder(); + } } diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java index 79b34c05bf87..b814e3f47162 100644 --- a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java +++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java @@ -55,26 +55,27 @@ public final class ShortcutConstants { } /** - * Annotation for different accessibilityService fragment UI type. + * Annotation for the different accessibility fragment type. * - * {@code LEGACY} for displaying appearance aligned with sdk version Q accessibility service - * page, but only hardware shortcut allowed and under service in version Q or early. - * {@code INVISIBLE} for displaying appearance without switch bar. - * {@code INTUITIVE} for displaying appearance with version R accessibility design. - * {@code BOUNCE} for displaying appearance with pop-up action. + * {@code VOLUME_SHORTCUT_TOGGLE} for displaying appearance with switch bar and only one + * shortcut option that is volume key shortcut. + * {@code INVISIBLE_TOGGLE} for displaying appearance without switch bar. + * {@code TOGGLE} for displaying appearance with switch bar. + * {@code LAUNCH_ACTIVITY} for displaying appearance with pop-up action that is for launch + * activity. */ @Retention(RetentionPolicy.SOURCE) @IntDef({ - AccessibilityServiceFragmentType.LEGACY, - AccessibilityServiceFragmentType.INVISIBLE, - AccessibilityServiceFragmentType.INTUITIVE, - AccessibilityServiceFragmentType.BOUNCE, + AccessibilityFragmentType.VOLUME_SHORTCUT_TOGGLE, + AccessibilityFragmentType.INVISIBLE_TOGGLE, + AccessibilityFragmentType.TOGGLE, + AccessibilityFragmentType.LAUNCH_ACTIVITY, }) - public @interface AccessibilityServiceFragmentType { - int LEGACY = 0; - int INVISIBLE = 1; - int INTUITIVE = 2; - int BOUNCE = 3; + public @interface AccessibilityFragmentType { + int VOLUME_SHORTCUT_TOGGLE = 0; + int INVISIBLE_TOGGLE = 1; + int TOGGLE = 2; + int LAUNCH_ACTIVITY = 3; } /** diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java index 51b13345a6c3..9338c3c87217 100644 --- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.internal.app; +package com.android.internal.accessibility.dialog; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; @@ -22,7 +22,7 @@ import static android.view.accessibility.AccessibilityManager.ShortcutType; import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; -import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityServiceFragmentType; +import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; import static com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode; import static com.android.internal.accessibility.common.ShortcutConstants.TargetType; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; @@ -79,9 +79,10 @@ import java.util.List; import java.util.Locale; /** - * Activity used to display and persist a service or feature target for the Accessibility button. + * Activity used to display various targets related to accessibility service, accessibility + * activity or white listing feature for volume key shortcut. */ -public class AccessibilityButtonChooserActivity extends Activity { +public class AccessibilityShortcutChooserActivity extends Activity { @ShortcutType private static int sShortcutType; @UserShortcutType @@ -97,21 +98,21 @@ public class AccessibilityButtonChooserActivity extends Activity { COLOR_INVERSION_COMPONENT_NAME.flattenToString(), String.valueOf(R.string.color_inversion_feature_name), String.valueOf(R.drawable.ic_accessibility_color_inversion), - String.valueOf(AccessibilityServiceFragmentType.INTUITIVE), + String.valueOf(AccessibilityFragmentType.TOGGLE), Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, }, { DALTONIZER_COMPONENT_NAME.flattenToString(), String.valueOf(R.string.color_correction_feature_name), String.valueOf(R.drawable.ic_accessibility_color_correction), - String.valueOf(AccessibilityServiceFragmentType.INTUITIVE), + String.valueOf(AccessibilityFragmentType.TOGGLE), Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, }, { MAGNIFICATION_CONTROLLER_NAME, String.valueOf(R.string.accessibility_magnification_chooser_text), String.valueOf(R.drawable.ic_accessibility_magnification), - String.valueOf(AccessibilityServiceFragmentType.INVISIBLE), + String.valueOf(AccessibilityFragmentType.INVISIBLE_TOGGLE), Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, }, }; @@ -355,17 +356,18 @@ public class AccessibilityButtonChooserActivity extends Activity { ViewHolder holder; if (convertView == null) { convertView = LayoutInflater.from(context).inflate( - R.layout.accessibility_button_chooser_item, parent, /* attachToRoot= */ + R.layout.accessibility_shortcut_chooser_item, parent, /* attachToRoot= */ false); holder = new ViewHolder(); holder.mItemView = convertView; holder.mCheckBox = convertView.findViewById( - R.id.accessibility_button_target_checkbox); - holder.mIconView = convertView.findViewById(R.id.accessibility_button_target_icon); + R.id.accessibility_shortcut_target_checkbox); + holder.mIconView = convertView.findViewById( + R.id.accessibility_shortcut_target_icon); holder.mLabelView = convertView.findViewById( - R.id.accessibility_button_target_label); + R.id.accessibility_shortcut_target_label); holder.mSwitchItem = convertView.findViewById( - R.id.accessibility_button_target_switch_item); + R.id.accessibility_shortcut_target_switch_item); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); @@ -381,25 +383,25 @@ public class AccessibilityButtonChooserActivity extends Activity { @NonNull ViewHolder holder, AccessibilityButtonTarget target) { switch (target.getFragmentType()) { - case AccessibilityServiceFragmentType.LEGACY: - updateLegacyActionItemVisibility(holder, target); + case AccessibilityFragmentType.VOLUME_SHORTCUT_TOGGLE: + updateVolumeShortcutToggleTargetActionItemVisibility(holder, target); break; - case AccessibilityServiceFragmentType.INVISIBLE: - updateInvisibleActionItemVisibility(holder, target); + case AccessibilityFragmentType.INVISIBLE_TOGGLE: + updateInvisibleToggleTargetActionItemVisibility(holder, target); break; - case AccessibilityServiceFragmentType.INTUITIVE: - updateIntuitiveActionItemVisibility(context, holder, target); + case AccessibilityFragmentType.TOGGLE: + updateToggleTargetActionItemVisibility(context, holder, target); break; - case AccessibilityServiceFragmentType.BOUNCE: - updateBounceActionItemVisibility(holder, target); + case AccessibilityFragmentType.LAUNCH_ACTIVITY: + updateLaunchActivityTargetActionItemVisibility(holder, target); break; default: throw new IllegalStateException("Unexpected fragment type"); } } - private void updateLegacyActionItemVisibility(@NonNull ViewHolder holder, - AccessibilityButtonTarget target) { + private void updateVolumeShortcutToggleTargetActionItemVisibility( + @NonNull ViewHolder holder, AccessibilityButtonTarget target) { final boolean isLaunchMenuMode = (mShortcutMenuMode == ShortcutMenuMode.LAUNCH); holder.mCheckBox.setChecked(!isLaunchMenuMode && target.isChecked()); @@ -409,7 +411,7 @@ public class AccessibilityButtonChooserActivity extends Activity { holder.mSwitchItem.setVisibility(View.GONE); } - private void updateInvisibleActionItemVisibility(@NonNull ViewHolder holder, + private void updateInvisibleToggleTargetActionItemVisibility(@NonNull ViewHolder holder, AccessibilityButtonTarget target) { final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT); @@ -420,7 +422,7 @@ public class AccessibilityButtonChooserActivity extends Activity { holder.mSwitchItem.setVisibility(View.GONE); } - private void updateIntuitiveActionItemVisibility(@NonNull Context context, + private void updateToggleTargetActionItemVisibility(@NonNull Context context, @NonNull ViewHolder holder, AccessibilityButtonTarget target) { final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT); final boolean isServiceEnabled = isWhiteListingService(target.getId()) @@ -435,7 +437,7 @@ public class AccessibilityButtonChooserActivity extends Activity { holder.mSwitchItem.setChecked(!isEditMenuMode && isServiceEnabled); } - private void updateBounceActionItemVisibility(@NonNull ViewHolder holder, + private void updateLaunchActivityTargetActionItemVisibility(@NonNull ViewHolder holder, AccessibilityButtonTarget target) { final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT); @@ -454,7 +456,7 @@ public class AccessibilityButtonChooserActivity extends Activity { private boolean mChecked; private CharSequence mLabel; private Drawable mDrawable; - @AccessibilityServiceFragmentType + @AccessibilityFragmentType private int mFragmentType; AccessibilityButtonTarget(@NonNull Context context, @@ -474,11 +476,11 @@ public class AccessibilityButtonChooserActivity extends Activity { this.mChecked = isTargetShortcutUsed(context, mId); this.mLabel = shortcutInfo.getActivityInfo().loadLabel(context.getPackageManager()); this.mDrawable = shortcutInfo.getActivityInfo().loadIcon(context.getPackageManager()); - this.mFragmentType = AccessibilityServiceFragmentType.BOUNCE; + this.mFragmentType = AccessibilityFragmentType.LAUNCH_ACTIVITY; } AccessibilityButtonTarget(Context context, @NonNull String id, int labelResId, - int iconRes, @AccessibilityServiceFragmentType int fragmentType) { + int iconRes, @AccessibilityFragmentType int fragmentType) { this.mId = id; this.mType = TargetType.WHITE_LISTING; this.mChecked = isTargetShortcutUsed(context, mId); @@ -535,17 +537,17 @@ public class AccessibilityButtonChooserActivity extends Activity { private void onTargetSelected(AdapterView<?> parent, View view, int position, long id) { final AccessibilityButtonTarget target = mTargets.get(position); switch (target.getFragmentType()) { - case AccessibilityServiceFragmentType.LEGACY: - onLegacyTargetSelected(target); + case AccessibilityFragmentType.VOLUME_SHORTCUT_TOGGLE: + onVolumeShortcutToggleTargetSelected(target); break; - case AccessibilityServiceFragmentType.INVISIBLE: - onInvisibleTargetSelected(target); + case AccessibilityFragmentType.INVISIBLE_TOGGLE: + onInvisibleToggleTargetSelected(target); break; - case AccessibilityServiceFragmentType.INTUITIVE: - onIntuitiveTargetSelected(target); + case AccessibilityFragmentType.TOGGLE: + onToggleTargetSelected(target); break; - case AccessibilityServiceFragmentType.BOUNCE: - onBounceTargetSelected(target); + case AccessibilityFragmentType.LAUNCH_ACTIVITY: + onLaunchActivityTargetSelected(target); break; default: throw new IllegalStateException("Unexpected fragment type"); @@ -554,7 +556,7 @@ public class AccessibilityButtonChooserActivity extends Activity { mAlertDialog.dismiss(); } - private void onLegacyTargetSelected(AccessibilityButtonTarget target) { + private void onVolumeShortcutToggleTargetSelected(AccessibilityButtonTarget target) { if (sShortcutType == ACCESSIBILITY_BUTTON) { final AccessibilityManager ams = getSystemService(AccessibilityManager.class); ams.notifyAccessibilityButtonClicked(getDisplayId(), target.getId()); @@ -563,7 +565,7 @@ public class AccessibilityButtonChooserActivity extends Activity { } } - private void onInvisibleTargetSelected(AccessibilityButtonTarget target) { + private void onInvisibleToggleTargetSelected(AccessibilityButtonTarget target) { final AccessibilityManager ams = getSystemService(AccessibilityManager.class); if (sShortcutType == ACCESSIBILITY_BUTTON) { ams.notifyAccessibilityButtonClicked(getDisplayId(), target.getId()); @@ -572,11 +574,11 @@ public class AccessibilityButtonChooserActivity extends Activity { } } - private void onIntuitiveTargetSelected(AccessibilityButtonTarget target) { + private void onToggleTargetSelected(AccessibilityButtonTarget target) { switchServiceState(target); } - private void onBounceTargetSelected(AccessibilityButtonTarget target) { + private void onLaunchActivityTargetSelected(AccessibilityButtonTarget target) { final AccessibilityManager ams = getSystemService(AccessibilityManager.class); if (sShortcutType == ACCESSIBILITY_BUTTON) { ams.notifyAccessibilityButtonClicked(getDisplayId(), target.getId()); @@ -620,24 +622,24 @@ public class AccessibilityButtonChooserActivity extends Activity { private void onTargetChecked(AccessibilityButtonTarget target, boolean checked) { switch (target.getFragmentType()) { - case AccessibilityServiceFragmentType.LEGACY: - onLegacyTargetChecked(checked); + case AccessibilityFragmentType.VOLUME_SHORTCUT_TOGGLE: + onVolumeShortcutToggleTargetChecked(checked); break; - case AccessibilityServiceFragmentType.INVISIBLE: - onInvisibleTargetChecked(checked); + case AccessibilityFragmentType.INVISIBLE_TOGGLE: + onInvisibleToggleTargetChecked(checked); break; - case AccessibilityServiceFragmentType.INTUITIVE: - onIntuitiveTargetChecked(checked); + case AccessibilityFragmentType.TOGGLE: + onToggleTargetChecked(checked); break; - case AccessibilityServiceFragmentType.BOUNCE: - onBounceTargetChecked(checked); + case AccessibilityFragmentType.LAUNCH_ACTIVITY: + onLaunchActivityTargetChecked(checked); break; default: throw new IllegalStateException("Unexpected fragment type"); } } - private void onLegacyTargetChecked(boolean checked) { + private void onVolumeShortcutToggleTargetChecked(boolean checked) { if (sShortcutType == ACCESSIBILITY_BUTTON) { setServiceEnabled(mCurrentCheckedTarget.getId(), checked); if (!checked) { @@ -657,7 +659,7 @@ public class AccessibilityButtonChooserActivity extends Activity { mTargetAdapter.notifyDataSetChanged(); } - private void onInvisibleTargetChecked(boolean checked) { + private void onInvisibleToggleTargetChecked(boolean checked) { final int shortcutTypes = UserShortcutType.SOFTWARE | HARDWARE; if (!hasValuesInSettings(this, shortcutTypes, mCurrentCheckedTarget.getId())) { setServiceEnabled(mCurrentCheckedTarget.getId(), checked); @@ -668,13 +670,13 @@ public class AccessibilityButtonChooserActivity extends Activity { mTargetAdapter.notifyDataSetChanged(); } - private void onIntuitiveTargetChecked(boolean checked) { + private void onToggleTargetChecked(boolean checked) { updateValueToSettings(mCurrentCheckedTarget.getId(), checked); mCurrentCheckedTarget.setChecked(checked); mTargetAdapter.notifyDataSetChanged(); } - private void onBounceTargetChecked(boolean checked) { + private void onLaunchActivityTargetChecked(boolean checked) { updateValueToSettings(mCurrentCheckedTarget.getId(), checked); mCurrentCheckedTarget.setChecked(checked); mTargetAdapter.notifyDataSetChanged(); @@ -740,7 +742,8 @@ public class AccessibilityButtonChooserActivity extends Activity { } private void onPermissionAllowButtonClicked(View view) { - if (mCurrentCheckedTarget.getFragmentType() != AccessibilityServiceFragmentType.LEGACY) { + if (mCurrentCheckedTarget.getFragmentType() + != AccessibilityFragmentType.VOLUME_SHORTCUT_TOGGLE) { updateValueToSettings(mCurrentCheckedTarget.getId(), /* checked= */ true); } onTargetChecked(mCurrentCheckedTarget, /* checked= */ true); diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java index d0ead5e3b6ce..a92a50d4d832 100644 --- a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java +++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java @@ -15,10 +15,11 @@ */ package com.android.internal.accessibility.util; -import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityServiceFragmentType; +import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR; import android.accessibilityservice.AccessibilityServiceInfo; +import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.os.Build; @@ -112,20 +113,20 @@ public final class AccessibilityUtils { * Gets the corresponding fragment type of a given accessibility service. * * @param accessibilityServiceInfo The accessibilityService's info. - * @return int from {@link AccessibilityServiceFragmentType}. + * @return int from {@link AccessibilityFragmentType}. */ - public static @AccessibilityServiceFragmentType int getAccessibilityServiceFragmentType( - AccessibilityServiceInfo accessibilityServiceInfo) { + public static @AccessibilityFragmentType int getAccessibilityServiceFragmentType( + @NonNull AccessibilityServiceInfo accessibilityServiceInfo) { final int targetSdk = accessibilityServiceInfo.getResolveInfo() .serviceInfo.applicationInfo.targetSdkVersion; final boolean requestA11yButton = (accessibilityServiceInfo.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; if (targetSdk <= Build.VERSION_CODES.Q) { - return AccessibilityServiceFragmentType.LEGACY; + return AccessibilityFragmentType.VOLUME_SHORTCUT_TOGGLE; } return requestA11yButton - ? AccessibilityServiceFragmentType.INVISIBLE - : AccessibilityServiceFragmentType.INTUITIVE; + ? AccessibilityFragmentType.INVISIBLE_TOGGLE + : AccessibilityFragmentType.TOGGLE; } } diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java index 717e78078b1c..7ec80ecdb2a9 100644 --- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java +++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java @@ -39,21 +39,21 @@ public final class ShortcutUtils { new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR); /** - * Opts in component name into colon-separated {@link UserShortcutType} - * key's string in Settings. + * Opts in component id into colon-separated {@link UserShortcutType} + * key's string from Settings. * * @param context The current context. * @param shortcutType The preferred shortcut type user selected. - * @param componentId The component id that need to be opted out from Settings. + * @param componentId The component id that need to be opted in Settings. */ public static void optInValueToSettings(Context context, @UserShortcutType int shortcutType, - String componentId) { + @NonNull String componentId) { final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR)); final String targetKey = convertToKey(shortcutType); final String targetString = Settings.Secure.getString(context.getContentResolver(), targetKey); - if (hasValueInSettings(context, shortcutType, componentId)) { + if (isComponentIdExistingInSettings(context, shortcutType, componentId)) { return; } @@ -66,14 +66,15 @@ public final class ShortcutUtils { } /** - * Opts out component name into colon-separated {@code shortcutType} key's string in Settings. + * Opts out of component id into colon-separated {@link UserShortcutType} key's string from + * Settings. * * @param context The current context. * @param shortcutType The preferred shortcut type user selected. - * @param componentId The component id that need to be opted out from Settings. + * @param componentId The component id that need to be opted out of Settings. */ public static void optOutValueFromSettings( - Context context, @UserShortcutType int shortcutType, String componentId) { + Context context, @UserShortcutType int shortcutType, @NonNull String componentId) { final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR)); final String targetsKey = convertToKey(shortcutType); final String targetsValue = Settings.Secure.getString(context.getContentResolver(), @@ -96,36 +97,38 @@ public final class ShortcutUtils { } /** - * Returns if component name existed in one of {@code shortcutTypes} string in Settings. + * Returns if component id existed in one of {@link UserShortcutType} string from Settings. * * @param context The current context. * @param shortcutTypes A combination of {@link UserShortcutType}. - * @param componentId The component name that need to be checked existed in Settings. - * @return {@code true} if componentName existed in Settings. + * @param componentId The component id that need to be checked existed in Settings. + * @return {@code true} if component id existed in Settings. */ - public static boolean hasValuesInSettings(Context context, int shortcutTypes, + public static boolean hasValuesInSettings(Context context, @UserShortcutType int shortcutTypes, @NonNull String componentId) { boolean exist = false; if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { - exist = hasValueInSettings(context, UserShortcutType.SOFTWARE, componentId); + exist = isComponentIdExistingInSettings(context, UserShortcutType.SOFTWARE, + componentId); } if (((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE)) { - exist |= hasValueInSettings(context, UserShortcutType.HARDWARE, componentId); + exist |= isComponentIdExistingInSettings(context, UserShortcutType.HARDWARE, + componentId); } return exist; } /** - * Returns if component name existed in Settings. + * Returns if component id existed in Settings. * * @param context The current context. * @param shortcutType The preferred shortcut type user selected. * @param componentId The component id that need to be checked existed in Settings. - * @return {@code true} if componentName existed in Settings. + * @return {@code true} if component id existed in Settings. */ - public static boolean hasValueInSettings(Context context, @UserShortcutType int shortcutType, - @NonNull String componentId) { + public static boolean isComponentIdExistingInSettings(Context context, + @UserShortcutType int shortcutType, @NonNull String componentId) { final String targetKey = convertToKey(shortcutType); final String targetString = Settings.Secure.getString(context.getContentResolver(), targetKey); @@ -146,7 +149,7 @@ public final class ShortcutUtils { } /** - * Converts {@link UserShortcutType} to key in Settings. + * Converts {@link UserShortcutType} to {@link Settings.Secure} key. * * @param type The shortcut type. * @return Mapping key in Settings. @@ -169,7 +172,7 @@ public final class ShortcutUtils { * Converts {@link ShortcutType} to {@link UserShortcutType}. * * @param type The shortcut type. - * @return {@link UserShortcutType}. + * @return Mapping type from {@link UserShortcutType}. */ public static @UserShortcutType int convertToUserType(@ShortcutType int type) { switch (type) { diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java index 9fc0da83c504..d43333e507a6 100644 --- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java @@ -55,6 +55,7 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { private static final String TAG = "AbstractMultiProfilePagerAdapter"; static final int PROFILE_PERSONAL = 0; static final int PROFILE_WORK = 1; + @IntDef({PROFILE_PERSONAL, PROFILE_WORK}) @interface Profile {} @@ -365,7 +366,7 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { UserHandle listUserHandle = listAdapter.getUserHandle(); if (!listUserHandle.equals(mWorkProfileUserHandle) || !mInjector.isQuietModeEnabled(mWorkProfileUserHandle) - || !hasResolvedAppsInWorkProfile(listAdapter)) { + || listAdapter.getCount() == 0) { return false; } DevicePolicyEventLogger @@ -382,20 +383,6 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { return true; } - /** - * Returns {@code true} if there is at least one app resolved in the work profile, - * regardless of whether the work profile is enabled or not. - */ - private boolean hasResolvedAppsInWorkProfile(ResolverListAdapter listAdapter) { - List<ResolverActivity.ResolvedComponentInfo> userStateIndependentWorkResolvers = - listAdapter.mResolverListController.getUserStateIndependentResolversAsUser( - listAdapter.getIntents(), mWorkProfileUserHandle); - return userStateIndependentWorkResolvers.stream() - .anyMatch(resolvedComponentInfo -> - resolvedComponentInfo.getResolveInfoAt(0).targetUserId - == UserHandle.USER_CURRENT); - } - private void maybeShowNoAppsAvailableEmptyState(ResolverListAdapter listAdapter) { UserHandle listUserHandle = listAdapter.getUserHandle(); if (mWorkProfileUserHandle != null @@ -529,6 +516,13 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { return false; } + boolean shouldShowEmptyStateScreen(ResolverListAdapter listAdapter) { + int count = listAdapter.getUnfilteredCount(); + return (count == 0 && listAdapter.getPlaceholderCount() == 0) + || (listAdapter.getUserHandle().equals(mWorkProfileUserHandle) + && isQuietModeEnabled(mWorkProfileUserHandle)); + } + protected class ProfileDescriptor { final ViewGroup rootView; private final ViewGroup mEmptyStateView; diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index c82ab6c79e9d..3e7f24b034ac 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -169,6 +169,17 @@ public class ChooserActivity extends ResolverActivity implements public static final String EXTRA_PRIVATE_RETAIN_IN_ON_STOP = "com.android.internal.app.ChooserActivity.EXTRA_PRIVATE_RETAIN_IN_ON_STOP"; + /** + * Integer extra to indicate which profile should be automatically selected. + * <p>Can only be used if there is a work profile. + * <p>Possible values can be either {@link #PROFILE_PERSONAL} or {@link #PROFILE_WORK}. + */ + static final String EXTRA_SELECTED_PROFILE = + "com.android.internal.app.ChooserActivity.EXTRA_SELECTED_PROFILE"; + + static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL; + static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK; + private static final String PREF_NUM_SHEET_EXPANSIONS = "pref_num_sheet_expansions"; private static final String CHIP_LABEL_METADATA_KEY = "android.service.chooser.chip_label"; @@ -860,15 +871,31 @@ public class ChooserActivity extends ResolverActivity implements filterLastUsed, mUseLayoutForBrowsables, /* userHandle */ getWorkProfileUserHandle()); + int selectedProfile = findSelectedProfile(); return new ChooserMultiProfilePagerAdapter( /* context */ this, personalAdapter, workAdapter, - /* defaultProfile */ getCurrentProfile(), + selectedProfile, getPersonalProfileUserHandle(), getWorkProfileUserHandle()); } + private int findSelectedProfile() { + int selectedProfile; + if (getIntent().hasExtra(EXTRA_SELECTED_PROFILE)) { + selectedProfile = getIntent().getIntExtra(EXTRA_SELECTED_PROFILE, /* defValue = */ -1); + if (selectedProfile != PROFILE_PERSONAL && selectedProfile != PROFILE_WORK) { + throw new IllegalArgumentException(EXTRA_SELECTED_PROFILE + " has invalid value " + + selectedProfile + ". Must be either ChooserActivity.PROFILE_PERSONAL or " + + "ChooserActivity.PROFILE_WORK."); + } + } else { + selectedProfile = getProfileForUser(getUser()); + } + return selectedProfile; + } + @Override protected boolean postRebuildList(boolean rebuildCompleted) { updateStickyContentPreview(); @@ -2479,7 +2506,10 @@ public class ChooserActivity extends ResolverActivity implements gridAdapter.getMaxTargetsPerRow()); } - if (mChooserMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) { + UserHandle currentUserHandle = mChooserMultiProfilePagerAdapter.getCurrentUserHandle(); + int currentProfile = getProfileForUser(currentUserHandle); + int initialProfile = findSelectedProfile(); + if (currentProfile != initialProfile) { return; } @@ -2576,6 +2606,19 @@ public class ChooserActivity extends ResolverActivity implements } } + /** + * Returns {@link #PROFILE_PERSONAL}, {@link #PROFILE_WORK}, or -1 if the given user handle + * does not match either the personal or work user handle. + **/ + private int getProfileForUser(UserHandle currentUserHandle) { + if (currentUserHandle == getPersonalProfileUserHandle()) { + return PROFILE_PERSONAL; + } else if (currentUserHandle == getWorkProfileUserHandle()) { + return PROFILE_WORK; + } + return -1; + } + private ViewGroup getCurrentEmptyStateView() { int currentPage = mChooserMultiProfilePagerAdapter.getCurrentPage(); return mChooserMultiProfilePagerAdapter.getItem(currentPage).getEmptyStateView(); diff --git a/core/java/com/android/internal/app/ChooserActivityLogger.java b/core/java/com/android/internal/app/ChooserActivityLogger.java index 088973cde3e9..c26bac437915 100644 --- a/core/java/com/android/internal/app/ChooserActivityLogger.java +++ b/core/java/com/android/internal/app/ChooserActivityLogger.java @@ -182,7 +182,8 @@ public interface ChooserActivityLogger { return FrameworkStatsLog.SHARESHEET_STARTED__PREVIEW_TYPE__CONTENT_PREVIEW_FILE; case ChooserActivity.CONTENT_PREVIEW_TEXT: default: - return FrameworkStatsLog.SHARESHEET_STARTED__PREVIEW_TYPE__CONTENT_PREVIEW_TEXT; + return FrameworkStatsLog + .SHARESHEET_STARTED__PREVIEW_TYPE__CONTENT_PREVIEW_TYPE_UNKNOWN; } } diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index 9bdfa4ad4e43..36eecfb685e8 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -108,20 +108,16 @@ public class IntentForwarderActivity extends Activity { finish(); return; } + if (Intent.ACTION_CHOOSER.equals(intentReceived.getAction())) { + launchChooserActivityWithCorrectTab(intentReceived, className); + return; + } final int callingUserId = getUserId(); final Intent newIntent = canForward(intentReceived, getUserId(), targetUserId, mInjector.getIPackageManager(), getContentResolver()); if (newIntent != null) { - if (Intent.ACTION_CHOOSER.equals(newIntent.getAction())) { - Intent innerIntent = newIntent.getParcelableExtra(Intent.EXTRA_INTENT); - // At this point, innerIntent is not null. Otherwise, canForward would have returned - // false. - innerIntent.prepareToLeaveUser(callingUserId); - innerIntent.fixUris(callingUserId); - } else { - newIntent.prepareToLeaveUser(callingUserId); - } + newIntent.prepareToLeaveUser(callingUserId); final ResolveInfo ri = mInjector.resolveActivityAsUser(newIntent, MATCH_DEFAULT_ONLY, targetUserId); @@ -153,6 +149,33 @@ public class IntentForwarderActivity extends Activity { finish(); } + private void launchChooserActivityWithCorrectTab(Intent intentReceived, String className) { + // When showing the sharesheet, instead of forwarding to the other profile, + // we launch the sharesheet in the current user and select the other tab. + // This fixes b/152866292 where the user can not go back to the original profile + // when cross-profile intents are disabled. + int selectedProfile = findSelectedProfile(className); + sanitizeIntent(intentReceived); + intentReceived.putExtra(ChooserActivity.EXTRA_SELECTED_PROFILE, selectedProfile); + Intent innerIntent = intentReceived.getParcelableExtra(Intent.EXTRA_INTENT); + if (innerIntent == null) { + Slog.wtf(TAG, "Cannot start a chooser intent with no extra " + Intent.EXTRA_INTENT); + return; + } + sanitizeIntent(innerIntent); + startActivity(intentReceived); + finish(); + } + + private int findSelectedProfile(String className) { + if (className.equals(FORWARD_INTENT_TO_PARENT)) { + return ChooserActivity.PROFILE_PERSONAL; + } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) { + return ChooserActivity.PROFILE_WORK; + } + return -1; + } + private boolean shouldShowDisclosure(@Nullable ResolveInfo ri, Intent intent) { if (!isDeviceProvisioned()) { return false; diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 35253b68aac7..dd3a6603f46a 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -398,11 +398,6 @@ public class ResolverActivity extends Activity implements | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); rdl.setOnApplyWindowInsetsListener(this::onApplyWindowInsets); - if (shouldShowTabs() && isIntentPicker()) { - rdl.setMaxCollapsedHeight(getResources() - .getDimensionPixelSize(R.dimen.resolver_max_collapsed_height_with_tabs)); - } - mResolverDrawerLayout = rdl; } @@ -994,7 +989,7 @@ public class ResolverActivity extends Activity implements if (isAutolaunching() || maybeAutolaunchActivity()) { return; } - if (isResolverListEmpty(listAdapter)) { + if (mMultiProfilePagerAdapter.shouldShowEmptyStateScreen(listAdapter)) { mMultiProfilePagerAdapter.showEmptyResolverListEmptyState(listAdapter); } else { mMultiProfilePagerAdapter.showListView(listAdapter); @@ -1012,6 +1007,15 @@ public class ResolverActivity extends Activity implements protected void onListRebuilt(ResolverListAdapter listAdapter) { final ItemClickListener listener = new ItemClickListener(); setupAdapterListView((ListView) mMultiProfilePagerAdapter.getActiveAdapterView(), listener); + if (shouldShowTabs() && isIntentPicker()) { + final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel); + if (rdl != null) { + rdl.setMaxCollapsedHeight(getResources() + .getDimensionPixelSize(useLayoutWithDefault() + ? R.dimen.resolver_max_collapsed_height_with_default_with_tabs + : R.dimen.resolver_max_collapsed_height_with_tabs)); + } + } } protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) { @@ -1641,16 +1645,11 @@ public class ResolverActivity extends Activity implements private void setupViewVisibilities() { ResolverListAdapter activeListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter(); - if (!isResolverListEmpty(activeListAdapter)) { + if (!mMultiProfilePagerAdapter.shouldShowEmptyStateScreen(activeListAdapter)) { addUseDifferentAppLabelIfNecessary(activeListAdapter); } } - private boolean isResolverListEmpty(ResolverListAdapter listAdapter) { - int count = listAdapter.getUnfilteredCount(); - return count == 0 && listAdapter.getPlaceholderCount() == 0; - } - /** * Add a label to signify that the user can pick a different app. * @param adapter The adapter used to provide data to item views. diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java index 3f897a5f26bf..033ac72dda4e 100644 --- a/core/java/com/android/internal/app/ResolverListController.java +++ b/core/java/com/android/internal/app/ResolverListController.java @@ -121,23 +121,13 @@ public class ResolverListController { List<Intent> intents, UserHandle userHandle) { int baseFlags = PackageManager.MATCH_DEFAULT_ONLY + | PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0) | (shouldGetActivityMetadata ? PackageManager.GET_META_DATA : 0); return getResolversForIntentAsUserInternal(intents, userHandle, baseFlags); } - /** - * Returns a list of resolved intents which is user state-independent. This means it will - * return the same results regardless of whether the {@code userHandle} user is disabled or not. - */ - public List<ResolverActivity.ResolvedComponentInfo> getUserStateIndependentResolversAsUser( - List<Intent> intents, - UserHandle userHandle) { - int baseFlags = PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; - return getResolversForIntentAsUserInternal(intents, userHandle, baseFlags); - } - private List<ResolverActivity.ResolvedComponentInfo> getResolversForIntentAsUserInternal( List<Intent> intents, UserHandle userHandle, diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 04bf91567986..02cf25a7c3d2 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -26,7 +26,6 @@ import static android.system.OsConstants.S_IXGRP; import static android.system.OsConstants.S_IXOTH; import android.content.Context; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageLite; @@ -40,6 +39,7 @@ import android.os.incremental.IncrementalManager; import android.os.incremental.IncrementalStorage; import android.system.ErrnoException; import android.system.Os; +import android.util.ArraySet; import android.util.Slog; import dalvik.system.CloseGuard; @@ -545,4 +545,18 @@ public class NativeLibraryHelper { } return false; } + + /** + * Wait for all native library extraction to complete for the passed storages. + * + * @param incrementalStorages A list of the storages to wait for. + */ + public static void waitForNativeBinariesExtraction( + ArraySet<IncrementalStorage> incrementalStorages) { + for (int i = 0; i < incrementalStorages.size(); ++i) { + IncrementalStorage storage = incrementalStorages.valueAtUnchecked(i); + storage.waitForNativeBinariesExtraction(); + } + } + } diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index ff03f1a1a2ab..505a05eb9c23 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -205,9 +205,15 @@ public final class Zygote { /** List of packages with the same uid, and its app data info: volume uuid and inode. */ public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map"; + /** List of whitelisted packages and its app data info: volume uuid and inode. */ + public static final String WHITELISTED_DATA_INFO_MAP = "--whitelisted-data-info-map"; + /** Bind mount app storage dirs to lower fs not via fuse */ public static final String BIND_MOUNT_APP_STORAGE_DIRS = "--bind-mount-storage-dirs"; + /** Bind mount app storage dirs to lower fs not via fuse */ + public static final String BIND_MOUNT_APP_DATA_DIRS = "--bind-mount-data-dirs"; + /** * An extraArg passed when a zygote process is forking a child-zygote, specifying a name * in the abstract socket namespace. This socket name is what the new child zygote @@ -313,6 +319,8 @@ public final class Zygote { * @param isTopApp true if the process is for top (high priority) application. * @param pkgDataInfoList A list that stores related packages and its app data * info: volume uuid and inode. + * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for whitelisted apps. + * @param bindMountAppDataDirs True if the zygote needs to mount data dirs. * @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs. * * @return 0 if this is the child, pid of the child @@ -321,13 +329,15 @@ public final class Zygote { static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, - boolean isTopApp, String[] pkgDataInfoList, boolean bindMountAppStorageDirs) { + boolean isTopApp, String[] pkgDataInfoList, String[] whitelistedDataInfoList, + boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) { ZygoteHooks.preFork(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp, - pkgDataInfoList, bindMountAppStorageDirs); + pkgDataInfoList, whitelistedDataInfoList, bindMountAppDataDirs, + bindMountAppStorageDirs); if (pid == 0) { // Note that this event ends at the end of handleChildProc, Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); @@ -344,6 +354,7 @@ public final class Zygote { int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, + String[] whitelistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs); /** @@ -371,15 +382,19 @@ public final class Zygote { * volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name, * app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid, * app_b_ce_inode, ...]; + * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for whitelisted apps. + * @param bindMountAppDataDirs True if the zygote needs to mount data dirs. * @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs. */ private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, - String[] pkgDataInfoList, boolean bindMountAppStorageDirs) { + String[] pkgDataInfoList, String[] whitelistedDataInfoList, + boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) { nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, startChildZygote, instructionSet, appDataDir, isTopApp, - pkgDataInfoList, bindMountAppStorageDirs); + pkgDataInfoList, whitelistedDataInfoList, + bindMountAppDataDirs, bindMountAppStorageDirs); // Note that this event ends at the end of handleChildProc. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); @@ -399,7 +414,8 @@ public final class Zygote { private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, - String[] pkgDataInfoList, boolean bindMountAppStorageDirs); + String[] pkgDataInfoList, String[] whitelistedDataInfoList, + boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs); /** * Called to do any initialization before starting an application. @@ -724,7 +740,8 @@ public final class Zygote { args.mRuntimeFlags, rlimits, args.mMountExternal, args.mSeInfo, args.mNiceName, args.mStartChildZygote, args.mInstructionSet, args.mAppDataDir, args.mIsTopApp, - args.mPkgDataInfoList, args.mBindMountAppStorageDirs); + args.mPkgDataInfoList, args.mWhitelistedDataInfoList, + args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); @@ -1060,4 +1077,11 @@ public final class Zygote { */ @FastNative public static native int nativeParseSigChld(byte[] in, int length, int[] out); + + /** + * Returns whether the kernel supports tagged pointers. Present in the + * Android Common Kernel from 4.14 and up. By default, you should prefer + * fully-feature Memory Tagging, rather than the static Tagged Pointers. + */ + public static native boolean nativeSupportsTaggedPointers(); } diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java index 1a63765fcaa6..94c1f71a26db 100644 --- a/core/java/com/android/internal/os/ZygoteArguments.java +++ b/core/java/com/android/internal/os/ZygoteArguments.java @@ -227,11 +227,22 @@ class ZygoteArguments { String[] mPkgDataInfoList; /** + * A list that stores all whitelisted app data info: volume uuid and inode. + * Null if it does need to do app data isolation. + */ + String[] mWhitelistedDataInfoList; + + /** * @see Zygote#BIND_MOUNT_APP_STORAGE_DIRS */ boolean mBindMountAppStorageDirs; /** + * @see Zygote#BIND_MOUNT_APP_DATA_DIRS + */ + boolean mBindMountAppDataDirs; + + /** * Constructs instance and parses args * * @param args zygote command-line args @@ -452,8 +463,12 @@ class ZygoteArguments { } } else if (arg.startsWith(Zygote.PKG_DATA_INFO_MAP)) { mPkgDataInfoList = getAssignmentList(arg); + } else if (arg.startsWith(Zygote.WHITELISTED_DATA_INFO_MAP)) { + mWhitelistedDataInfoList = getAssignmentList(arg); } else if (arg.equals(Zygote.BIND_MOUNT_APP_STORAGE_DIRS)) { mBindMountAppStorageDirs = true; + } else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) { + mBindMountAppDataDirs = true; } else { break; } diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index bc8dfd4aa402..e6a3029c5b2b 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -258,7 +258,8 @@ class ZygoteConnection { parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote, parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp, - parsedArgs.mPkgDataInfoList, parsedArgs.mBindMountAppStorageDirs); + parsedArgs.mPkgDataInfoList, parsedArgs.mWhitelistedDataInfoList, + parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs); try { if (pid == 0) { diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index ec1f516df5f3..c2b13c971020 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -757,9 +757,11 @@ public class ZygoteInit { Zygote.applyDebuggerSystemProperty(parsedArgs); Zygote.applyInvokeWithSystemProperty(parsedArgs); - /* Enable pointer tagging in the system server unconditionally. Hardware support for - * this is present in all ARMv8 CPUs; this flag has no effect on other platforms. */ - parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI; + if (Zygote.nativeSupportsTaggedPointers()) { + /* Enable pointer tagging in the system server. Hardware support for this is present + * in all ARMv8 CPUs. */ + parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI; + } /* Enable gwp-asan on the system server with a small probability. This is the same * policy as applied to native processes and system apps. */ diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 71cf5cad316e..f5d38ca37bb7 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -68,7 +68,6 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.InsetDrawable; import android.graphics.drawable.LayerDrawable; -import android.os.Build.VERSION_CODES; import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; @@ -120,7 +119,6 @@ import com.android.internal.widget.DecorCaptionView; import com.android.internal.widget.FloatingToolbar; import java.util.List; -import java.util.function.Function; /** @hide */ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks { @@ -283,11 +281,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private Insets mLastBackgroundInsets = Insets.NONE; private boolean mDrawLegacyNavigationBarBackground; - /** - * Whether the app targets an SDK that uses the new insets APIs. - */ - private boolean mUseNewInsetsApi; - private PendingInsetsController mPendingInsetsController = new PendingInsetsController(); DecorView(Context context, int featureId, PhoneWindow window, @@ -319,7 +312,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind initResizingPaints(); mLegacyNavigationBarBackgroundPaint.setColor(Color.BLACK); - mUseNewInsetsApi = context.getApplicationInfo().targetSdkVersion >= VERSION_CODES.R; } void setBackgroundFallback(@Nullable Drawable fallbackDrawable) { @@ -1189,23 +1181,23 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind // these flags wouldn't make the window draw behind the navigation bar, unless // LAYOUT_HIDE_NAVIGATION was set. // - // Note: Once the app targets R+, we no longer do this logic because we can't rely on - // SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION to indicate whether the app wants to handle it by - // themselves. + // Note: Once the app uses the R+ Window.setDecorFitsSystemWindows(false) API we no longer + // consume insets because they might no longer set SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION. boolean hideNavigation = (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0 || !(controller == null || controller.isRequestedVisible(ITYPE_NAVIGATION_BAR)); + boolean decorFitsSystemWindows = mWindow.mDecorFitsSystemWindows; boolean forceConsumingNavBar = (mForceWindowDrawsBarBackgrounds && (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0 && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0 + && decorFitsSystemWindows && !hideNavigation) || (mLastShouldAlwaysConsumeSystemBars && hideNavigation); boolean consumingNavBar = ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0 - && !hideNavigation - // TODO IME wrap_content windows need to have margin to work properly - && (!mUseNewInsetsApi || isImeWindow)) + && decorFitsSystemWindows + && !hideNavigation) || forceConsumingNavBar; // If we didn't request fullscreen layout, but we still got it because of the @@ -1216,6 +1208,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind || (attrs.flags & FLAG_FULLSCREEN) != 0 || !(controller == null || controller.isRequestedVisible(ITYPE_STATUS_BAR)); boolean consumingStatusBar = (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == 0 + && decorFitsSystemWindows && (attrs.flags & FLAG_LAYOUT_IN_SCREEN) == 0 && (attrs.flags & FLAG_LAYOUT_INSET_DECOR) == 0 && mForceWindowDrawsBarBackgrounds @@ -1638,9 +1631,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind int opacity = PixelFormat.OPAQUE; final WindowConfiguration winConfig = getResources().getConfiguration().windowConfiguration; - // TODO(b/149585281) remove when root task has the correct bounds for freeform - final boolean renderShadowsInCompositor = mWindow.mRenderShadowsInCompositor - && winConfig.getWindowingMode() != WINDOWING_MODE_FREEFORM; + final boolean renderShadowsInCompositor = mWindow.mRenderShadowsInCompositor; // If we draw shadows in the compositor we don't need to force the surface to be // translucent. if (winConfig.hasWindowShadow() && !renderShadowsInCompositor) { @@ -2434,8 +2425,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private void updateElevation() { final int windowingMode = getResources().getConfiguration().windowConfiguration.getWindowingMode(); - final boolean renderShadowsInCompositor = mWindow.mRenderShadowsInCompositor - && windowingMode != WINDOWING_MODE_FREEFORM; + final boolean renderShadowsInCompositor = mWindow.mRenderShadowsInCompositor; // If rendering shadows in the compositor, don't set an elevation on the view if (renderShadowsInCompositor) { return; diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 138d0dd39537..25c114f4b7c1 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -343,8 +343,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { /** @see ViewRootImpl#mActivityConfigCallback */ private ActivityConfigCallback mActivityConfigCallback; - private OnContentApplyWindowInsetsListener mPendingOnContentApplyWindowInsetsListener = - sDefaultContentInsetsApplier; + boolean mDecorFitsSystemWindows = true; static class WindowManagerHolder { static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface( @@ -2138,9 +2137,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { /** Notify when decor view is attached to window and {@link ViewRootImpl} is available. */ void onViewRootImplSet(ViewRootImpl viewRoot) { viewRoot.setActivityConfigCallback(mActivityConfigCallback); - viewRoot.setOnContentApplyWindowInsetsListener( - mPendingOnContentApplyWindowInsetsListener); - mPendingOnContentApplyWindowInsetsListener = null; + applyDecorFitsSystemWindows(); } static private final String FOCUSED_ID_TAG = "android:focusedViewId"; @@ -3907,14 +3904,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void setDecorFitsSystemWindows(boolean decorFitsSystemWindows) { + mDecorFitsSystemWindows = decorFitsSystemWindows; + applyDecorFitsSystemWindows(); + } + + private void applyDecorFitsSystemWindows() { ViewRootImpl impl = getViewRootImplOrNull(); - OnContentApplyWindowInsetsListener listener = decorFitsSystemWindows - ? sDefaultContentInsetsApplier - : null; if (impl != null) { - impl.setOnContentApplyWindowInsetsListener(listener); - } else { - mPendingOnContentApplyWindowInsetsListener = listener; + impl.setOnContentApplyWindowInsetsListener(mDecorFitsSystemWindows + ? sDefaultContentInsetsApplier + : null); } } } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 1dbd69c67831..24fe0638b091 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -77,7 +77,7 @@ interface IStatusBarService void onNotificationSmartReplySent(in String key, in int replyIndex, in CharSequence reply, in int notificationLocation, boolean modifiedBeforeSending); void onNotificationSettingsViewed(String key); - void onNotificationBubbleChanged(String key, boolean isBubble); + void onNotificationBubbleChanged(String key, boolean isBubble, int flags); void onBubbleNotificationSuppressionChanged(String key, boolean isSuppressed); void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName); void clearInlineReplyUriPermissions(String key); diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java index 3c9791791a68..9168438dc2bf 100644 --- a/core/java/com/android/internal/util/FunctionalUtils.java +++ b/core/java/com/android/internal/util/FunctionalUtils.java @@ -16,6 +16,7 @@ package com.android.internal.util; +import android.annotation.NonNull; import android.os.RemoteException; import android.util.ExceptionUtils; @@ -218,4 +219,37 @@ public class FunctionalUtils { } } } + + // TODO: add unit test + /** + * Gets a user-friendly name for a lambda function. + */ + @NonNull + public static String getLambdaName(@NonNull Object function) { + // Full function has one of the following formats: + // package-$$Lambda$class$randomId + // package-$$Lambda$randomId + // + // We just want just package.class$Lambda (or package$Lambda) respectively + + final String fullFunction = function.toString(); + + final int endPkgIdx = fullFunction.indexOf("-$$"); + if (endPkgIdx == -1) return fullFunction; + + // firstDollarIdx could be either beginning of class or beginning of the random id + final int firstDollarIdx = fullFunction.indexOf('$', endPkgIdx + 3); + if (firstDollarIdx == -1) return fullFunction; + + final int endClassIdx = fullFunction.indexOf('$', firstDollarIdx + 1); + if (endClassIdx == -1) { + // Just package + return fullFunction.substring(0, endPkgIdx - 1) + "$Lambda"; + } + + // Package + class + return fullFunction.substring(0, endPkgIdx) + + fullFunction.substring(firstDollarIdx + 1, endClassIdx) + + "$Lambda"; + } } diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java index e4a44084e91c..1646a07b8001 100755 --- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java +++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java @@ -16,7 +16,6 @@ package com.android.internal.util.function.pooled; -import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Message; import android.text.TextUtils; @@ -25,6 +24,7 @@ import android.util.Pools; import com.android.internal.util.ArrayUtils; import com.android.internal.util.BitUtils; +import com.android.internal.util.FunctionalUtils; import com.android.internal.util.function.DecConsumer; import com.android.internal.util.function.DecFunction; import com.android.internal.util.function.DecPredicate; @@ -580,36 +580,6 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, return r; } - // TODO: add unit test - @NonNull - private static String getFriendlyName(@NonNull Object function) { - // Full function has one of the following formats: - // package-$$Lambda$class$randomId - // package-$$Lambda$randomId - // - // We just want just package.class$Lambda (or package$Lambda) respectively - - final String fullFunction = function.toString(); - - final int endPkgIdx = fullFunction.indexOf("-$$"); - if (endPkgIdx == -1) return fullFunction; - - // firstDollarIdx could be either beginning of class or beginning of the random id - final int firstDollarIdx = fullFunction.indexOf('$', endPkgIdx + 3); - if (firstDollarIdx == -1) return fullFunction; - - final int endClassIdx = fullFunction.indexOf('$', firstDollarIdx + 1); - if (endClassIdx == -1) { - // Just package - return fullFunction.substring(0, endPkgIdx - 1) + "$Lambda"; - } - - // Package + class - return fullFunction.substring(0, endPkgIdx) - + fullFunction.substring(firstDollarIdx + 1, endClassIdx) - + "$Lambda"; - } - private static void setIfInBounds(Object[] array, int i, Object a) { if (i < ArrayUtils.size(array)) array[i] = a; } @@ -651,7 +621,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, @Override public String getTraceName() { - return getFriendlyName(mFunc); + return FunctionalUtils.getLambdaName(mFunc); } private boolean isRecycled() { diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index 5a979ac97c54..26684201019c 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -40,7 +40,6 @@ import android.os.Bundle; import android.os.Parcelable; import android.text.TextUtils; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.Gravity; @@ -387,14 +386,17 @@ public class ConversationLayout extends FrameLayout /** @hide */ public void setUnreadCount(int unreadCount) { - mUnreadBadge.setVisibility(mIsCollapsed && unreadCount > 1 ? VISIBLE : GONE); - CharSequence text = unreadCount >= 100 - ? getResources().getString(R.string.unread_convo_overflow, 99) - : String.format(Locale.getDefault(), "%d", unreadCount); - mUnreadBadge.setText(text); - mUnreadBadge.setBackgroundTintList(ColorStateList.valueOf(mLayoutColor)); - boolean needDarkText = ColorUtils.calculateLuminance(mLayoutColor) > 0.5f; - mUnreadBadge.setTextColor(needDarkText ? Color.BLACK : Color.WHITE); + boolean visible = mIsCollapsed && unreadCount > 1; + mUnreadBadge.setVisibility(visible ? VISIBLE : GONE); + if (visible) { + CharSequence text = unreadCount >= 100 + ? getResources().getString(R.string.unread_convo_overflow, 99) + : String.format(Locale.getDefault(), "%d", unreadCount); + mUnreadBadge.setText(text); + mUnreadBadge.setBackgroundTintList(ColorStateList.valueOf(mLayoutColor)); + boolean needDarkText = ColorUtils.calculateLuminance(mLayoutColor) > 0.5f; + mUnreadBadge.setTextColor(needDarkText ? Color.BLACK : Color.WHITE); + } } private void addRemoteInputHistoryToMessages( @@ -537,37 +539,26 @@ public class ConversationLayout extends FrameLayout } private void updateImageMessages() { - boolean displayExternalImage = false; - ArraySet<View> newMessages = new ArraySet<>(); - if (mIsCollapsed) { - - // When collapsed, we're displaying all image messages in a dedicated container - // on the right of the layout instead of inline. Let's add all isolated images there - int imageIndex = 0; - for (int i = 0; i < mGroups.size(); i++) { - MessagingGroup messagingGroup = mGroups.get(i); - MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage(); - if (isolatedMessage != null) { - newMessages.add(isolatedMessage.getView()); - displayExternalImage = true; - if (imageIndex - != mImageMessageContainer.indexOfChild(isolatedMessage.getView())) { - mImageMessageContainer.removeView(isolatedMessage.getView()); - mImageMessageContainer.addView(isolatedMessage.getView(), imageIndex); - } - imageIndex++; - } + View newMessage = null; + if (mIsCollapsed && mGroups.size() > 0) { + + // When collapsed, we're displaying the image message in a dedicated container + // on the right of the layout instead of inline. Let's add the isolated image there + MessagingGroup messagingGroup = mGroups.get(mGroups.size() -1); + MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage(); + if (isolatedMessage != null) { + newMessage = isolatedMessage.getView(); } } // Remove all messages that don't belong into the image layout - for (int i = 0; i < mImageMessageContainer.getChildCount(); i++) { - View child = mImageMessageContainer.getChildAt(i); - if (!newMessages.contains(child)) { - mImageMessageContainer.removeView(child); - i--; + View previousMessage = mImageMessageContainer.getChildAt(0); + if (previousMessage != newMessage) { + mImageMessageContainer.removeView(previousMessage); + if (newMessage != null) { + mImageMessageContainer.addView(newMessage); } } - mImageMessageContainer.setVisibility(displayExternalImage ? VISIBLE : GONE); + mImageMessageContainer.setVisibility(newMessage != null ? VISIBLE : GONE); } private void bindFacePile() { diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index bf3fc5704739..12abc256a20e 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -481,6 +481,11 @@ static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/ return sparse_array; } +static jboolean ContainsAllocatedTable(JNIEnv* env, jclass /*clazz*/, jlong ptr) { + ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); + return assetmanager->ContainsAllocatedTable(); +} + static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) { ScopedUtfChars path_utf8(env, path); if (path_utf8.c_str() == nullptr) { @@ -1495,6 +1500,7 @@ static const JNINativeMethod gAssetManagerMethods[] = { (void*)NativeGetAssignedPackageIdentifiers}, // AssetManager file methods. + {"nativeContainsAllocatedTable", "(J)Z", (void*)ContainsAllocatedTable}, {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList}, {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset}, {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;", diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index b2ca0a7bcbe3..58697875b2c3 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -29,11 +29,13 @@ #include <android_runtime/AndroidRuntime.h> #include <android_runtime/android_view_Surface.h> #include <android_runtime/android_view_SurfaceSession.h> +#include <gui/ISurfaceComposer.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <jni.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedUtfChars.h> +#include <private/gui/ComposerService.h> #include <stdio.h> #include <system/graphics.h> #include <ui/ConfigStoreTypes.h> @@ -624,6 +626,23 @@ static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, transaction->setFrameRate(ctrl, frameRate, static_cast<int8_t>(compatibility)); } +static jlong nativeAcquireFrameRateFlexibilityToken(JNIEnv* env, jclass clazz) { + sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<IBinder> token; + status_t result = composer->acquireFrameRateFlexibilityToken(&token); + if (result < 0) { + ALOGE("Failed acquiring frame rate flexibility token: %s (%d)", strerror(-result), result); + return 0; + } + token->incStrong((void*)nativeAcquireFrameRateFlexibilityToken); + return reinterpret_cast<jlong>(token.get()); +} + +static void nativeReleaseFrameRateFlexibilityToken(JNIEnv* env, jclass clazz, jlong tokenLong) { + sp<IBinder> token(reinterpret_cast<IBinder*>(tokenLong)); + token->decStrong((void*)nativeAcquireFrameRateFlexibilityToken); +} + static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) { const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds(); jlongArray array = env->NewLongArray(displayIds.size()); @@ -829,8 +848,18 @@ static jobject convertDeviceProductInfoToJavaObject( LOG_FATAL("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate"); } + jintArray relativeAddress = nullptr; + if (info->relativeAddress != DeviceProductInfo::NO_RELATIVE_ADDRESS) { + relativeAddress = env->NewIntArray(info->relativeAddress.size()); + jint* relativeAddressData = env->GetIntArrayElements(relativeAddress, nullptr); + for (size_t i = 0; i < info->relativeAddress.size(); i++) { + relativeAddressData[i] = static_cast<jint>(info->relativeAddress[i]); + } + env->ReleaseIntArrayElements(relativeAddress, relativeAddressData, 0); + } return env->NewObject(gDeviceProductInfoClassInfo.clazz, gDeviceProductInfoClassInfo.ctor, name, - manufacturerPnpId, productId, modelYear, manufactureDate); + manufacturerPnpId, productId, modelYear, manufactureDate, + relativeAddress); } static jobject nativeGetDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) { @@ -1411,6 +1440,12 @@ static void nativeSetGlobalShadowSettings(JNIEnv* env, jclass clazz, jfloatArray client->setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, lightRadius); } + +static jlong nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) { + SurfaceControl *surfaceControl = reinterpret_cast<SurfaceControl*>(nativeObject); + return reinterpret_cast<jlong>(surfaceControl->getHandle().get()); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod sSurfaceControlMethods[] = { @@ -1474,6 +1509,10 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetShadowRadius }, {"nativeSetFrameRate", "(JJFI)V", (void*)nativeSetFrameRate }, + {"nativeAcquireFrameRateFlexibilityToken", "()J", + (void*)nativeAcquireFrameRateFlexibilityToken }, + {"nativeReleaseFrameRateFlexibilityToken", "(J)V", + (void*)nativeReleaseFrameRateFlexibilityToken }, {"nativeGetPhysicalDisplayIds", "()[J", (void*)nativeGetPhysicalDisplayIds }, {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;", @@ -1583,6 +1622,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeMirrorSurface }, {"nativeSetGlobalShadowSettings", "([F[FFFF)V", (void*)nativeSetGlobalShadowSettings }, + {"nativeGetHandle", "(J)J", + (void*)nativeGetHandle }, }; int register_android_view_SurfaceControl(JNIEnv* env) @@ -1653,7 +1694,8 @@ int register_android_view_SurfaceControl(JNIEnv* env) "Ljava/lang/String;" "Ljava/lang/String;" "Ljava/lang/Integer;" - "Landroid/hardware/display/DeviceProductInfo$ManufactureDate;)V"); + "Landroid/hardware/display/DeviceProductInfo$ManufactureDate;" + "[I)V"); jclass deviceProductInfoManufactureDateClazz = FindClassOrDie(env, "android/hardware/display/DeviceProductInfo$ManufactureDate"); diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index ea3c0fa9fc3c..924dc4b3a051 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -110,7 +110,6 @@ using android::base::StringAppendF; using android::base::StringPrintf; using android::base::WriteStringToFile; using android::base::GetBoolProperty; -using android::base::GetProperty; #define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \ append(StringPrintf(__VA_ARGS__)) @@ -170,18 +169,6 @@ static int gSystemServerSocketFd = -1; static constexpr int DEFAULT_DATA_DIR_PERMISSION = 0751; -/** - * Property to control if app data isolation is enabled. - */ -static const std::string ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY = - "persist.zygote.app_data_isolation"; - -/** - * Property to enable app data isolation for sdcard obb or data in vold. - */ -static const std::string ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY = - "persist.sys.vold_app_data_isolation_enabled"; - static constexpr const uint64_t UPPER_HALF_WORD_MASK = 0xFFFF'FFFF'0000'0000; static constexpr const uint64_t LOWER_HALF_WORD_MASK = 0x0000'0000'FFFF'FFFF; @@ -1319,20 +1306,13 @@ static void relabelAllDirs(const char* path, security_context_t context, fail_fn * be decrypted after storage is decrypted. * */ -static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list, - uid_t uid, const char* process_name, jstring managed_nice_name, - fail_fn_t fail_fn) { +static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_data_info_list, + uid_t uid, const char* process_name, + jstring managed_nice_name, fail_fn_t fail_fn) { const userid_t userId = multiuser_get_user_id(uid); - auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); - - int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0; - // Size should be a multiple of 3, as it contains list of <package_name, volume_uuid, inode> - if ((size % 3) != 0) { - fail_fn(CREATE_ERROR("Wrong pkg_inode_list size %d", size)); - } - ensureInAppMountNamespace(fail_fn); + int size = merged_data_info_list.size(); // Mount tmpfs on all possible data directories, so app no longer see the original apps data. char internalCePath[PATH_MAX]; @@ -1377,14 +1357,10 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list, bool legacySymlinkCreated = false; for (int i = 0; i < size; i += 3) { - jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i)); - std::string packageName = extract_fn(package_str).value(); + std::string const & packageName = merged_data_info_list[i]; + std::string const & volUuid = merged_data_info_list[i + 1]; + std::string const & inode = merged_data_info_list[i + 2]; - jstring vol_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i + 1)); - std::string volUuid = extract_fn(vol_str).value(); - - jstring inode_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i + 2)); - std::string inode = extract_fn(inode_str).value(); std::string::size_type sz; long long ceDataInode = std::stoll(inode, &sz); @@ -1482,6 +1458,48 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list, freecon(dataDataContext); } +static void insertPackagesToMergedList(JNIEnv* env, + std::vector<std::string>& merged_data_info_list, + jobjectArray data_info_list, const char* process_name, + jstring managed_nice_name, fail_fn_t fail_fn) { + + auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); + + int size = (data_info_list != nullptr) ? env->GetArrayLength(data_info_list) : 0; + // Size should be a multiple of 3, as it contains list of <package_name, volume_uuid, inode> + if ((size % 3) != 0) { + fail_fn(CREATE_ERROR("Wrong data_info_list size %d", size)); + } + + for (int i = 0; i < size; i += 3) { + jstring package_str = (jstring) (env->GetObjectArrayElement(data_info_list, i)); + std::string packageName = extract_fn(package_str).value(); + merged_data_info_list.push_back(packageName); + + jstring vol_str = (jstring) (env->GetObjectArrayElement(data_info_list, i + 1)); + std::string volUuid = extract_fn(vol_str).value(); + merged_data_info_list.push_back(volUuid); + + jstring inode_str = (jstring) (env->GetObjectArrayElement(data_info_list, i + 2)); + std::string inode = extract_fn(inode_str).value(); + merged_data_info_list.push_back(inode); + } +} + +static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list, + jobjectArray whitelisted_data_info_list, uid_t uid, const char* process_name, + jstring managed_nice_name, fail_fn_t fail_fn) { + + ensureInAppMountNamespace(fail_fn); + std::vector<std::string> merged_data_info_list; + insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list, + process_name, managed_nice_name, fail_fn); + insertPackagesToMergedList(env, merged_data_info_list, whitelisted_data_info_list, + process_name, managed_nice_name, fail_fn); + + isolateAppData(env, merged_data_info_list, uid, process_name, managed_nice_name, fail_fn); +} + /** * Like isolateAppData(), isolate jit profile directories, so apps don't see what * other apps are installed by reading content inside /data/misc/profiles/cur. @@ -1594,7 +1612,9 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jstring managed_nice_name, bool is_system_server, bool is_child_zygote, jstring managed_instruction_set, jstring managed_app_data_dir, bool is_top_app, - jobjectArray pkg_data_info_list, bool mount_storage_dirs) { + jobjectArray pkg_data_info_list, + jobjectArray whitelisted_data_info_list, + bool mount_data_dirs, bool mount_storage_dirs) { const char* process_name = is_system_server ? "system_server" : "zygote"; auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1); auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); @@ -1628,12 +1648,14 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, // give a null in same_uid_pkgs and private_volumes so they don't need app data isolation. // Isolated process / webview / app zygote should be gated by SELinux and file permission // so they can't even traverse CE / DE directories. - if (pkg_data_info_list != nullptr - && GetBoolProperty(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true)) { - isolateAppData(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); + if (mount_data_dirs) { + isolateAppData(env, pkg_data_info_list, whitelisted_data_info_list, + uid, process_name, managed_nice_name, fail_fn); isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); } - if ((mount_external != MOUNT_EXTERNAL_INSTALLER) && mount_storage_dirs) { + if (mount_external != MOUNT_EXTERNAL_INSTALLER && + mount_external != MOUNT_EXTERNAL_PASS_THROUGH && + mount_storage_dirs) { BindMountStorageDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); } @@ -2003,7 +2025,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( jint mount_external, jstring se_info, jstring nice_name, jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, - jobjectArray pkg_data_info_list, jboolean mount_storage_dirs) { + jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, + jboolean mount_data_dirs, jboolean mount_storage_dirs) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); if (UNLIKELY(managed_fds_to_close == nullptr)) { @@ -2041,6 +2064,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list, + whitelisted_data_info_list, + mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE); } return pid; @@ -2076,7 +2101,8 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( permitted_capabilities, effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, false, nullptr, nullptr, /* is_top_app= */ false, - /* pkg_data_info_list */ nullptr, false); + /* pkg_data_info_list */ nullptr, + /* whitelisted_data_info_list */ nullptr, false, false); } else if (pid > 0) { // The zygote process checks whether the child process has died or not. ALOGI("System server process %d has been created", pid); @@ -2206,15 +2232,16 @@ static void com_android_internal_os_Zygote_nativeSpecializeAppProcess( jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, - jobjectArray pkg_data_info_list, jboolean mount_storage_dirs) { + jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, + jboolean mount_data_dirs, jboolean mount_storage_dirs) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, - is_top_app == JNI_TRUE, pkg_data_info_list, - mount_storage_dirs == JNI_TRUE); + is_top_app == JNI_TRUE, pkg_data_info_list, whitelisted_data_info_list, + mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE); } /** @@ -2405,10 +2432,19 @@ static jint com_android_internal_os_Zygote_nativeParseSigChld(JNIEnv* env, jclas return -1; } +static jboolean com_android_internal_os_Zygote_nativeSupportsTaggedPointers(JNIEnv* env, jclass) { +#ifdef __aarch64__ + int res = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0); + return res >= 0 && res & PR_TAGGED_ADDR_ENABLE; +#else + return false; +#endif +} + static const JNINativeMethod gMethods[] = { {"nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/" - "String;Z[Ljava/lang/String;Z)I", + "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)I", (void*)com_android_internal_os_Zygote_nativeForkAndSpecialize}, {"nativeForkSystemServer", "(II[II[[IJJ)I", (void*)com_android_internal_os_Zygote_nativeForkSystemServer}, @@ -2421,7 +2457,7 @@ static const JNINativeMethod gMethods[] = { {"nativeForkUsap", "(II[IZ)I", (void*)com_android_internal_os_Zygote_nativeForkUsap}, {"nativeSpecializeAppProcess", "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/" - "String;Z[Ljava/lang/String;Z)V", + "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V", (void*)com_android_internal_os_Zygote_nativeSpecializeAppProcess}, {"nativeInitNativeState", "(Z)V", (void*)com_android_internal_os_Zygote_nativeInitNativeState}, @@ -2440,6 +2476,8 @@ static const JNINativeMethod gMethods[] = { (void*)com_android_internal_os_Zygote_nativeBoostUsapPriority}, {"nativeParseSigChld", "([BI[I)I", (void*)com_android_internal_os_Zygote_nativeParseSigChld}, + {"nativeSupportsTaggedPointers", "()Z", + (void*)com_android_internal_os_Zygote_nativeSupportsTaggedPointers}, }; int register_com_android_internal_os_Zygote(JNIEnv* env) { diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 6321651c1345..3e007e4704a4 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -2674,4 +2674,14 @@ enum PageId { // CATEGORY: SETTINGS // OS: R FUELGAUGE_ADVANCED_BATTERY_OPTION = 1842; + + // OPEN: Settings > System > Gestures > Power menu + // CATEGORY: SETTINGS + // OS: R + POWER_MENU_SETTINGS = 1843; + + // OPEN: Settings > System > Gestures > Power menu > Device controls + // CATEGORY: SETTINGS + // OS: R + DEVICE_CONTROLS_SETTINGS = 1844; } diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index bd1bae6d83fb..b678d627d48c 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -523,6 +523,7 @@ message StateControllerProto { optional bool is_idle = 1; optional bool is_screen_on = 2; optional bool is_dock_idle = 3; + optional bool in_car_mode = 4; } oneof active_tracker { diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto index 684a29249294..896ee4fa42a5 100644 --- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto +++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto @@ -186,4 +186,15 @@ enum EventId { RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK= 159; RESOLVER_EMPTY_STATE_NO_APPS_RESOLVED= 160; RESOLVER_AUTOLAUNCH_CROSS_PROFILE_TARGET = 161; + CROSS_PROFILE_SETTINGS_PAGE_LAUNCHED_FROM_APP = 162; + CROSS_PROFILE_SETTINGS_PAGE_LAUNCHED_FROM_SETTINGS = 163; + CROSS_PROFILE_SETTINGS_PAGE_ADMIN_RESTRICTED = 164; + CROSS_PROFILE_SETTINGS_PAGE_MISSING_WORK_APP = 165; + CROSS_PROFILE_SETTINGS_PAGE_MISSING_PERSONAL_APP = 166; + CROSS_PROFILE_SETTINGS_PAGE_MISSING_INSTALL_BANNER_INTENT = 167; + CROSS_PROFILE_SETTINGS_PAGE_INSTALL_BANNER_CLICKED = 168; + CROSS_PROFILE_SETTINGS_PAGE_INSTALL_BANNER_NO_INTENT_CLICKED = 169; + CROSS_PROFILE_SETTINGS_PAGE_USER_CONSENTED = 170; + CROSS_PROFILE_SETTINGS_PAGE_USER_DECLINED_CONSENT = 171; + CROSS_PROFILE_SETTINGS_PAGE_PERMISSION_REVOKED = 172; } diff --git a/core/proto/android/stats/dnsresolver/dns_resolver.proto b/core/proto/android/stats/dnsresolver/dns_resolver.proto index 76f8f0febf59..61b9b25fe7cf 100644 --- a/core/proto/android/stats/dnsresolver/dns_resolver.proto +++ b/core/proto/android/stats/dnsresolver/dns_resolver.proto @@ -62,6 +62,13 @@ enum NsRcode { NS_R_NOTAUTH = 9; // Not authoritative for zone NS_R_NOTZONE = 10; // Zone of record different from zone section NS_R_MAX = 11; + // Define rcode=12~15(UNASSIGNED) in rcode enum type. + // Some DNS Servers might return undefined code to devices. + // Without the enum definition, that would be noise for our dashboard. + NS_R_UNASSIGNED12 = 12; // Unassigned + NS_R_UNASSIGNED13 = 13; // Unassigned + NS_R_UNASSIGNED14 = 14; // Unassigned + NS_R_UNASSIGNED15 = 15; // Unassigned // The following are EDNS extended rcodes NS_R_BADVERS = 16; // The following are TSIG errors @@ -170,12 +177,22 @@ enum NetworkType { NT_BLUETOOTH = 3; // Indicates this network uses an Ethernet transport. NT_ETHERNET = 4; - // Indicates this network uses a VPN transport. - NT_VPN = 5; + // Indicates this network uses a VPN transport, now deprecated. + NT_VPN = 5 [deprecated=true]; // Indicates this network uses a Wi-Fi Aware transport. NT_WIFI_AWARE = 6; // Indicates this network uses a LoWPAN transport. NT_LOWPAN = 7; + // Indicates this network uses a Cellular+VPN transport. + NT_CELLULAR_VPN = 8; + // Indicates this network uses a Wi-Fi+VPN transport. + NT_WIFI_VPN = 9; + // Indicates this network uses a Bluetooth+VPN transport. + NT_BLUETOOTH_VPN = 10; + // Indicates this network uses an Ethernet+VPN transport. + NT_ETHERNET_VPN = 11; + // Indicates this network uses a Wi-Fi+Cellular+VPN transport. + NT_WIFI_CELLULAR_VPN = 12; } enum CacheStatus{ diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 451363f6bd3d..5d6fc766676b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -351,8 +351,9 @@ <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_ALLOWED_APP" /> <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_DISALLOWED_APP" /> <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_DISMISSED" /> - <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_ALLOWED_CARRIER" /> - <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_DISALLOWED_CARRIER" /> + <protected-broadcast android:name="com.android.server.wifi.action.CarrierNetwork.USER_ALLOWED_CARRIER" /> + <protected-broadcast android:name="com.android.server.wifi.action.CarrierNetwork.USER_DISALLOWED_CARRIER" /> + <protected-broadcast android:name="com.android.server.wifi.action.CarrierNetwork.USER_DISMISSED" /> <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION" /> <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK" /> <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK" /> @@ -1098,9 +1099,9 @@ android:description="@string/permgroupdesc_phone" android:priority="500" /> - <!-- Allows read only access to phone state, including the phone number of the device, - current cellular network information, the status of any ongoing calls, and a list of any - {@link android.telecom.PhoneAccount}s registered on the device. + <!-- Allows read only access to phone state, including the current cellular network information, + the status of any ongoing calls, and a list of any {@link android.telecom.PhoneAccount}s + registered on the device. <p class="note"><strong>Note:</strong> If <em>both</em> your <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> and <a @@ -4122,7 +4123,10 @@ set of pages referenced over time. <p>Declaring the permission implies intention to use the API and the user of the device can grant permission through the Settings application. - <p>Protection level: signature|privileged|appop --> + <p>Protection level: signature|privileged|appop + <p>A data loader has to be the one which provides data to install an app. + <p>A data loader has to have both permission:LOADER_USAGE_STATS AND + appop:LOADER_USAGE_STATS allowed to be able to access the read logs. --> <permission android:name="android.permission.LOADER_USAGE_STATS" android:protectionLevel="signature|privileged|appop" /> <uses-permission android:name="android.permission.LOADER_USAGE_STATS" /> @@ -5056,7 +5060,7 @@ <category android:name="android.intent.category.VOICE" /> </intent-filter> </activity> - <activity android:name="com.android.internal.app.AccessibilityButtonChooserActivity" + <activity android:name="com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity" android:exported="false" android:theme="@style/Theme.DeviceDefault.Dialog.Alert.DayNight" android:finishOnCloseSystemDialogs="true" @@ -5454,6 +5458,13 @@ </intent-filter> </service> + <provider + android:name="com.android.server.textclassifier.IconsContentProvider" + android:authorities="com.android.textclassifier.icons" + android:enabled="true" + android:exported="true"> + </provider> + </application> </manifest> diff --git a/core/res/res/layout/accessibility_button_chooser_item.xml b/core/res/res/layout/accessibility_shortcut_chooser_item.xml index b7dd892fd161..fff22d916b15 100644 --- a/core/res/res/layout/accessibility_button_chooser_item.xml +++ b/core/res/res/layout/accessibility_shortcut_chooser_item.xml @@ -24,7 +24,7 @@ android:padding="16dp"> <CheckBox - android:id="@+id/accessibility_button_target_checkbox" + android:id="@+id/accessibility_shortcut_target_checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingStart="16dp" @@ -34,13 +34,13 @@ android:visibility="gone"/> <ImageView - android:id="@+id/accessibility_button_target_icon" + android:id="@+id/accessibility_shortcut_target_icon" android:layout_width="48dp" android:layout_height="48dp" android:scaleType="fitCenter"/> <TextView - android:id="@+id/accessibility_button_target_label" + android:id="@+id/accessibility_shortcut_target_label" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" @@ -50,7 +50,7 @@ android:fontFamily="sans-serif-medium"/> <Switch - android:id="@+id/accessibility_button_target_switch_item" + android:id="@+id/accessibility_shortcut_target_switch_item" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null" diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml index 425801991927..ec54091e5a20 100644 --- a/core/res/res/layout/notification_material_action_list.xml +++ b/core/res/res/layout/notification_material_action_list.xml @@ -20,16 +20,34 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/notification_action_list_margin_top" android:layout_gravity="bottom"> - <com.android.internal.widget.NotificationActionListLayout - android:id="@+id/actions" + + <LinearLayout android:layout_width="match_parent" - android:layout_height="@dimen/notification_action_list_height" - android:paddingEnd="12dp" + android:layout_height="wrap_content" android:orientation="horizontal" - android:gravity="center_vertical" - android:visibility="gone" - android:background="@color/notification_action_list_background_color" + android:paddingEnd="12dp" > - <!-- actions will be added here --> - </com.android.internal.widget.NotificationActionListLayout> + + <com.android.internal.widget.NotificationActionListLayout + android:id="@+id/actions" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="@dimen/notification_action_list_height" + android:orientation="horizontal" + android:gravity="center_vertical" + android:visibility="gone" + android:background="@color/notification_action_list_background_color" + > + <!-- actions will be added here --> + </com.android.internal.widget.NotificationActionListLayout> + + <ImageView + android:id="@+id/bubble_button" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_gravity="center_vertical|end" + android:visibility="gone" + android:scaleType="centerInside" + /> + </LinearLayout> </FrameLayout> diff --git a/core/res/res/layout/resolver_empty_states.xml b/core/res/res/layout/resolver_empty_states.xml index c7e1a21aa642..5890bed11b07 100644 --- a/core/res/res/layout/resolver_empty_states.xml +++ b/core/res/res/layout/resolver_empty_states.xml @@ -19,61 +19,66 @@ android:id="@+id/resolver_empty_state" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" android:gravity="center_horizontal" android:visibility="gone" - android:paddingTop="48dp" android:paddingStart="24dp" android:paddingEnd="24dp"> - <ImageView - android:id="@+id/resolver_empty_state_icon" - android:layout_width="24dp" - android:layout_height="24dp" - android:layout_centerHorizontal="true" /> - <TextView - android:id="@+id/resolver_empty_state_title" - android:layout_below="@+id/resolver_empty_state_icon" - android:layout_marginTop="8dp" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:fontFamily="@string/config_headlineFontFamilyMedium" - android:textColor="@color/resolver_empty_state_text" - android:textSize="14sp" - android:layout_centerHorizontal="true" /> - <TextView - android:id="@+id/resolver_empty_state_subtitle" - android:layout_below="@+id/resolver_empty_state_title" - android:layout_marginTop="4dp" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textColor="@color/resolver_empty_state_text" - android:textSize="12sp" - android:gravity="center_horizontal" - android:layout_centerHorizontal="true" /> - <Button - android:id="@+id/resolver_empty_state_button" - android:layout_below="@+id/resolver_empty_state_subtitle" - android:layout_marginTop="16dp" - android:text="@string/resolver_switch_on_work" - android:layout_width="wrap_content" + <RelativeLayout + android:layout_width="match_parent" android:layout_height="wrap_content" - android:fontFamily="@string/config_headlineFontFamilyMedium" - android:textSize="14sp" - android:textColor="?attr/colorAccent" - android:layout_centerHorizontal="true" - android:background="@drawable/resolver_turn_on_work_button_ripple_background"/> - <ProgressBar - android:id="@+id/resolver_empty_state_progress" - style="@style/Widget.Material.Light.ProgressBar" - android:visibility="gone" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:indeterminate="true" - android:layout_alignTop="@+id/resolver_empty_state_icon" - android:layout_alignBottom="@+id/resolver_empty_state_button" - android:layout_centerHorizontal="true" - android:layout_below="@+id/resolver_empty_state_subtitle" - android:indeterminateTint="?attr/colorAccent"/> + android:paddingTop="48dp" + android:paddingBottom="48dp" + android:gravity="center_horizontal"> + <ImageView + android:id="@+id/resolver_empty_state_icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_centerHorizontal="true" /> + <TextView + android:id="@+id/resolver_empty_state_title" + android:layout_below="@+id/resolver_empty_state_icon" + android:layout_marginTop="8dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:fontFamily="@string/config_headlineFontFamilyMedium" + android:textColor="@color/resolver_empty_state_text" + android:textSize="14sp" + android:layout_centerHorizontal="true" /> + <TextView + android:id="@+id/resolver_empty_state_subtitle" + android:layout_below="@+id/resolver_empty_state_title" + android:layout_marginTop="4dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="@color/resolver_empty_state_text" + android:textSize="12sp" + android:gravity="center_horizontal" + android:layout_centerHorizontal="true" /> + <Button + android:id="@+id/resolver_empty_state_button" + android:layout_below="@+id/resolver_empty_state_subtitle" + android:layout_marginTop="16dp" + android:text="@string/resolver_switch_on_work" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:fontFamily="@string/config_headlineFontFamilyMedium" + android:textSize="14sp" + android:textColor="?attr/colorAccent" + android:layout_centerHorizontal="true" + android:background="@drawable/resolver_turn_on_work_button_ripple_background"/> + <ProgressBar + android:id="@+id/resolver_empty_state_progress" + style="@style/Widget.Material.Light.ProgressBar" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:indeterminate="true" + android:layout_alignTop="@+id/resolver_empty_state_icon" + android:layout_alignBottom="@+id/resolver_empty_state_button" + android:layout_centerHorizontal="true" + android:layout_below="@+id/resolver_empty_state_subtitle" + android:indeterminateTint="?attr/colorAccent"/> + </RelativeLayout> <TextView android:id="@+id/empty" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml index 06a7633ce3f5..4a5aa020fb9f 100644 --- a/core/res/res/layout/resolver_list_with_default.xml +++ b/core/res/res/layout/resolver_list_with_default.xml @@ -21,7 +21,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:maxWidth="@dimen/resolver_max_width" - android:maxCollapsedHeight="144dp" + android:maxCollapsedHeight="@dimen/resolver_max_collapsed_height_with_default" android:id="@id/contentPanel"> <LinearLayout diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 37fd9652e894..cafa7e8e3af9 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB አድስ ተያይዟል"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"የዩኤስቢ ማረሚያን ለማጥፋት መታ ያድርጉ"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ማረሚያ ላለማንቃት ምረጥ።"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ገመድ-አልባ ማረም ተገናኝቷል"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ገመድ-አልባ ማረምን ለማጥፋት ይምረጡ"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ገመድ-አልባ ማረምን ለማሰናከል ይምረጡ።"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ገመድ-አልባ debugging ተገናኝቷል"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ገመድ-አልባ debuggingን ለማጥፋት ይምረጡ"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ገመድ-አልባ debuggingን ለማሰናከል ይምረጡ።"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"የሙከራ ጥቅል ሁነታ ነቅቷል"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"የመሞከሪያ ጥቅል ሁነታን ለማሰናከል የፋብሪካ ዳግም ቅንብርን ይሞክሩ።"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"ተከታታይ ኮንሶል ነቅቷል"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 4715823b6482..1ed36a80ca52 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -554,7 +554,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"لم يتم التعرف عليها."</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"تم إلغاء المصادقة."</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"لم يتم ضبط رقم تعريف شخصي أو نقش أو كلمة مرور."</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"تم اكتشاف بصمة الإصبع بشكل جزئي؛ يرجى إعادة المحاولة."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"تم اكتشاف جزء من بصمة الإصبع فقط؛ يرجى إعادة المحاولة."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"تعذرت معالجة بصمة الإصبع. يُرجى إعادة المحاولة."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"زر استشعار بصمات الأصابع متّسخ. يُرجى تنظيفه وإعادة المحاولة."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"لقد حرّكت إصبعك بسرعة، يُرجى إعادة المحاولة."</string> @@ -1389,9 +1389,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"تم توصيل أداة تصحيح أخطاء الجهاز عبر USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"انقر لإيقاف تصحيح أخطاء الجهاز عبر USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"اختيار إيقاف تصحيح أخطاء USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"تم تفعيل ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\""</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"انقر لإيقاف ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\"."</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"اختيار إيقاف ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\""</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"تم تفعيل ميزة \"تصحيح الأخطاء اللاسلكي\"."</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"انقر لإيقاف ميزة \"تصحيح الأخطاء اللاسلكي\"."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"اختيار إيقاف ميزة \"تصحيح الأخطاء اللاسلكي\""</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"تم تفعيل وضع \"مفعّل الاختبار\""</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"يمكنك إجراء إعادة ضبط على الإعدادات الأصلية لإيقاف وضع \"مفعِّل اختبار\"."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"وحدة التحكّم التسلسلية مفعّلة"</string> @@ -2180,8 +2180,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"محادثة"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"محادثة جماعية"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"شخصي"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"عمل"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"عرض المحتوى الشخصي"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index c0e070bf27bf..dae98671aa84 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"ইউএছবি ডিবাগিং সংযোগ কৰা হ’ল"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"ইউএছবি ডিবাগিং বন্ধ কৰিবলৈ টিপক"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"ইউএছবি ডিবাগিং অক্ষম কৰিবলৈ বাছনি কৰক।"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ৱায়াৰলেছ ডিবাগিং সংযোগ কৰা হৈছে"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ৱায়াৰলেছ ডিবাগিং অফ কৰিবলৈ টিপক"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ৱায়াৰলেছ ডিবাগিং অক্ষম কৰিবলৈ বাছনি কৰক।"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ৱায়াৰলেচ ডি\'বাগিং সংযোগ কৰা হৈছে"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ৱায়াৰলেচ ডি\'বাগিং অফ কৰিবলৈ টিপক"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ৱায়াৰলেচ ডি\'বাগিং অক্ষম কৰিবলৈ বাছনি কৰক।"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"টেষ্ট হাৰনেছ ম’ড সক্ষম কৰা আছে"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"টেষ্ট হাৰনেছ ম’ড অক্ষম কৰিবলৈ ফেক্টৰী ৰিছেট কৰক।"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"ক্ৰমিক কনছ’ল সক্ষম কৰা আছে"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"বাৰ্তালাপ"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"গোটত কৰা বাৰ্তালাপ"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"কৰ্মস্থান"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ব্যক্তিগত ভিউ"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index ec6960660b54..462ca3ad7130 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB sazlama qoşuludur"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB sazlamanı deaktiv etmək üçün klikləyin"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USb debaqı deaktivasiya etməyi seçin."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Simsiz sazlama qoşulub"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Simsiz sazlamanı deaktiv etmək üçün toxunun"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Simsiz sazlamanı deaktiv etmək üçün seçin."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"WiFi sazlaması qoşulub"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"WiFi sazlamasını deaktiv etmək üçün toxunun"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"WiFi sazlamasını deaktiv etmək üçün seçin."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test Rejimi aktivdir"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Test Rejimini deaktiv etmək üçün fabrika ayarlarına sıfırlayın."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Ardıcıl konsol aktiv edildi"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Söhbət"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Qrup Söhbəti"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Şəxsi"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Şəxsi məzmuna baxış"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 0636ea960572..84545894e794 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -701,7 +701,7 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"Zahteva da sačuvani podaci aplikacije budu šifrovani."</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"Onemogućavanje kamera"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Sprečite korišćenje svih kamera uređaja."</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Onemogućava funkcije zaključavanja ekrana"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Onemogućavanje funkcija zaklj. ekrana"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Sprečava korišćenje nekih funkcija zaključavanja ekrana."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Kuća"</item> @@ -2078,8 +2078,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konverzacija"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupna konverzacija"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Lični"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Poslovni"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Lični prikaz"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 133df6c00109..9d3ca537ff04 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -1349,9 +1349,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Адладка па USB падключана"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Націсніце, каб выключыць адладку па USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Выберыце, каб адключыць адладку USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Бесправадная адладка падключана"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Націсніце, каб выключыць бесправадную адладку"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Выберыце, каб адключыць бесправадную адладку."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Адладка па Wi-Fi уключана"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Націсніце, каб выключыць адладку па Wi-Fi"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Выберыце, каб выключыць адладку па Wi-Fi."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Тэставы рэжым уключаны"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Каб выключыць тэставы рэжым, скіньце налады да заводскіх значэнняў."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Паслядоўная кансоль уключана"</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Размова"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групавая размова"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Асабістыя"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Працоўныя"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Прагляд асабістага змесціва"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 468b8256c689..ff0838dede37 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Разговор"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групов разговор"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"Над <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Служебни"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Личен изглед"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index a8cc98620260..4090e21544b2 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -545,7 +545,7 @@ <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"আঙ্গুলের ছাপ আংশিক শনাক্ত করা হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"আঙ্গুলের ছাপ প্রক্রিয়া করা যায়নি৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"আঙ্গুলের ছাপ নেওয়ার সেন্সরটি অপরিস্কার৷ অনুগ্রহ করে পরিষ্কার করে আবার চেষ্টা করুন৷"</string> - <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"আঙ্গুল অতি দ্রুত সরানো হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> + <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"আঙ্গুল অতি দ্রুত সরানো হয়েছে৷ আবার চেষ্টা করুন৷"</string> <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"আঙ্গুল খুব ধীরে সরানো হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> <string-array name="fingerprint_acquired_vendor"> </string-array> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"কথোপকথন"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"গ্রুপ কথোপকথন"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"অফিস"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ব্যক্তিগত ভিউ"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index a6aa753cdee0..bd05452c771b 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -513,7 +513,7 @@ <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"Omogućava aplikaciji uspostavljanje i prekidanje veze tableta sa WiMAX mrežama."</string> <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Omogućava aplikaciji da se poveže s vašim Android TV uređajem i prekine povezanost Android TV uređaja s WiMAX mrežama."</string> <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Omogućava aplikaciji uspostavljanje i prekidanje veze telefona sa WiMAX mrežama."</string> - <string name="permlab_bluetooth" msgid="586333280736937209">"uparivanje sa Bluetooth uređajima"</string> + <string name="permlab_bluetooth" msgid="586333280736937209">"uparivanje s Bluetooth uređajima"</string> <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Omogućava aplikaciji prikaz konfiguracije za Bluetooth na tabletu, kao i uspostavljanje i prihvatanje veza sa uparenim uređajima."</string> <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Omogućava aplikaciji da prikaže konfiguraciju Bluetootha na Android TV uređaju te uspostavi i prihvati vezu s uparenim uređajima."</string> <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Omogućava aplikaciji prikaz konfiguracije za Bluetooth na telefonu, kao i uspostavljanje i prihvatanje veza sa uparenim uređajima."</string> @@ -545,7 +545,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"Nije prepoznato"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikacija je otkazana"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nije postavljen PIN, uzorak niti lozinka"</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Otkriven je djelomičan otisak prsta. Pokušajte ponovo."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Otkriven je djelomični otisak prsta. Pokušajte ponovo."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Obrada otiska prsta nije uspjela. Pokušajte ponovo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzor za otisak prsta je prljav. Očistite ga i pokušajte ponovo."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Prst je uklonjen prebrzo. Pokušajte ponovo."</string> @@ -702,7 +702,7 @@ <string name="policylab_disableCamera" msgid="5749486347810162018">"Isključuje kamere"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Sprečava korištenje svih kamera uređaja."</string> <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Onemog. neke funk. zak. ekrana"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Spriječava korištenje nekih funkcija za zaključavanje ekrana."</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Sprečava korištenje nekih funkcija za zaključavanje ekrana."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Kuća"</item> <item msgid="7740243458912727194">"Mobilni"</item> @@ -1205,7 +1205,7 @@ <string name="unsupported_display_size_show" msgid="980129850974919375">"Uvijek prikaži"</string> <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je napravljena za verziju operativnog sistema Android koja nije kompatibilna i može se ponašati neočekivano. Ažurirana verzija aplikacije može biti dostupna."</string> <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Uvijek prikaži"</string> - <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Provjeri ima li ažuriranja"</string> + <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Provjeri je li dostupno ažuriranje"</string> <string name="smv_application" msgid="3775183542777792638">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastita StrictMode pravila."</string> <string name="smv_process" msgid="1398801497130695446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> prekršio je vlastita StrictMode pravila."</string> <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Ažuriranje telefona…"</string> @@ -1531,7 +1531,7 @@ <string name="storage_usb_drive_label" msgid="6631740655876540521">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string> <string name="storage_usb" msgid="2391213347883616886">"USB pohrana"</string> <string name="extract_edit_menu_button" msgid="63954536535863040">"Uredi"</string> - <string name="data_usage_warning_title" msgid="9034893717078325845">"Upozorenje o potrošnji podataka"</string> + <string name="data_usage_warning_title" msgid="9034893717078325845">"Upozorenje o prijenosu podataka"</string> <string name="data_usage_warning_body" msgid="1669325367188029454">"Potrošili ste <xliff:g id="APP">%s</xliff:g> podataka"</string> <string name="data_usage_mobile_limit_title" msgid="3911447354393775241">"Dostignuto ograničenje za prijenos podataka"</string> <string name="data_usage_wifi_limit_title" msgid="2069698056520812232">"Dostignut limit WiFi podataka"</string> @@ -2080,8 +2080,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Razgovor"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupni razgovor"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Lično"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Prikaz ličnog sadržaja"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index b3cb436fff63..a0e404a9e28a 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1349,8 +1349,8 @@ <string name="ext_media_unmountable_notification_message" product="tv" msgid="3003611129979934633">"La unitat següent està malmesa: <xliff:g id="NAME">%s</xliff:g>. Selecciona-la per solucionar-ho."</string> <string name="ext_media_unmountable_notification_message" product="automotive" msgid="5622514265490819212"></string> <string name="ext_media_unsupported_notification_title" msgid="4358280700537030333">"<xliff:g id="NAME">%s</xliff:g> no és compatible"</string> - <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"El dispositiu no admet la unitat <xliff:g id="NAME">%s</xliff:g>. Toca per configurar-la amb un format compatible."</string> - <string name="ext_media_unsupported_notification_message" product="tv" msgid="7744945987775645685">"Aquest dispositiu no admet la unitat següent: <xliff:g id="NAME">%s</xliff:g>. Selecciona-la per configurar-la en un format compatible."</string> + <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"El dispositiu no admet <xliff:g id="NAME">%s</xliff:g>. Toca per configurar-la en un format compatible."</string> + <string name="ext_media_unsupported_notification_message" product="tv" msgid="7744945987775645685">"Aquest dispositiu no admet <xliff:g id="NAME">%s</xliff:g>. Selecciona-la per configurar-la en un format compatible."</string> <string name="ext_media_unsupported_notification_message" product="automotive" msgid="7657357085538772913">"El dispositiu no admet <xliff:g id="NAME">%s</xliff:g>."</string> <string name="ext_media_badremoval_notification_title" msgid="4114625551266196872">"S\'ha extret <xliff:g id="NAME">%s</xliff:g> de manera inesperada"</string> <string name="ext_media_badremoval_notification_message" msgid="1986514704499809244">"Expulsa el suport extern abans d\'extreure\'l per evitar perdre\'n el contingut"</string> @@ -1592,7 +1592,7 @@ <string name="kg_invalid_sim_pin_hint" msgid="4821601451222564077">"Escriu un PIN que tingui de 4 a 8 números."</string> <string name="kg_invalid_sim_puk_hint" msgid="2539364558870734339">"El codi PUK ha de tenir 8 números."</string> <string name="kg_invalid_puk" msgid="4809502818518963344">"Torna a introduir el codi PUK correcte. Els intents repetits faran que es desactivi la SIM permanentment."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"Els codis PIN no coincideixen"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"Els PIN no coincideixen"</string> <string name="kg_login_too_many_attempts" msgid="699292728290654121">"Massa intents incorrectes"</string> <string name="kg_login_instructions" msgid="3619844310339066827">"Per desbloquejar el telèfon, inicia la sessió amb el compte de Google."</string> <string name="kg_login_username_hint" msgid="1765453775467133251">"Nom d\'usuari (correu electrònic)"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa de grup"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Feina"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Visualització personal"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 36adc52ec8f7..f56b8b5d5bd7 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1835,8 +1835,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizováno administrátorem"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Smazáno administrátorem"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Hej Google“\n\n"<annotation id="url">"Další informace"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Hej Google“"</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Ok Google“\n\n"<annotation id="url">"Další informace"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Ok Google“"</string> <string name="data_saver_description" msgid="4995164271550590517">"Spořič dat z důvodu snížení využití dat některým aplikacím brání v odesílání nebo příjmu dat na pozadí. Aplikace, kterou právě používáte, data přenášet může, ale může tak činit méně často. V důsledku toho se například obrázky nemusejí zobrazit, dokud na ně neklepnete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnout Spořič dat?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnout"</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konverzace"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Skupinová konverzace"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobní"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Pracovní"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Osobní zobrazení"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 6d8a2b4d21ff..6e9098b4c3e4 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Samtale"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppesamtale"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Arbejde"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Visningen Personligt"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 3de322e16ff1..bfb7b4d50512 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -542,7 +542,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"Nicht erkannt"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Authentifizierung abgebrochen"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Keine PIN, kein Muster und kein Passwort festgelegt"</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Fingerabdruck teilweise erkannt. Bitte versuche es noch einmal."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Fingerabdruck nur teilweise erkannt. Bitte versuche es noch einmal."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Fingerabdruck konnte nicht verarbeitet werden. Bitte versuche es noch einmal."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerabdrucksensor ist verschmutzt. Reinige ihn und versuche es noch einmal."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Du hast deinen Finger zu schnell bewegt. Bitte versuche es noch einmal."</string> @@ -679,7 +679,7 @@ <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Es wird überwacht, wie oft beim Versuch, den Bildschirm zu entsperren, ein falsches Passwort eingegeben wird. Wenn es zu viele Fehlversuche gibt, wird das Android TV-Gerät gesperrt oder alle Daten dieses Nutzers werden gelöscht."</string> <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Displays überwachen und Smartphone sperren oder alle Daten dieses Nutzers löschen, wenn zu häufig ein falsches Passwort eingegeben wird"</string> <string name="policylab_resetPassword" msgid="214556238645096520">"Displaysperre ändern"</string> - <string name="policydesc_resetPassword" msgid="4626419138439341851">"Displaysperre ändern"</string> + <string name="policydesc_resetPassword" msgid="4626419138439341851">"Ändern der Displaysperre"</string> <string name="policylab_forceLock" msgid="7360335502968476434">"Bildschirm sperren"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"Festlegen, wie und wann der Bildschirm gesperrt wird"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"Alle Daten löschen"</string> @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-Debugging aktiviert"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Zum Deaktivieren von USB-Debugging tippen"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB-Debugging deaktivieren: auswählen"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Kabelloses Debugging verbunden"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tippen, um kabelloses Debugging zu deaktivieren"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Auswählen, um kabelloses Debugging zu deaktivieren."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"\"Debugging über WLAN\" verbunden"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tippen, um \"Debugging über WLAN\" zu deaktivieren"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Auswählen, um \"Debugging über WLAN\" zu deaktivieren."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test-Harnischmodus aktiviert"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Setz das Gerät auf die Werkseinstellungen zurück, um den Test-Harnischmodus zu deaktivieren."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serielle Konsole aktiviert"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Unterhaltung"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppenunterhaltung"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Geschäftlich"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Private Ansicht"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 57b02f44954a..5fdbe9ed2a61 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Απενεργοποιήστε τον εντοπισμό/διόρθ. σφαλμάτων USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Συνδέθηκε ο εντοπισμός σφαλμάτων μέσω ασύρματης σύνδεσης"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Πατήστε, για να απενεργοποιήσετε τον εντοπισμό σφαλμάτων μέσω ασύρματης σύνδεσης"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Επιλέξτε, για να απενεργοποιήσετε τον εντοπισμό σφαλμάτων μέσω ασύρματης σύνδεσης."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Συνδέθηκε ο ασύρματος εντοπισμός σφαλμάτων"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Πατήστε, για να απενεργοποιήσετε τον ασύρματο εντοπισμό σφαλμάτων"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Επιλέξτε, για να απενεργοποιήσετε τον ασύρματο εντοπισμό σφαλμάτων."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Η λειτουργία περιβάλλοντος δοκιμών ενεργοποιήθηκε"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Εκτελέστε επαναφορά εργοστασιακών ρυθμίσεων για να απενεργοποιήσετε τη λειτουργία περιβάλλοντος δοκιμών."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Η σειριακή κονσόλα ενεργοποιήθηκε"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Συνομιλία"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Ομαδική συνομιλία"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Προσωπικό"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Εργασία"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Προσωπική προβολή"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 366d19db16b8..cf58937aa9ca 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -542,7 +542,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"No se reconoció"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Se canceló la autenticación"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No se estableció ningún PIN, patrón ni contraseña"</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"La huella digital se detectó parcialmente. Vuelve a intentarlo."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Se detectó parcialmente la huella digital. Vuelve a intentarlo."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No se pudo procesar la huella digital. Vuelve a intentarlo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"El sensor de huellas digitales está sucio. Limpia el sensor y vuelve a intentarlo."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Moviste el dedo muy rápido. Vuelve a intentarlo."</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 197a47cd20ac..b57b6929cdc9 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -310,7 +310,7 @@ <string name="permgrouplab_camera" msgid="9090413408963547706">"Cámara"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"hacer fotos y grabar vídeos"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"Registros de llamadas"</string> - <string name="permgroupdesc_calllog" msgid="2026996642917801803">"leer y editar el registro de llamadas del teléfono"</string> + <string name="permgroupdesc_calllog" msgid="2026996642917801803">"leer y escribir en el registro de llamadas del teléfono"</string> <string name="permgrouplab_phone" msgid="570318944091926620">"Teléfono"</string> <string name="permgroupdesc_phone" msgid="270048070781478204">"hacer y administrar llamadas telefónicas"</string> <string name="permgrouplab_sensors" msgid="9134046949784064495">"Sensores corporales"</string> @@ -698,7 +698,7 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"Exige que se cifren los datos de la aplicación almacenados."</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"Inhabilitar cámaras"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Evita el uso de las cámaras del dispositivo"</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Inhabilitar algunas funciones del bloqueo de pantalla"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Desactivar algunas funciones del bloqueo de pantalla"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Evitar el uso de algunas funciones del bloqueo de pantalla"</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Casa"</item> @@ -1262,7 +1262,7 @@ <string name="decline" msgid="6490507610282145874">"Rechazar"</string> <string name="select_character" msgid="3352797107930786979">"Insertar carácter"</string> <string name="sms_control_title" msgid="4748684259903148341">"Enviando mensajes SMS..."</string> - <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> está enviando un gran número de mensajes SMS. ¿Quieres permitir que está aplicación siga enviando mensajes?"</string> + <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> está enviando un gran número de mensajes SMS. ¿Permitir que está aplicación siga enviando mensajes?"</string> <string name="sms_control_yes" msgid="4858845109269524622">"Permitir"</string> <string name="sms_control_no" msgid="4845717880040355570">"Denegar"</string> <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> quiere enviar un mensaje a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string> @@ -1307,7 +1307,7 @@ <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Se ha detectado un accesorio de audio analógico"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"El dispositivo adjunto no es compatible con este teléfono. Toca para obtener más información."</string> <string name="adb_active_notification_title" msgid="408390247354560331">"Depuración USB habilitada"</string> - <string name="adb_active_notification_message" msgid="5617264033476778211">"Tocar para desactivar depuración USB"</string> + <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca aquí para desactivar la depuración USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para inhabilitar la depuración USB"</string> <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuración inalámbrica conectada"</string> <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca para desactivar la depuración inalámbrica"</string> @@ -1327,7 +1327,7 @@ <string name="share_remote_bugreport_action" msgid="7630880678785123682">"COMPARTIR"</string> <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"RECHAZAR"</string> <string name="select_input_method" msgid="3971267998568587025">"Selecciona un método de entrada"</string> - <string name="show_ime" msgid="6406112007347443383">"Mantener en la pantalla mientras el teclado físico está activo"</string> + <string name="show_ime" msgid="6406112007347443383">"Lo mantiene en pantalla mientras el teclado físico está activo"</string> <string name="hardware" msgid="1800597768237606953">"Mostrar teclado virtual"</string> <string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"Configura el teclado físico"</string> <string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Toca para seleccionar el idioma y el diseño"</string> @@ -1628,7 +1628,7 @@ <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Al mantener pulsadas ambas teclas de volumen durante unos segundos se activa <xliff:g id="SERVICE">%1$s</xliff:g>, una función de accesibilidad. Esta función puede modificar el funcionamiento del dispositivo.\n\nPuedes asignar este acceso directo a otra función en Ajustes > Accesibilidad."</string> <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activar"</string> <string name="accessibility_shortcut_off" msgid="3651336255403648739">"No activar"</string> - <string name="accessibility_enable_service_title" msgid="3931558336268541484">"¿Quieres permitir que <xliff:g id="SERVICE">%1$s</xliff:g> pueda controlar totalmente tu dispositivo?"</string> + <string name="accessibility_enable_service_title" msgid="3931558336268541484">"¿Permitir que <xliff:g id="SERVICE">%1$s</xliff:g> pueda controlar totalmente tu dispositivo?"</string> <string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"Si activas <xliff:g id="SERVICE">%1$s</xliff:g>, el dispositivo no utilizará el bloqueo de pantalla para mejorar el cifrado de datos."</string> <string name="accessibility_service_warning_description" msgid="291674995220940133">"El control total es adecuado para las aplicaciones de accesibilidad, pero no para la mayoría de las aplicaciones."</string> <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Ver y controlar la pantalla"</string> @@ -1789,9 +1789,9 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado por el administrador"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado por el administrador"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Para que la batería dure más, Ahorro de batería:\n· Activa el tema oscuro\n· Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\"\n\n"<annotation id="url">"Más información"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Para que la batería dure más, Ahorro de batería:\n· Activa el tema oscuro\n· Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\""</string> - <string name="data_saver_description" msgid="4995164271550590517">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se mostrarán hasta que las toques."</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Para que la batería dure más, el modo Ahorro de batería:\n· Activa el tema oscuro\n· Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\"\n\n"<annotation id="url">"Más información"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Para que la batería dure más, el modo Ahorro de batería:\n· Activa el tema oscuro\n· Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\""</string> + <string name="data_saver_description" msgid="4995164271550590517">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"¿Activar ahorro de datos?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string> <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273"> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversación"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversación de grupo"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"+ <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabajo"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Ver contenido personal"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 2e9ea38e7aa2..070fd79f65a3 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -563,7 +563,7 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ühtegi sõrmejälge pole registreeritud."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Selles seadmes pole sõrmejäljeandurit."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Andur on ajutiselt keelatud."</string> - <string name="fingerprint_name_template" msgid="8941662088160289778">"Sõrm <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_name_template" msgid="8941662088160289778">"Sõrmejälg <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sõrmejälje ikoon"</string> @@ -679,7 +679,7 @@ <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Jälgitakse ekraanikuva avamisel sisestatud valede paroolide arvu ja lukustatakse Android TV seade või kustutatakse kõik selle kasutaja andmed, kui vale parool sisestatakse liiga palju kordi."</string> <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Jälgitakse ekraani avamisel sisestatud valede paroolide arvu ja lukustatakse telefon või kustutatakse kõik selle kasutaja andmed, kui vale parool sisestatakse liiga palju kordi."</string> <string name="policylab_resetPassword" msgid="214556238645096520">"Ekraaniluku muutmine"</string> - <string name="policydesc_resetPassword" msgid="4626419138439341851">"Muudetakse ekraanilukku."</string> + <string name="policydesc_resetPassword" msgid="4626419138439341851">"Muutke ekraanilukku."</string> <string name="policylab_forceLock" msgid="7360335502968476434">"Ekraani lukustamine"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"Määrake, kuidas ja millal ekraan lukustub."</string> <string name="policylab_wipeData" msgid="1359485247727537311">"Kõikide andmete kustutamine"</string> @@ -1789,8 +1789,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Administraator on seda värskendanud"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administraator on selle kustutanud"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja akusäästja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja akusäästja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid."</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid."</string> <string name="data_saver_description" msgid="4995164271550590517">"Andmekasutuse vähendamiseks keelab andmemahu säästja mõne rakenduse puhul andmete taustal saatmise ja vastuvõtmise. Rakendus, mida praegu kasutate, pääseb andmesidele juurde, kuid võib seda teha väiksema sagedusega. Seetõttu võidakse näiteks pildid kuvada alles siis, kui neid puudutate."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Lül. andmemahu säästja sisse?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Lülita sisse"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Vestlus"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupivestlus"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Isiklik"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Töö"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Isiklik vaade"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 9af4b68a071a..c5922e1d5972 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -571,7 +571,7 @@ <string name="permdesc_manageFace" msgid="6204569688492710471">"Aurpegi-txantiloiak gehitu eta ezabatzeko metodoei dei egitea baimentzen dio aplikazioari."</string> <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"erabili aurpegiaren bidez desblokeatzeko hardwarea"</string> <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Autentifikazioa egiteko aurpegiaren bidez desblokeatzeko hardwarea erabiltzeko baimena ematen dio aplikazioari"</string> - <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Aurpegiaren bidez desblokeatzeko aukera"</string> + <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Aurpegiaren bidez desblokeatzeko eginbidea"</string> <string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Erregistratu aurpegia berriro"</string> <string name="face_recalibrate_notification_content" msgid="892757485125249962">"Ezagutzea hobetzeko, erregistratu aurpegia berriro"</string> <string name="face_acquired_insufficient" msgid="2150805835949162453">"Ezin izan dira bildu argazkiaren datu zehatzak. Saiatu berriro."</string> @@ -602,9 +602,9 @@ <string name="face_error_canceled" msgid="2164434737103802131">"Utzi da aurpegiaren bidezko eragiketa."</string> <string name="face_error_user_canceled" msgid="8553045452825849843">"Erabiltzaileak bertan behera utzi du aurpegiaren bidez desblokeatzea."</string> <string name="face_error_lockout" msgid="7864408714994529437">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string> - <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Saiakera gehiegi egin dira. Aurpegiaren bidez desblokeatzeko aukera desgaitu egin da."</string> + <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Saiakera gehiegi egin dira. Aurpegiaren bidez desblokeatzeko eginbidea desgaitu egin da."</string> <string name="face_error_unable_to_process" msgid="5723292697366130070">"Ezin da egiaztatu aurpegia. Saiatu berriro."</string> - <string name="face_error_not_enrolled" msgid="7369928733504691611">"Ez duzu konfiguratu aurpegiaren bidez desblokeatzeko aukera."</string> + <string name="face_error_not_enrolled" msgid="7369928733504691611">"Ez duzu konfiguratu aurpegiaren bidez desblokeatzeko eginbidea."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Gailu honek ez du onartzen aurpegiaren bidez desblokeatzea."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sentsorea aldi baterako desgaitu da."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> aurpegia"</string> @@ -905,7 +905,7 @@ <string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Zabaldu desblokeatzeko eremua."</string> <string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Hatza lerratuta desblokeatzea."</string> <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Ereduaren bidez desblokeatzea."</string> - <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Aurpegiaren bidez desblokeatzeko aukera."</string> + <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Aurpegiaren bidez desblokeatzeko eginbidea."</string> <string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN kodearen bidez desblokeatzea."</string> <string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM txartela desblokeatzeko PIN kodea."</string> <string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM txartela desblokeatzeko PUK kodea."</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Elkarrizketa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Taldeko elkarrizketa"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Pertsonala"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Lanekoa"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Ikuspegi pertsonala"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index b62d8b02cbe3..315f7ea459b2 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1307,7 +1307,7 @@ <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Analoginen äänilaite havaittu"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Liitetty laite ei ole yhteensopiva puhelimen kanssa. Napauta, niin näet lisätietoja."</string> <string name="adb_active_notification_title" msgid="408390247354560331">"USB-vianetsintä yhdistetty"</string> - <string name="adb_active_notification_message" msgid="5617264033476778211">"Poista USB-virheenkorjaus käytöstä napauttamalla."</string> + <string name="adb_active_notification_message" msgid="5617264033476778211">"Poista USB-virheenkorjaus käytöstä napauttamalla"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Poista USB-vianetsintä käytöstä valitsemalla tämä."</string> <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Langaton virheenkorjaus yhdistetty"</string> <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Poista langaton virheenkorjaus käytöstä napauttamalla"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Keskustelu"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Ryhmäkeskustelu"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Henkilökohtainen"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Työ"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Henkilökohtainen näkymä"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 84c1c18151b6..6198d0ecb30c 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversation"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversation de groupe"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Bureau"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Affichage personnel"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 1de01a3d738d..3708d3a9ca6e 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -310,7 +310,7 @@ <string name="permgrouplab_camera" msgid="9090413408963547706">"Appareil photo"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"prendre des photos et enregistrer des vidéos"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"Journaux d\'appels"</string> - <string name="permgroupdesc_calllog" msgid="2026996642917801803">"Lire et écrire les journaux d\'appels du téléphone"</string> + <string name="permgroupdesc_calllog" msgid="2026996642917801803">"Consulter et modifier les journaux d\'appels du téléphone"</string> <string name="permgrouplab_phone" msgid="570318944091926620">"Téléphone"</string> <string name="permgroupdesc_phone" msgid="270048070781478204">"effectuer et gérer des appels téléphoniques"</string> <string name="permgrouplab_sensors" msgid="9134046949784064495">"Capteurs corporels"</string> @@ -681,7 +681,7 @@ <string name="policylab_resetPassword" msgid="214556238645096520">"Modifier le verrouillage de l\'écran"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"Modifier le verrouillage de l\'écran"</string> <string name="policylab_forceLock" msgid="7360335502968476434">"Verrouiller l\'écran"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"Gérer le mode et les conditions de verrouillage de l\'écran"</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"Gérer la méthode et les conditions de verrouillage de l\'écran"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"Effacer toutes les données"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Effacer les données de la tablette sans avertissement, en rétablissant la configuration d\'usine"</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Efface les données de votre appareil Android TV sans avertissement en rétablissant la configuration d\'usine."</string> @@ -699,7 +699,7 @@ <string name="policylab_disableCamera" msgid="5749486347810162018">"Désactiver les appareils photo"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Empêcher l\'utilisation de tous les appareils photos"</string> <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Désactiver les options de verrouillage de l\'écran"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Empêcher l\'utilisation de certaines fonctionnalités du verrouillage de l\'écran."</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Empêcher l\'utilisation de certaines fonctionnalités du verrouillage de l\'écran"</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Domicile"</item> <item msgid="7740243458912727194">"Mobile"</item> @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Débogage USB activé"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Appuyez pour désactiver le débogage USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Sélectionnez cette option pour désactiver le débogage USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Débogage via Wi-Fi activé"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Appuyez pour désactiver le débogage via Wi-Fi"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Sélectionnez cette option pour désactiver le débogage via Wi-Fi."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Débogage sans fil connecté"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Appuyez pour désactiver le débogage sans fil"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Sélectionnez cette option pour désactiver le débogage sans fil."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Mode Atelier de test activé"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Rétablissez la configuration d\'usine pour désactiver le mode Atelier de test."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Console série activée"</string> @@ -1789,8 +1789,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Mis à jour par votre administrateur"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n·active le thème sombre ;\n·désactive ou restreint les activités en arrière-plan, certains effet visuels et d\'autres fonctionnalités, comme \"Ok Google\".\n\n"<annotation id="url">"En savoir plus"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n·active le thème sombre ;\n·désactive ou restreint les activités en arrière-plan, certains effet visuels et d\'autres fonctionnalités, comme \"Ok Google\"."</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n· active le thème sombre ;\n· désactive ou restreint les activités en arrière-plan, certains effet visuels et d\'autres fonctionnalités, comme \"Ok Google\".\n\n"<annotation id="url">"En savoir plus"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n· active le thème sombre ;\n· désactive ou restreint les activités en arrière-plan, certains effet visuels et d\'autres fonctionnalités, comme \"Ok Google\"."</string> <string name="data_saver_description" msgid="4995164271550590517">"Pour réduire la consommation de données, l\'économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Ainsi, les applications que vous utilisez peuvent toujours accéder aux données, mais pas en permanence. Par exemple, il se peut que les images ne s\'affichent pas tant que vous n\'appuyez pas dessus."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données ?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversation"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversation de groupe"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g> ou +"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Professionnel"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Vue personnelle"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 1f6e4d74f696..7f621ca43545 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa de grupo"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"><xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Traballo"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Vista persoal"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 29a984773c31..fa88ebc38c5c 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -307,7 +307,7 @@ <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ઑડિઓ રેકોર્ડ કરવાની"</string> <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"શારીરિક પ્રવૃત્તિ"</string> <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"તમારી શારીરિક પ્રવૃત્તિને ઍક્સેસ કરવી"</string> - <string name="permgrouplab_camera" msgid="9090413408963547706">"કૅમેરો"</string> + <string name="permgrouplab_camera" msgid="9090413408963547706">"કૅમેરા"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"ચિત્રો લેવાની અને વીડિઓ રેકોર્ડ કરવાની"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"કૉલ લૉગ"</string> <string name="permgroupdesc_calllog" msgid="2026996642917801803">"ફોન કૉલ લૉગ વાંચો અને લખો"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"વાતચીત"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ગ્રૂપ વાતચીત"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"વ્યક્તિગત"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"કાર્યાલય"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"વ્યક્તિગત વ્યૂ"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index cd6eec1ade9e..ca9ad6778590 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -559,7 +559,7 @@ <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"उपयोगकर्ता ने फिंगरप्रिंट की पुष्टि की कार्रवाई रद्द कर दी है."</string> <string name="fingerprint_error_lockout" msgid="7853461265604738671">"बहुत ज़्यादा प्रयास कर लिए गए हैं. बाद में फिर से प्रयास करें."</string> <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"बहुत ज़्यादा कोशिशें. फ़िंगरप्रिंट सेंसर अक्षम है."</string> - <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"फिर से प्रयास करें."</string> + <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"फिर से कोशिश करें."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोई फ़िंगरप्रिंट रजिस्टर नहीं किया गया है."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string> @@ -680,8 +680,8 @@ <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"स्क्रीनका लॉक खोलते समय गलत तरीके से लिखे गए पासवर्ड पर नज़र रखें, और अगर बार-बार गलत पासवर्ड लिखा जाता है तो फ़ोन को लॉक करें या इस उपयोगकर्ता का सभी डेटा मिटा दें."</string> <string name="policylab_resetPassword" msgid="214556238645096520">"स्क्रीन लॉक बदलना"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"स्क्रीन लॉक बदलना."</string> - <string name="policylab_forceLock" msgid="7360335502968476434">"स्क्रीन लॉक करें"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"नियंत्रित करें कि स्क्रीन कैसे और कब लॉक हो."</string> + <string name="policylab_forceLock" msgid="7360335502968476434">"स्क्रीन लॉक करना"</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"इससे नियंत्रित होगा कि स्क्रीन कैसे और कब लॉक हो."</string> <string name="policylab_wipeData" msgid="1359485247727537311">"सारा डेटा मिटाना"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"फ़ैक्टरी डेटा रीसेट करके चेतावनी दिए बिना फ़ोन का डेटा मिटाना."</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"फ़ैक्ट्री डेटा रीसेट करके अपने Android TV डिवाइस का डेटा बिना चेतावनी दिए मिटाएं."</string> @@ -698,8 +698,8 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"संग्रहित ऐप्स डेटा को एन्क्रिप्ट किया जाना आवश्यक है."</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"कैमरों को अक्षम करें"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"सभी डिवाइस कैमरों का उपयोग रोकें."</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"स्क्रीन लॉक की कुछ सुविधाएं बंद करें"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"कुछ स्क्रीन लाॅक सुविधाओं का उपयोग रोकें."</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"स्क्रीन लॉक की कुछ सुविधाएं बंद करना"</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"यह कुछ स्क्रीन लाॅक सुविधाओं का इस्तेमाल रोकती है."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"घर"</item> <item msgid="7740243458912727194">"मोबाइल"</item> @@ -832,8 +832,8 @@ <string name="lockscreen_emergency_call" msgid="7500692654885445299">"आपातकाल"</string> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"कॉल पर वापस लौटें"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"सही!"</string> - <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"फिर से प्रयास करें"</string> - <string name="lockscreen_password_wrong" msgid="8605355913868947490">"फिर से प्रयास करें"</string> + <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"फिर से कोशिश करें"</string> + <string name="lockscreen_password_wrong" msgid="8605355913868947490">"फिर से कोशिश करें"</string> <string name="lockscreen_storage_locked" msgid="634993789186443380">"सभी सुविधाओं और डेटा के लिए अनलॉक करें"</string> <string name="faceunlock_multiple_failures" msgid="681991538434031708">"मालिक का चेहरा पहचानकर अनलॉक करने की तय सीमा खत्म हो गई"</string> <string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"कोई सिम कार्ड नहीं है"</string> @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"यूएसबी डीबग करने के लिए एडीबी कनेक्ट किया गया"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"यूएसबी को डीबग करने की सुविधा बंद करने के लिए टैप करें"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB डीबग करना अक्षम करने के लिए चुनें."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"वायरलेस तरीके से डीबग करने की सुविधा फ़ोन से कनेक्ट है"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"वायरलेस तरीके से डीबग करने की सुविधा बंद करने के लिए टैप करें"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"वायरलेस तरीके से डीबग करने की सुविधा बंद करने के लिए चुनें."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"वॉयरलेस डीबगिंग कनेक्ट है"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"वॉयरलेस डीबगिंग की सुविधा बंद करने के लिए टैप करें"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"वॉयरलेस डीबगिंग की सुविधा बंद करने के लिए चुनें."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"टेस्ट हार्नेस मोड चालू किया गया"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"टेस्ट हार्नेस मोड बंद करने के लिए फ़ैक्ट्री रीसेट करें."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"सीरियल कंसोल को चालू करें"</string> @@ -1660,7 +1660,7 @@ <string name="user_switched" msgid="7249833311585228097">"मौजूदा उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string> <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> पर स्विच किया जा रहा है…"</string> <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा प्रस्थान किया जा रहा है…"</string> - <string name="owner_name" msgid="8713560351570795743">"स्वामी"</string> + <string name="owner_name" msgid="8713560351570795743">"मालिक"</string> <string name="error_message_title" msgid="4082495589294631966">"गड़बड़ी"</string> <string name="error_message_change_not_allowed" msgid="843159705042381454">"आपका व्यवस्थापक इस बदलाव की अनुमति नहीं देता"</string> <string name="app_not_found" msgid="3429506115332341800">"इस कार्यवाही को प्रबंधित करने के लिए कोई ऐप्स नहीं मिला"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"बातचीत"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ग्रुप में बातचीत"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"निजी प्रोफ़ाइल"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"वर्क प्रोफ़ाइल"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"निजी व्यू"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 94ff54c3cd48..4dab59979ccd 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -2078,8 +2078,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Razgovor"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupni razgovor"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobno"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Osobni prikaz"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 30a75dc25ff4..a2eac83638ae 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -34,7 +34,7 @@ <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string> <string name="mmiError" msgid="2862759606579822246">"Kapcsolódási probléma vagy érvénytelen MMI-kód."</string> <string name="mmiFdnError" msgid="3975490266767565852">"A művelet fix hívószámokra van korlátozva."</string> - <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"A hívásátirányítási beállításokat barangolás közben telefonról nem lehet módosítani."</string> + <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"A hívásátirányítási beállításokat roaming közben telefonról nem lehet módosítani."</string> <string name="serviceEnabled" msgid="7549025003394765639">"A szolgáltatás engedélyezésre került."</string> <string name="serviceEnabledFor" msgid="1463104778656711613">"Engedélyezett szolgáltatás(ok):"</string> <string name="serviceDisabled" msgid="641878791205871379">"A szolgáltatás ki van kapcsolva."</string> @@ -113,12 +113,12 @@ <string name="roamingText2" msgid="2834048284153110598">"Barangolásjelző villog"</string> <string name="roamingText3" msgid="831690234035748988">"A környéken kívül"</string> <string name="roamingText4" msgid="2171252529065590728">"Épületen kívül"</string> - <string name="roamingText5" msgid="4294671587635796641">"Barangolás - preferált rendszer"</string> - <string name="roamingText6" msgid="5536156746637992029">"Barangolás -- elérhető rendszer"</string> - <string name="roamingText7" msgid="1783303085512907706">"Barangolás - szövetségi partner"</string> - <string name="roamingText8" msgid="7774800704373721973">"Barangolás -- Prémium partner"</string> - <string name="roamingText9" msgid="1933460020190244004">"Barangolás - teljes szolgáltatásműködés"</string> - <string name="roamingText10" msgid="7434767033595769499">"Barangolás - részleges szolgáltatásműködés"</string> + <string name="roamingText5" msgid="4294671587635796641">"Roaming - preferált rendszer"</string> + <string name="roamingText6" msgid="5536156746637992029">"Roaming - elérhető rendszer"</string> + <string name="roamingText7" msgid="1783303085512907706">"Roaming - szövetségi partner"</string> + <string name="roamingText8" msgid="7774800704373721973">"Roaming - Prémium partner"</string> + <string name="roamingText9" msgid="1933460020190244004">"Roaming - teljes szolgáltatásműködés"</string> + <string name="roamingText10" msgid="7434767033595769499">"Roaming - részleges szolgáltatásműködés"</string> <string name="roamingText11" msgid="5245687407203281407">"Barangolást jelző szalaghirdetés bekapcsolva"</string> <string name="roamingText12" msgid="673537506362152640">"Barangolást jelző szalaghirdetés kikapcsolva"</string> <string name="roamingTextSearching" msgid="5323235489657753486">"Szolgáltatás keresése"</string> @@ -1309,7 +1309,7 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-hibakereső csatlakoztatva"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Koppintson az USB-hibakeresés kikapcsolásához"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Válassza ezt az USB hibakeresés kikapcsolásához."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Vezeték nélküli hibakereső csatlakoztatva"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Vezeték nélküli hibakeresés csatlakoztatva"</string> <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Koppintson a vezeték nélküli hibakeresés kikapcsolásához"</string> <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Válassza ezt a vezeték nélküli hibakeresés letiltásához."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Tesztelési alapkörnyezet mód engedélyezve"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Beszélgetés"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Csoportos beszélgetés"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Személyes"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Munka"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Személyes nézet"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 21aa14802157..8ca31763d7c5 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1546,7 +1546,7 @@ <string name="activity_resolver_use_once" msgid="948462794469672658">"Միայն այս անգամ"</string> <string name="activity_resolver_app_settings" msgid="6758823206817748026">"Կարգավորումներ"</string> <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s-ը չի աջակցում աշխատանքային պրոֆիլներ"</string> - <string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Գրասալիկ"</string> + <string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Պլանշետ"</string> <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Հեռուստացույց"</string> <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Հեռախոս"</string> <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Դոկ-կայանի բարձրախոսներ"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>՝"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Նամակագրություն"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Խմբային նամակագրություն"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Անձնական"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Աշխատանքային"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Անձնական"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 6f2deee7e511..c45f349146d9 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Samtal"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Hópsamtal"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Persónulegt"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Vinna"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Persónulegt yfirlit"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 39e5a6e61d66..704b233a010c 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -295,7 +295,7 @@ <string name="managed_profile_label" msgid="7316778766973512382">"Passa a profilo di lavoro"</string> <string name="permgrouplab_contacts" msgid="4254143639307316920">"Contatti"</string> <string name="permgroupdesc_contacts" msgid="9163927941244182567">"accedere ai contatti"</string> - <string name="permgrouplab_location" msgid="1858277002233964394">"Geolocalizz."</string> + <string name="permgrouplab_location" msgid="1858277002233964394">"Geolocalizzazione"</string> <string name="permgroupdesc_location" msgid="1995955142118450685">"accedere alla posizione di questo dispositivo"</string> <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendario"</string> <string name="permgroupdesc_calendar" msgid="6762751063361489379">"accedere al calendario"</string> @@ -309,7 +309,7 @@ <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"Consente di accedere all\'attività fisica"</string> <string name="permgrouplab_camera" msgid="9090413408963547706">"Fotocamera"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"scattare foto e registrare video"</string> - <string name="permgrouplab_calllog" msgid="7926834372073550288">"Log chiamate"</string> + <string name="permgrouplab_calllog" msgid="7926834372073550288">"Registri chiamate"</string> <string name="permgroupdesc_calllog" msgid="2026996642917801803">"leggere e modificare il registro chiamate del telefono"</string> <string name="permgrouplab_phone" msgid="570318944091926620">"Telefono"</string> <string name="permgroupdesc_phone" msgid="270048070781478204">"eseguire e gestire le telefonate"</string> @@ -1789,8 +1789,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Aggiornato dall\'amministratore"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Per estendere la durata della batteria, Risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Per estendere la durata della batteria, Risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Per estendere la durata della batteria, il risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Per estendere la durata della batteria, il risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string> <string name="data_saver_description" msgid="4995164271550590517">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Attivare Risparmio dati?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Attiva"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 4b131247e7ee..5c0ab1448bbf 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"שיחה"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"שיחה קבוצתית"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"אישי"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"עבודה"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"תצוגה אישית"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index f31f1c830688..1e5f5ec50eb9 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -545,7 +545,7 @@ <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"指紋を一部しか検出できませんでした。もう一度お試しください。"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"指紋を処理できませんでした。もう一度お試しください。"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"指紋認証センサーに汚れがあります。汚れを落としてもう一度お試しください。"</string> - <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"指の動きが速すぎました。もう一度お試しください。"</string> + <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"指を離すのが速すぎました。もう一度お試しください。"</string> <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"指の動きが遅すぎました。もう一度お試しください。"</string> <string-array name="fingerprint_acquired_vendor"> </string-array> @@ -698,7 +698,7 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"保存したアプリデータが暗号化されるようにします。"</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"カメラを無効にする"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"すべてのデバイスカメラを使用できないようにします。"</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"画面ロックの一部の機能を無効化"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"画面ロックの一部機能を無効化"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"画面ロックの一部の機能の使用を禁止します。"</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"自宅"</item> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"会話"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"グループの会話"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"個人用"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"仕事用"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"個人用ビュー"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index b5892ebbe434..a417eab484a9 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -305,8 +305,8 @@ <string name="permgroupdesc_storage" msgid="6351503740613026600">"құрылғыдағы фотосуреттерге, мультимедиаға және файлдарға қол жеткізу"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Микрофон"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"аудио жазу"</string> - <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Физикалық әрекет"</string> - <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"физикалық әрекет дерегін алу"</string> + <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Іс-қимыл"</string> + <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"іс-қимыл дерегін алу"</string> <string name="permgrouplab_camera" msgid="9090413408963547706">"Камера"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"суретке түсіріп, бейне жазу"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"Қоңырау журналдары"</string> @@ -542,7 +542,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"Танылмады"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Аутентификациядан бас тартылды."</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ешқандай PIN коды, өрнек немесе құпия сөз орнатылмаған."</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Саусақ ізі ішінара анықталды. Әрекетті қайталаңыз."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Саусақ ізі толық анықталмады. Әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Саусақ ізін өңдеу мүмкін емес. Әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Саусақ ізі сенсоры лас. Тазалап, әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Саусағыңызды тым жылдам қозғалттыңыз. Әрекетті қайталап көріңіз."</string> @@ -699,7 +699,7 @@ <string name="policylab_disableCamera" msgid="5749486347810162018">"Камераларды өшіру"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Құрылғыдағы барлық камералар қолданысын бөгеу."</string> <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Экран құлпы функцияларын өшіру"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Кейбір экранды құлыптау мүмкіндіктерін пайдалануға тыйым салынады."</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Кейбір экранды құлыптау мүмкіндіктерін пайдалануға тыйым салу."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Үй"</item> <item msgid="7740243458912727194">"Ұялы тел."</item> @@ -1183,7 +1183,7 @@ <string name="unsupported_display_size_show" msgid="980129850974919375">"Үнемі көрсету"</string> <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы сіздің Android OЖ-бен үйлеспейді және дұрыс жұмыс істемеуі ықтимал. Қолданбаның жаңартылған нұсқасы қолжетімді болуы мүмкін."</string> <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Үнемі көрсету"</string> - <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Жаңартуды тексеру"</string> + <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Жаңа нұсқасының бар-жоғын тексеру"</string> <string name="smv_application" msgid="3775183542777792638">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасы (<xliff:g id="PROCESS">%2$s</xliff:g> процесі) өзі қолданған StrictMode саясатын бұзды."</string> <string name="smv_process" msgid="1398801497130695446">"<xliff:g id="PROCESS">%1$s</xliff:g> үрдісі өздігінен күшіне енген ҚатаңРежим ережесін бұзды."</string> <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Телефон жаңартылуда…"</string> @@ -1889,7 +1889,7 @@ <string name="app_blocked_title" msgid="7353262160455028160">"Қолданба қолжетімді емес"</string> <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> қазір қолжетімді емес."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Қолданба Android жүйесінің ескі нұсқасына арналған және дұрыс жұмыс істемеуі мүмкін. Жаңартылған нұсқаны тексеріңіз немесе әзірлеушіге хабарласыңыз."</string> - <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңартылған нұсқаны тексеру"</string> + <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңа нұсқасының бар-жоғын тексеру"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Сізде жаңа хабарлар бар"</string> <string name="new_sms_notification_content" msgid="3197949934153460639">"Көру үшін SMS қолданбасын ашыңыз"</string> <string name="profile_encrypted_title" msgid="9001208667521266472">"Кейбір функциялар істемеуі мүмкін."</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Чат"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Топтық чат"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Жұмыс"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Жеке көру"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 7de5a8b40ffa..50cea4455695 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -681,7 +681,7 @@ <string name="policylab_resetPassword" msgid="214556238645096520">"ប្តូរការចាក់សោអេក្រង់"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"ប្តូរការចាក់សោអេក្រង់។"</string> <string name="policylab_forceLock" msgid="7360335502968476434">"ចាក់សោអេក្រង់"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"ពិនិត្យវិធី និងពេលវេលាចាក់សោអេក្រង់។"</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"គ្រប់គ្រងវិធី និងពេលវេលាចាក់សោអេក្រង់។"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"លុបទិន្នន័យទាំងអស់"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"លុបទិន្នន័យកុំព្យូទ័របន្ទះដោយមិនព្រមានដោយអនុវត្តការកំណត់ទិន្នន័យដូចចេញពីរោងចក្រ។"</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"លុបទិន្នន័យឧបករណ៍ Android TV របស់អ្នកដោយមិនមានការព្រមាន ដោយធ្វើការកំណត់ទិន្នន័យដូចចេញពីរោងចក្រ។"</string> @@ -2046,8 +2046,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>៖"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ការសន្ទនា"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ការសន្ទនាជាក្រុម"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ផ្ទាល់ខ្លួន"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ការងារ"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ទិដ្ឋភាពផ្ទាល់ខ្លួន"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 8d4b30ac100d..bbe9201bacaf 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -1573,7 +1573,7 @@ <string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string> <string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", ಸುರಕ್ಷಿತ"</string> <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ಮರೆತಿರುವಿರಿ"</string> - <string name="kg_wrong_pattern" msgid="1342812634464179931">"ತಪ್ಪು ಪ್ಯಾಟರ್ನ್"</string> + <string name="kg_wrong_pattern" msgid="1342812634464179931">"ಪ್ಯಾಟರ್ನ್ ತಪ್ಪಾಗಿದೆ"</string> <string name="kg_wrong_password" msgid="2384677900494439426">"ತಪ್ಪು ಪಾಸ್ವರ್ಡ್"</string> <string name="kg_wrong_pin" msgid="3680925703673166482">"ತಪ್ಪಾದ ಪಿನ್"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568"> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ಸಂವಾದ"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ಗುಂಪು ಸಂವಾದ"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ವೈಯಕ್ತಿಕ"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ಕೆಲಸ"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ವೈಯಕ್ತಿಕ ವೀಕ್ಷಣೆ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 73a769b65c19..a5c88328d39f 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"대화"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"그룹 대화"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"개인"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"직장"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"개인 뷰"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 69d886f0dbd4..5ea4383c6a45 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -491,7 +491,7 @@ <string name="permlab_changeNetworkState" msgid="8945711637530425586">"тармак туташымдуулугун өзгөртүү"</string> <string name="permdesc_changeNetworkState" msgid="649341947816898736">"Колдонмого тармактык туташуунун абалын өзгөртүү мүмкүнчүлүгүн берет."</string> <string name="permlab_changeTetherState" msgid="9079611809931863861">"интернет бөлүшүү байланышын өзгөртүү"</string> - <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Колдонмого тетеринг тармактык туташуусунун абалын өзгөртүү мүмкүнчүлүгүн берет."</string> + <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Колдонмо модем режимин күйгүзүп, өчүрө алат."</string> <string name="permlab_accessWifiState" msgid="5552488500317911052">"Wi-Fi туташууларын көрүү"</string> <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Колдонмого Wi-Fi жандырылгандыгы жана туташкан Wi-Fi түзмөктөрдүн аттары сыяктуу, Wi-Fi түйүндөрүнүн маалыматтарын көрүүгө уруксаты берет."</string> <string name="permlab_changeWifiState" msgid="7947824109713181554">"Wi-Fi менен туташуу жана ажыратуу"</string> @@ -545,7 +545,7 @@ <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Манжа изи жарым-жартылай аныкталды. Кайталап көрүңүз."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Манжа изи иштелбей койду. Кайталап көрүңүз."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Манжа изинин сенсору кирдеп калган. Тазалап, кайталап көрүңүз."</string> - <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Манжа өтө тез жылдырылды. Кайталап көрүңүз."</string> + <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Манжаңызды өтө тез жылдырдыңыз. Кайталап көрүңүз."</string> <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Манжа өтө жай жылды. Кайталап көрүңүз."</string> <string-array name="fingerprint_acquired_vendor"> </string-array> @@ -1311,7 +1311,7 @@ <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB аркылуу мүчүлүштүктөрдү оңдоону өчүрүүнү тандаңыз."</string> <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Мүчүлүштүктөрдү зымсыз оңдоо иштетилди"</string> <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Мүчүлүштүктөрдү зымсыз оңдоону өчүрүү үчүн таптап коюңуз"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Мүчүлүштүктөрдү зымсыз оңдоону өчүрүүнү тандаңыз."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоону өчүрүңүз."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Сыноо программасынын режими иштетилди"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Сыноо программасынын режимин өчүрүү үчүн, баштапкы жөндөөлөргө кайтарыңыз."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Сериялык консоль иштетилди"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Жазышуу"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Топтук маек"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Жумуш"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Жеке көрүнүш"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 2e331a03bb97..b22fa0e7b6b4 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -293,7 +293,7 @@ <string name="android_system_label" msgid="5974767339591067210">"ລະບົບ Android"</string> <string name="user_owner_label" msgid="8628726904184471211">"ສະຫຼັບໄປໂປຣໄຟລ໌ສ່ວນຕົວ"</string> <string name="managed_profile_label" msgid="7316778766973512382">"ສະຫຼັບໄປໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string> - <string name="permgrouplab_contacts" msgid="4254143639307316920">"ລາຍຊື່"</string> + <string name="permgrouplab_contacts" msgid="4254143639307316920">"ລາຍຊື່ຜູ້ຕິດຕໍ່"</string> <string name="permgroupdesc_contacts" msgid="9163927941244182567">"ເຂົ້າຫາລາຍຊື່ຂອງທ່ານ"</string> <string name="permgrouplab_location" msgid="1858277002233964394">"ສະຖານທີ່"</string> <string name="permgroupdesc_location" msgid="1995955142118450685">"ເຂົ້າເຖິງຂໍ້ມູນສະຖານທີ່ຂອງອຸປະກອນນີ້"</string> @@ -681,7 +681,7 @@ <string name="policylab_resetPassword" msgid="214556238645096520">"ປ່ຽນລັອກໜ້າຈໍ"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"ປ່ຽນລັອກໜ້າຈໍ."</string> <string name="policylab_forceLock" msgid="7360335502968476434">"ລັອກໜ້າຈໍ"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"ຄວບຄຸມວ່າໜ້າຈໍຄວນຈະຖືກລັອກເມື່ອໃດ ແລະແນວໃດ"</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"ຄວບຄຸມວ່າໜ້າຈໍຄວນຈະຖືກລັອກເມື່ອໃດ ແລະ ແນວໃດ."</string> <string name="policylab_wipeData" msgid="1359485247727537311">"ລຶບຂໍ້ມູນທັງໝົດ"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"ລຶບຂໍ້ມູນຂອງແທັບເລັດໂດຍບໍ່ມີການເຕືອນ ໂດຍການຣີເຊັດກັບຄືນໃຫ້ເປັນແບບທີ່ມາຈາກໂຮງງານ."</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"ລຶບຂໍ້ມູນຂອງອຸປະກອນ Android TV ທ່ານໂດຍບໍ່ຕ້ອງແຈ້ງເຕືອນດ້ວຍການຣີເຊັດຂໍ້ມູນເປັນຄ່າເລີ່ມຕົ້ນຈາກໂຮງງານ."</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 021717d5133c..1b2d0b59f080 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Pokalbis"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupės pokalbis"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Asmeninė"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Darbo"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Asmeninė peržiūra"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 6ea61a170fe0..9cb4bd6b89cd 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -2078,8 +2078,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Saruna"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupas saruna"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Privātais profils"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Darba profils"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personisks skats"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 9c434db0d025..3807da8bcd09 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -194,7 +194,7 @@ <string name="location_changed_notification_title" msgid="3620158742816699316">"Апликациите може да пристапуваат до вашата локација"</string> <string name="location_changed_notification_text" msgid="7158423339982706912">"Контактирајте со IT-администраторот за да дознаете повеќе"</string> <string name="country_detector" msgid="7023275114706088854">"Детектор на земја"</string> - <string name="location_service" msgid="2439187616018455546">"Услуги според локација"</string> + <string name="location_service" msgid="2439187616018455546">"Услуга за локација"</string> <string name="sensor_notification_service" msgid="7474531979178682676">"Услуга за известување од сензорот"</string> <string name="twilight_service" msgid="8964898045693187224">"Услуга за самрак"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Уредот ќе се избрише"</string> @@ -678,14 +678,14 @@ <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Набљудувај го бројот на погрешно внесени лозинки при отклучување на екранот и заклучи го таблетот или избриши ги сите податоци од овој корисник доколку се внесени премногу погрешни лозинки."</string> <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Го следи бројот на погрешно внесени лозинки при отклучување на екранот и го заклучува уредот Android TV или ги брише сите податоци од овој корисник доколку се внесени премногу погрешни лозинки."</string> <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Набљудувај го бројот на погрешно внесени лозинки при отклучување на екранот и заклучи го телефонот или избриши ги сите податоци од овој корисник доколку се внесени премногу погрешни лозинки."</string> - <string name="policylab_resetPassword" msgid="214556238645096520">"Промени го заклучувањето на екранот."</string> + <string name="policylab_resetPassword" msgid="214556238645096520">"Промени го заклучувањето на екранот"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"Промени го заклучувањето на екранот."</string> <string name="policylab_forceLock" msgid="7360335502968476434">"Заклучи го екранот"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"Контролирај како и кога се заклучува екранот."</string> <string name="policylab_wipeData" msgid="1359485247727537311">"Избриши ги сите податоци"</string> - <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Избриши ги податоците во таблетот без предупредување со вршење на фабричко ресетирање на податоци."</string> + <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Избриши ги податоците во таблетот без предупредување со ресетирање на фабрички податоци."</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Ги брише податоците на вашиот уред Android TV без предупредување, така што ќе изврши ресетирање на фабричките податоци."</string> - <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Избриши ги податоците во телефонот без предупредување со вршење на фабричко ресетирање на податоци."</string> + <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Избриши ги податоците во телефонот без предупредување со ресетирање на фабрички податоци."</string> <string name="policylab_wipeData_secondaryUser" msgid="413813645323433166">"Избриши ги податоците на корисникот"</string> <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Избриши ги податоците на овој корисник на таблетот без предупредување."</string> <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"Ги брише податоците на овој корисник на уредов Android TV без предупредување."</string> @@ -699,7 +699,7 @@ <string name="policylab_disableCamera" msgid="5749486347810162018">"Оневозможи фотоапарати"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Спречи употреба на сите камери на уредот."</string> <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Онев. функции од заклуч. екран"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Спречете користење на некои функции од заклучување на екранот."</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Спречи користење на некои функции од заклучување на екранот."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Дома"</item> <item msgid="7740243458912727194">"Мобилен"</item> @@ -2046,8 +2046,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Разговор"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групен разговор"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Службени"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Личен приказ"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index ad0cde1d4f87..e54cf72a7ac3 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -680,7 +680,7 @@ <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"സ്ക്രീൻ അൺലോക്കുചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പുചെയ്ത പാസ്വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുകയും നിരവധി തവണ പാസ്വേഡ് ടൈപ്പുചെയ്തെങ്കിൽ ഫോൺ ലോക്കുചെയ്യുകയോ ഈ എല്ലാ ഉപയോക്തൃവിവരവും മായ്ക്കുകയോ ചെയ്യുക."</string> <string name="policylab_resetPassword" msgid="214556238645096520">"സ്ക്രീൻ ലോക്ക് മാറ്റുക"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"സ്ക്രീൻ ലോക്ക് മാറ്റുക."</string> - <string name="policylab_forceLock" msgid="7360335502968476434">"സ്ക്രീൻ ലോക്കുചെയ്യുക"</string> + <string name="policylab_forceLock" msgid="7360335502968476434">"സ്ക്രീൻ ലോക്ക് ചെയ്യുക"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"സ്ക്രീൻ ലോക്കുകൾ എങ്ങനെ വേണമെന്നും എപ്പോൾ വേണമെന്നും എന്നത് നിയന്ത്രിക്കുക"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"എല്ലാ ഡാറ്റയും മായ്ക്കുക"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"ഒരു ഫാക്ടറി ഡാറ്റ പുനഃസജ്ജീകരണം നടപ്പിലാക്കുന്നതിലൂടെ ടാബ്ലെറ്റിന്റെ ഡാറ്റ മുന്നറിയിപ്പില്ലാതെ മായ്ക്കുക."</string> @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ഡീബഗ്ഗിംഗ് കണക്റ്റ് ചെയ്തു"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ഡീബഗ്ഗിംഗ് ഓഫാക്കാൻ ടാപ്പ് ചെയ്യുക"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ഡീബഗ്ഗുചെയ്യൽ പ്രവർത്തനരഹിതമാക്കാൻ തിരഞ്ഞെടുക്കുക."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ ഓഫാക്കാൻ ടാപ്പ് ചെയ്യുക"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ പ്രവർത്തനരഹിതമാക്കാൻ തിരഞ്ഞെടുക്കുക."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"വയർലെസ് ഡീബഗ്ഗിംഗ് കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"വയർലെസ് ഡീബഗ്ഗിംഗ് ഓഫാക്കാൻ ടാപ്പ് ചെയ്യുക"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"വയർലെസ് ഡീബഗ്ഗിംഗ് പ്രവർത്തനരഹിതമാക്കാൻ തിരഞ്ഞെടുക്കുക."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"പരിശോധനാ സംവിധാനങ്ങൾ മോഡ് പ്രവർത്തനക്ഷമമാക്കി"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"പരിശോധനാ സംവിധാന മോഡ് പ്രവർത്തനരഹിതമാക്കാൻ ഫാക്ടറി പുനഃക്രമീകരണം നിർവഹിക്കുക."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"സീരിയൽ കൺസോൾ പ്രവർത്തനക്ഷമമാക്കി"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"സംഭാഷണം"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ഗ്രൂപ്പ് സംഭാഷണം"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"വ്യക്തിപരമായത്"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ജോലിസ്ഥലം"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"വ്യക്തിപര കാഴ്ച"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 462d3a5c52ea..4fcbe76d1125 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB дебаг холбогдсон"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB дебаг хийхийг унтраахын тулд товшино уу"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB дебаг хийхийг идэвхгүй болгох бол сонгоно уу."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Утасгүй дебагийг холболоо"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Утасгүй дебагийг унтраахын тулд товшино уу"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Утасгүй дебагийг идэвхгүй болгохын тулд сонгоно уу."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wireless debugging-г холболоо"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Wireless debugging-г унтраахын тулд товшино уу"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Wireless debugging-г идэвхгүй болгохын тулд сонгоно уу."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Туршилтын цогц горимыг идэвхжүүлсэн"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Туршилтын цогц горимыг идэвхгүй болгохын тулд үйлдвэрийн төлөвт шинэчилнэ үү."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Цуваа консолыг идэвхжүүлсэн"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Харилцан яриа"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Бүлгийн харилцан яриа"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Хувийн"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Ажил"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Хувийн харагдах байдал"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 5dc743355260..feba806659e4 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"संभाषण"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"गट संभाषण"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"वैयक्तिक"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ऑफिस"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"वैयक्तिक दृश्य"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 752a9c72e6ee..1a69a731f4cc 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -681,11 +681,11 @@ <string name="policylab_resetPassword" msgid="214556238645096520">"Tukar kunci skrin"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"Tukar kunci skrin."</string> <string name="policylab_forceLock" msgid="7360335502968476434">"Kunci skrin"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"Mengawal cara dan masa skrin dikunci."</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"Kawal cara dan masa skrin dikunci."</string> <string name="policylab_wipeData" msgid="1359485247727537311">"Padamkan semua data"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Memadamkan data tablet tanpa amaran dengan melakukan tetapan semula data kilang."</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Padamkan data peranti Android TV anda tanpa amaran dengan melaksanakan tetapan semula data kilang."</string> - <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Memadamkan data telefon tanpa amaran dengan melakukan tetapan semula data kilang."</string> + <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Padamkan data telefon tanpa amaran dengan melakukan tetapan semula data kilang."</string> <string name="policylab_wipeData_secondaryUser" msgid="413813645323433166">"Padam data pengguna"</string> <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Padam data pengguna ini pada tablet ini tanpa amaran."</string> <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"Padamkan data pengguna ini pada peranti Android TV tanpa amaran."</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Perbualan"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Perbualan Kumpulan"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Peribadi"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Kerja"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Paparan peribadi"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index e94e5536bd0b..c93ca0f30ce9 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -678,9 +678,9 @@ <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"ဖန်မျက်နှာပြင်အား သော့ဖွင့်စဉ် လျှို့ဝှက်ကုဒ်အမှားများ ရိုက်သွင်းမှုအား စောင့်ကြည့်ရန်နှင့်၊ လျှို့ဝှက်ကုဒ်အမှားများ များစွာ ရိုက်သွင်းပါက တက်ဘလက်အား သော့ချခြင်း သို့မဟုတ် တက်ဘလက်၏ အချက်အလက်များအား ဖျက်ပစ်ခြင်းများ ပြုလုပ်မည်။"</string> <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"မျက်နှာပြင်ကို လော့ခ်ဖွင့်သည့်အခါ စကားဝှက်မှားယွင်းစွာ ရိုက်သွင်းသည့်အကြိမ်ရေကို စောင့်ကြည့်ပြီး မှားယွင်းသည့်အကြိမ်ရေ အလွန်များလာပါက သင့် Android TV စက်ပစ္စည်းကို လော့ခ်ချခြင်း သို့မဟုတ် ဤအသုံးပြုသူဒေတာများအားလုံးကို ဖျက်ခြင်းတို့ ပြုလုပ်သွားပါမည်။"</string> <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"ဖန်မျက်နှာပြင်အား သော့ဖွင့်စဉ် လျှို့ဝှက်ကုဒ်အမှားများ ရိုက်သွင်းမှုအား စောင့်ကြည့်ရန်နှင့်၊ လျှို့ဝှက်ကုဒ်အမှားများ များစွာ ရိုက်သွင်းပါက ဖုန်းအား သော့ချခြင်း သို့မဟုတ် ဖုန်း၏ အချက်အလက်များအား ဖျက်ပစ်ခြင်းများ ပြုလုပ်မည်။"</string> - <string name="policylab_resetPassword" msgid="214556238645096520">"မျက်နှာပြင်လော့ခ်ပြောင်းခြင်း"</string> - <string name="policydesc_resetPassword" msgid="4626419138439341851">"မျက်နှာပြင်လော့ခ်ပြောင်းသည်။"</string> - <string name="policylab_forceLock" msgid="7360335502968476434">"မျက်နှာပြင်အား လော့ခ်ချခြင်း"</string> + <string name="policylab_resetPassword" msgid="214556238645096520">"ဖန်သားပြင်လော့ခ်ပြောင်းခြင်း"</string> + <string name="policydesc_resetPassword" msgid="4626419138439341851">"ဖန်သားပြင်လော့ခ်ပြောင်းသည်။"</string> + <string name="policylab_forceLock" msgid="7360335502968476434">"ဖန်သားပြင်အား လော့ခ်ချခြင်း"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"ဖန်သားပြင် လော့ခ်ချချိန်၊ လော့ချနည်းကို ထိမ်းချုပ်သည်။"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"ဒေတာအားလုံးအားဖျက်ခြင်း"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"စက်ရုံထုတ် အခြေအနေအား ပြန်ပြောင်းခြင်းဖြင့် တက်ဘလက်ရှိ အချက်အလက်များအား ကြိုတင်သတိပေးမှုမရှိပဲ ဖျက်စီးရန်"</string> @@ -1855,7 +1855,7 @@ <string name="expand_button_content_description_expanded" msgid="7484217944948667489">"ခေါက်သိမ်းရန်"</string> <string name="expand_action_accessibility" msgid="1947657036871746627">"ချဲ့ခြင်းခလုတ်"</string> <string name="usb_midi_peripheral_name" msgid="490523464968655741">"Android USB ဘေးဘက်အပေါက်"</string> - <string name="usb_midi_peripheral_manufacturer_name" msgid="7557148557088787741">"အန်းဒရွိုက်"</string> + <string name="usb_midi_peripheral_manufacturer_name" msgid="7557148557088787741">"Android"</string> <string name="usb_midi_peripheral_product_name" msgid="2836276258480904434">"USB ဘေးရှိပို့တ်"</string> <string name="floating_toolbar_open_overflow_description" msgid="2260297653578167367">"နောက်ထပ် ရွေးစရာများ"</string> <string name="floating_toolbar_close_overflow_description" msgid="3949818077708138098">"ကိရိယာဘားအပိုအား ပိတ်ရန်"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index e41127b30609..78580644f2d5 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Samtale"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppesamtale"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personlig visning"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 6693823eb4c1..2ad119f23fe1 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -678,14 +678,14 @@ <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप संख्या अनुगमन गर्नुहोस्, र यदि निकै धेरै गलत पासवर्डहरू टाइप गरिएमा ट्याब्लेट लक गर्नुहोस् वा प्रयोगकर्ताको डेटा मेटाउनुहोस्।"</string> <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप गरेको सङ्ख्या निरीक्षण गर्नुहोस्, र धेरै पटक गलत पासवर्डहरू टाइप गरिएको खण्डमा आफ्नो Android TV यन्त्र लक गर्नुहोस् वा यो प्रयोगकर्ताको सम्पूर्ण डेटा मेटाउनुहोस्।"</string> <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप संख्या अनुगमन गर्नुहोस्, र यदि निकै धेरै गलत पासवर्डहरू टाइप गरिएमा फोन लक गर्नुहोस् वा प्रयोगकर्ताको डेटा मेटाउनुहोस्।"</string> - <string name="policylab_resetPassword" msgid="214556238645096520">"स्क्रिन लक परिवर्तन गर्नुहोस्"</string> + <string name="policylab_resetPassword" msgid="214556238645096520">"स्क्रिन लक परिवर्तन गर्ने"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"स्क्रिन लक परिवर्तन गर्नुहोस्।"</string> - <string name="policylab_forceLock" msgid="7360335502968476434">"स्क्रिन लक गर्नुहोस्।"</string> + <string name="policylab_forceLock" msgid="7360335502968476434">"स्क्रिन लक गर्ने"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"कसरी र कहिले स्क्रिन लक गर्ने नियन्त्रण गर्नुहोस्।"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"सबै डेटा मेट्नुहोस्"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"एउटा फ्याक्ट्रि डेटा पुनःसेट गरेर चेतावनी नआउँदै ट्याबल्टको डेटा मेट्नुहोस्।"</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"फ्याक्ट्री डेटा रिसेट गरेर चेतावनी नदिइकन आफ्नो Android TV यन्त्रको डेटा मेटाउनुहोस्।"</string> - <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"एउटा फ्याक्ट्रि डेटा पुनःसेट गरेर चेतावनी नआउँदै फोनको डेटा मेट्नुहोस्।"</string> + <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"एउटा फ्याक्ट्रि डेटा पुनःसेट गरेर चेतावनी नदिइकन फोनको डेटा मेट्न।"</string> <string name="policylab_wipeData_secondaryUser" msgid="413813645323433166">"प्रयोगकर्ता डेटा मेट्नुहोस्"</string> <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"चेतावनी बिना यो ट्याब्लेटमा यस प्रयोगकर्ताको डेटा मेट्नुहोस्।"</string> <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"यो Android TV यन्त्रमा भएको यस प्रयोगकर्ताको डेटा चेतावनी नदिइकन मेटाउनुहोस्।"</string> @@ -698,7 +698,7 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"भण्डार गरिएको डेटा इन्क्रिप्ट हुनु आवश्यक छ।"</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"क्यामेरालाई असक्षम गराउनुहोस्"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"सबै उपकरण क्यामराहरूको प्रयोग रोक्नुहोस्"</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"केही स्क्रिन लकका सुविधाहरू अक्षम गर्नुहोस्"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"स्क्रिन लकका केही सुविधा असक्षम पार्ने"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"केही स्क्रिन लक सुविधाहरूको प्रयोगमा रोक लगाउनुहोस्।"</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"गृह"</item> @@ -930,7 +930,7 @@ <string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"यही पृष्ठमा रहनुहोस्"</string> <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nके तपाईं यो पेजबाट नेभिगेट गर्न चाहनु हुन्छ भन्ने निश्चत छ?"</string> <string name="save_password_label" msgid="9161712335355510035">"निश्चित गर्नुहोस्"</string> - <string name="double_tap_toast" msgid="7065519579174882778">"जुक्ति: जुमलाई ठूलो र सानो पार्न दुई पटक हान्नुहोस्।"</string> + <string name="double_tap_toast" msgid="7065519579174882778">"जुक्ति: जुमलाई ठुलो र सानो पार्न दुई पटक हान्नुहोस्।"</string> <string name="autofill_this_form" msgid="3187132440451621492">"स्वतः भर्ने"</string> <string name="setup_autofill" msgid="5431369130866618567">"अटोफिल सेटअप गर्नुहोस्"</string> <string name="autofill_window_title" msgid="4379134104008111961">"<xliff:g id="SERVICENAME">%1$s</xliff:g> मार्फत स्वतः भरण गर्नुहोस्"</string> @@ -1315,9 +1315,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB डिबग गर्ने सुविधा सुचारू छ"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB डिबग प्रक्रिया निष्क्रिय पार्न ट्याप गर्नुहोस्"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB डिबगिङलाई असक्षम पार्न ट्याप गर्नुहोस्।"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"वायरलेस डिबग प्रक्रिया जडान गरियो"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"वायरलेस डिबग प्रक्रिया निष्क्रिय पार्न ट्याप गर्नुहोस्"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"वायरलेस डिबग प्रक्रिया असक्षम पार्ने विकल्प चयन गर्नुहोस्।"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"वायरलेस डिबगिङ जोडियो"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"वायरलेस डिबगिङ निष्क्रिय पार्न ट्याप गर्नुहोस्"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"वायरलेस डिबगिङ असक्षम पार्न यो विकल्प चयन गर्नुहोस्।"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"परीक्षण प्याकेज मोड सक्षम पारियो"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"परीक्षण प्याकेज मोड असक्षम पार्न फ्याक्ट्री रिसेट गर्नुहोस्।"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"क्रमसम्बन्धी कन्सोल सक्षम पारियो"</string> @@ -1339,7 +1339,7 @@ <string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string> <string name="fast_scroll_alphabet" msgid="8854435958703888376">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"अन्य अनुप्रयोगहरूको माथिपट्टि देखाउनुहोस्"</string> + <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"अन्य अनुप्रयोगमा देखाउनुहोस्"</string> <string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> अन्य अनुप्रयोगहरूमा देखिँदैछ"</string> <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> अन्य अनुप्रयोगहरूमा देखिँदैछ"</string> <string name="alert_windows_notification_message" msgid="6538171456970725333">"तपाईं <xliff:g id="NAME">%s</xliff:g> ले यो विशेषता प्रयोग नगरेको चाहनुहुन्न भने सेटिङहरू खोली यसलाई निष्क्रिय पार्न ट्याप गर्नुहोस्।"</string> @@ -1579,7 +1579,7 @@ <string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string> <string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", सुरक्षित"</string> <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"ढाँचा बिर्सनु भयो"</string> - <string name="kg_wrong_pattern" msgid="1342812634464179931">"गलत ढाँचा"</string> + <string name="kg_wrong_pattern" msgid="1342812634464179931">"प्याटर्न मिलेन"</string> <string name="kg_wrong_password" msgid="2384677900494439426">"गलत पासवर्ड"</string> <string name="kg_wrong_pin" msgid="3680925703673166482">"गलत PIN"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568"> @@ -1865,7 +1865,7 @@ <string name="usb_midi_peripheral_product_name" msgid="2836276258480904434">"USB पेरिफेरल पोर्ट"</string> <string name="floating_toolbar_open_overflow_description" msgid="2260297653578167367">"थप विकल्पहरू"</string> <string name="floating_toolbar_close_overflow_description" msgid="3949818077708138098">"ओभरफ्लो बन्द गर्नुहोस्"</string> - <string name="maximize_button_text" msgid="4258922519914732645">"ठूलो बनाउनुहोस्"</string> + <string name="maximize_button_text" msgid="4258922519914732645">"ठुलो बनाउनुहोस्"</string> <string name="close_button_text" msgid="10603510034455258">"बन्द गर्नुहोस्"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> @@ -2050,8 +2050,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"वार्तालाप"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"सामूहिक वार्तालाप"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"व्यक्तिगत"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"काम"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"व्यक्तिगत दृश्य"</string> @@ -2135,17 +2134,17 @@ <string name="PERSOSUBSTATE_RUIM_CORPORATE_ERROR" msgid="8644184447744175747">"RUIM को कर्पोरेट लक खोलिदिन गरिएको अनुरोध असफल भयो"</string> <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ERROR" msgid="3801002648649640407">"RUIM को सेवा प्रदायकसम्बन्धी लक खोलिदिन अनुरोध गर्न सकिएन।"</string> <string name="PERSOSUBSTATE_RUIM_RUIM_ERROR" msgid="707397021218680753">"RUIM अनलक गर्न गरिएको अनुरोध असफल भयो।"</string> - <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_ERROR" msgid="894358680773257820">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ERROR" msgid="352466878146726991">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_ERROR" msgid="7353389721907138671">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ERROR" msgid="2655263155490857920">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_SIM_SIM_PUK_ERROR" msgid="6903740900892931310">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_ERROR" msgid="5165901670447518687">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_ERROR" msgid="2856763216589267623">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_ERROR" msgid="817542684437829139">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ERROR" msgid="5178635064113393143">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_ERROR" msgid="5391587926974531008">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_ERROR" msgid="4895494864493315868">"PUK अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_ERROR" msgid="894358680773257820">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ERROR" msgid="352466878146726991">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_ERROR" msgid="7353389721907138671">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ERROR" msgid="2655263155490857920">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_ERROR" msgid="6903740900892931310">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_ERROR" msgid="5165901670447518687">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_ERROR" msgid="2856763216589267623">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_ERROR" msgid="817542684437829139">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ERROR" msgid="5178635064113393143">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_ERROR" msgid="5391587926974531008">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_ERROR" msgid="4895494864493315868">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> <string name="PERSOSUBSTATE_SIM_SPN_ERROR" msgid="9017576601595353649">"SPN अनलक गर्न गरिएको अनुरोध असफल भयो।"</string> <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_ERROR" msgid="1116993930995545742">"घरमा जोडिने SP सरहको PLMN अनलक गर्न गरिएको अनुरोध असफल भयो।"</string> <string name="PERSOSUBSTATE_SIM_ICCID_ERROR" msgid="7559167306794441462">"ICCID अनलक गर्न गरिएको अनुरोध असफल भयो।"</string> @@ -2162,17 +2161,17 @@ <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_SUCCESS" msgid="6020936629725666932">"RUIM को सेवा प्रदायकसम्बन्धी लक खोलियो।"</string> <string name="PERSOSUBSTATE_RUIM_CORPORATE_SUCCESS" msgid="6944873647584595489">"RUIM को कर्पोरेट लक खोलियो।"</string> <string name="PERSOSUBSTATE_RUIM_RUIM_SUCCESS" msgid="2526483514124121988">"RUIM अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_SUCCESS" msgid="7662200333621664621">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_SUCCESS" msgid="2861223407953766632">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_SUCCESS" msgid="5345648571175243272">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="3725278343103422466">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_SIM_SIM_PUK_SUCCESS" msgid="6998502547560297983">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_SUCCESS" msgid="8555433771162560361">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_SUCCESS" msgid="3555767296933606232">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_SUCCESS" msgid="6778051818199974237">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_SUCCESS" msgid="4080108758498911429">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="7873675303000794343">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_SUCCESS" msgid="1763198215069819523">"PUK अनलक गरियो।"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_SUCCESS" msgid="7662200333621664621">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_SUCCESS" msgid="2861223407953766632">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_SUCCESS" msgid="5345648571175243272">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="3725278343103422466">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_SUCCESS" msgid="6998502547560297983">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_SUCCESS" msgid="8555433771162560361">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_SUCCESS" msgid="3555767296933606232">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_SUCCESS" msgid="6778051818199974237">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_SUCCESS" msgid="4080108758498911429">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="7873675303000794343">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_SUCCESS" msgid="1763198215069819523">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> <string name="PERSOSUBSTATE_SIM_SPN_SUCCESS" msgid="2053891977727320532">"SPN अनलक गरियो।"</string> <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_SUCCESS" msgid="8146602361895007345">"घरमा जोडिने SP सरहको PLMN अनलक गरियो।"</string> <string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID अनलक गरियो।"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 2fb675c4d5d0..90172037465d 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Gesprek"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Groepsgesprek"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoonlijk"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Werk"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Persoonlijke weergave"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index b5757c6f674d..e28ed6f5c061 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -385,7 +385,7 @@ <string name="permdesc_foregroundService" msgid="8720071450020922795">"ଫୋର୍ଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"ଆପ୍ ଷ୍ଟୋରେଜ୍ ସ୍ଥାନର ମାପ କରନ୍ତୁ"</string> <string name="permdesc_getPackageSize" msgid="742743530909966782">"ଆପ୍ର କୋଡ୍, ଡାଟା ଓ କ୍ୟାଶ୍ ଆକାର ହାସଲ କରିବା ପାଇଁ ଏହାକୁ ଅନୁମତି ଦେଇଥାଏ।"</string> - <string name="permlab_writeSettings" msgid="8057285063719277394">"ସିଷ୍ଟମ୍ ସେଟିଙ୍ଗ ବଦଳାନ୍ତୁ"</string> + <string name="permlab_writeSettings" msgid="8057285063719277394">"ସିଷ୍ଟମ୍ ସେଟିଂସ ବଦଳାନ୍ତୁ"</string> <string name="permdesc_writeSettings" msgid="8293047411196067188">"ଆପ୍କୁ, ସିଷ୍ଟମର ସେଟିଙ୍ଗ ଡାଟା ବଦଳାଇବାକୁ ଦେଇଥାଏ। ହାନୀକାରକ ଆପ୍ ଦ୍ୱାରା ଆପଣଙ୍କ ସିଷ୍ଟମର କନଫିଗରେସନ୍ ଖରାପ ହୋଇପାରେ।"</string> <string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"ଆରମ୍ଭ ହେଲେ ଚଲାନ୍ତୁ"</string> <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"ସିଷ୍ଟମ୍ ବୁଟ୍ ଶେଷ ହେବା କ୍ଷଣି ଆପ୍ଟିକୁ ସ୍ୱତଃ ଆରମ୍ଭ ହେବାକୁ ଦେଇଥାଏ। ଏହା କାରଣରୁ ଟାବଲେଟଟ୍ଟି ଚାଲୁ ହେବାରେ ଅଧିକ ସମୟ ଲାଗିପାରେ ଏବଂ ଆପ୍ଟି ଲଗାତାର ଚାଲିବା ଦ୍ୱାରା ସମଗ୍ର ଟାବଲେଟଟ୍ ମନ୍ଥର ହୋଇଯାଇପାରେ।"</string> @@ -1118,7 +1118,7 @@ <string name="no" msgid="5122037903299899715">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string> <string name="dialog_alert_title" msgid="651856561974090712">"ଧ୍ୟାନଦିଅନ୍ତୁ"</string> <string name="loading" msgid="3138021523725055037">"ଲୋଡ୍ କରାଯାଉଛି…"</string> - <string name="capital_on" msgid="2770685323900821829">"ଅନ୍"</string> + <string name="capital_on" msgid="2770685323900821829">"ଚାଲୁ"</string> <string name="capital_off" msgid="7443704171014626777">"ଅଫ୍"</string> <string name="checked" msgid="9179896827054513119">"ଯାଞ୍ଚ ହୋଇଛି"</string> <string name="not_checked" msgid="7972320087569023342">"ଯାଞ୍ଚ ହୋଇନାହିଁ"</string> @@ -1170,7 +1170,7 @@ <string name="anr_application_process" msgid="4978772139461676184">"<xliff:g id="APPLICATION">%1$s</xliff:g> କାମ କରୁନାହିଁ"</string> <string name="anr_process" msgid="1664277165911816067">"<xliff:g id="PROCESS">%1$s</xliff:g> ପ୍ରୋସେସ୍ କାମ କରୁନାହିଁ"</string> <string name="force_close" msgid="9035203496368973803">"ଠିକ୍ ଅଛି"</string> - <string name="report" msgid="2149194372340349521">"ରିପୋର୍ଟ"</string> + <string name="report" msgid="2149194372340349521">"ରିପୋର୍ଟ କରନ୍ତୁ"</string> <string name="wait" msgid="7765985809494033348">"ଅପେକ୍ଷା କରନ୍ତୁ"</string> <string name="webpage_unresponsive" msgid="7850879412195273433">"ଏହି ପୃଷ୍ଠାଟି ଚାଲୁନାହିଁ।\n\nଆପଣ ଏହାକୁ ବନ୍ଦ କରିବେ କି?"</string> <string name="launch_warning_title" msgid="6725456009564953595">"ଆପ୍କୁ ରିଡାଇରେକ୍ଟ କରାଗଲା"</string> @@ -1253,7 +1253,7 @@ <string-array name="network_switch_type_name"> <item msgid="2255670471736226365">"ମୋବାଇଲ୍ ଡାଟା"</item> <item msgid="5520925862115353992">"ୱାଇ-ଫାଇ"</item> - <item msgid="1055487873974272842">"ବ୍ଲୁଟୂଥ୍"</item> + <item msgid="1055487873974272842">"ବ୍ଲୁଟୁଥ"</item> <item msgid="1616528372438698248">"ଇଥରନେଟ୍"</item> <item msgid="9177085807664964627">"VPN"</item> </string-array> @@ -1309,8 +1309,8 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ଡିବଗିଙ୍ଗ ସଂଯୁକ୍ତ ହୋଇଛି"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USBର ଡିବଗିଙ୍ଗ ସୁବିଧାକୁ ବନ୍ଦ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ଡିବଗିଙ୍ଗକୁ ଅକ୍ଷମ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ।"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ୱେୟାରଲେସ୍ ଡିବଗିଂ ସଂଯୋଗ କରାଯାଇଛି"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ୱାୟାରଲେସର ଡିବଗିଂକୁ ବନ୍ଦ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ୱାୟାରଲେସ୍ ଡିବଗିଂ ସଂଯୋଗ କରାଯାଇଛି"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ୱାୟାରଲେସ୍ ଡିବଗିଂକୁ ବନ୍ଦ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ୱାୟାରଲେସ୍ ଡିବଗିଂକୁ ଅକ୍ଷମ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ।"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"ଟେଷ୍ଟ ହାର୍ନେସ୍ ମୋଡ୍ ସକ୍ଷମ ଅଛି"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"ଟେଷ୍ଟ ହାର୍ନେସ୍ ମୋଡ୍ ଅକ୍ଷମ କରିବାକୁ ଏକ ଫ୍ୟାକ୍ଟରୀ ରିସେଟ୍ କରନ୍ତୁ।"</string> @@ -1770,7 +1770,7 @@ <string name="restr_pin_try_later" msgid="5897719962541636727">"ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string> <string name="immersive_cling_title" msgid="2307034298721541791">"ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ଦେଖାଯାଉଛି"</string> <string name="immersive_cling_description" msgid="7092737175345204832">"ବାହାରିବା ପାଇଁ, ଉପରୁ ତଳକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ।"</string> - <string name="immersive_cling_positive" msgid="7047498036346489883">"ବୁଝିଲି"</string> + <string name="immersive_cling_positive" msgid="7047498036346489883">"ବୁଝିଗଲି"</string> <string name="done_label" msgid="7283767013231718521">"ହୋଇଗଲା"</string> <string name="hour_picker_description" msgid="5153757582093524635">"ଘଣ୍ଟା ସର୍କୁଲାର୍ ସ୍ଲାଇଡର୍"</string> <string name="minute_picker_description" msgid="9029797023621927294">"ମିନିଟ୍ସ ସର୍କୁଲାର୍ ସ୍ଲାଇଡର୍"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ବାର୍ତ୍ତାଳାପ"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ଗୋଷ୍ଠୀ ବାର୍ତ୍ତାଳାପ"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ବ୍ୟକ୍ତିଗତ"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"କାର୍ଯ୍ୟ"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ବ୍ୟକ୍ତିଗତ ଭ୍ୟୁ"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 760b08b4a393..9a3ae250b157 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -290,7 +290,7 @@ <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"ਬੈਟਰੀ ਅਤੇ ਡਾਟਾ ਵਰਤੋਂ ਸਬੰਧੀ ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string> <string name="safeMode" msgid="8974401416068943888">"ਸੁਰੱਖਿਅਤ ਮੋਡ"</string> - <string name="android_system_label" msgid="5974767339591067210">"Android System"</string> + <string name="android_system_label" msgid="5974767339591067210">"Android ਸਿਸਟਮ"</string> <string name="user_owner_label" msgid="8628726904184471211">"ਨਿੱਜੀ ਪ੍ਰੋਫਾਈਲ ਵਰਤੋ"</string> <string name="managed_profile_label" msgid="7316778766973512382">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਰਤੋ"</string> <string name="permgrouplab_contacts" msgid="4254143639307316920">"ਸੰਪਰਕ"</string> @@ -545,7 +545,7 @@ <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ਅਧੂਰਾ ਫਿੰਗਰਪ੍ਰਿਟ ਮਿਲਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਪ੍ਰਕਿਰਿਆ ਨਹੀਂ ਕਰ ਸਕਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਗੰਦਾ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਇਸਨੂੰ ਸਾਫ਼ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> - <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"ਉਂਗਲ ਨੂੰ ਬਹੁਤ ਤੇਜ਼ ਲੈ ਜਾਇਆ ਗਿਆ. ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ."</string> + <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"ਉਂਗਲ ਨੂੰ ਬਹੁਤ ਤੇਜ਼ ਲੈ ਜਾਇਆ ਗਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"ਉਂਗਲ ਕਾਫ਼ੀ ਹੌਲੀ ਮੂਵ ਹੋਈ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string-array name="fingerprint_acquired_vendor"> </string-array> @@ -1183,7 +1183,7 @@ <string name="unsupported_display_size_show" msgid="980129850974919375">"ਹਮੇਸ਼ਾ ਦਿਖਾਓ"</string> <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ Android OS ਦਾ ਇੱਕ ਗੈਰ-ਅਨੁਕੂਲ ਵਰਜਨ ਬਣਾਇਆ ਗਿਆ ਸੀ ਅਤੇ ਅਣਕਿਆਸੇ ਤੌਰ \'ਤੇ ਵਿਹਾਰ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਦਾ ਇੱਕ ਅੱਪਡੇਟ ਕੀਤਾ ਹੋਇਆ ਵਰਜਨ ਉਪਲਬਧ ਹੋ ਸਕਦਾ ਹੈ।"</string> <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"ਹਮੇਸਾਂ ਦਿਖਾਓ"</string> - <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"ਅੱਪਡੇਟ ਦੀ ਜਾਂਚ ਕਰੋ"</string> + <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"ਅੱਪਡੇਟ ਲਈ ਜਾਂਚ ਕਰੋ"</string> <string name="smv_application" msgid="3775183542777792638">"ਐਪ <xliff:g id="APPLICATION">%1$s</xliff:g> (ਪ੍ਰਕਿਰਿਆ <xliff:g id="PROCESS">%2$s</xliff:g>) ਨੇ ਆਪਣੀ ਖੁਦ-ਲਾਗੂ ਕੀਤੀ ਸਟ੍ਰਿਕਟਮੋਡ ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕੀਤੀ ਹੈ।"</string> <string name="smv_process" msgid="1398801497130695446">"ਪ੍ਰਕਿਰਿਆ <xliff:g id="PROCESS">%1$s</xliff:g> ਨੇ ਆਪਣੀ ਖੁਦ-ਲਾਗੂ ਕੀਤੀ ਸਟ੍ਰਿਕਟਮੋਡ ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕੀਤੀ ਹੈ।"</string> <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"ਫ਼ੋਨ ਅੱਪਡੇਟ ਹੋ ਰਿਹਾ ਹੈ…"</string> @@ -1573,7 +1573,7 @@ <string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string> <string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", ਸੁਰੱਖਿਅਤ"</string> <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"ਪੈਟਰਨ ਭੁੱਲ ਗਏ"</string> - <string name="kg_wrong_pattern" msgid="1342812634464179931">"ਗ਼ਲਤ ਪੈਟਰਨ"</string> + <string name="kg_wrong_pattern" msgid="1342812634464179931">"ਗਲਤ ਪੈਟਰਨ"</string> <string name="kg_wrong_password" msgid="2384677900494439426">"ਗਲਤ ਪਾਸਵਰਡ"</string> <string name="kg_wrong_pin" msgid="3680925703673166482">"ਗਲਤ ਪਿੰਨ"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568"> @@ -1789,7 +1789,7 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ਠੀਕ ਹੈ"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Hey Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Ok Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string> <string name="battery_saver_description" msgid="7618492104632328184">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Hey Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ"</string> <string name="data_saver_description" msgid="4995164271550590517">"ਡਾਟਾ ਵਰਤੋਂ ਘਟਾਉਣ ਵਿੱਚ ਮਦਦ ਲਈ, ਡਾਟਾ ਸੇਵਰ ਕੁਝ ਐਪਾਂ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਟਾ ਭੇਜਣ ਜਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤਮਾਨ ਤੌਰ \'ਤੇ ਵਰਤੀ ਜਾ ਰਹੀ ਐਪ ਡਾਟਾ \'ਤੇ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਉਹ ਇੰਝ ਕਦੇ-ਕਦਾਈਂ ਕਰ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸ ਦਾ ਮਤਲਬ ਇਹ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਚਿੱਤਰ ਤਦ ਤੱਕ ਨਹੀਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕੀਤੇ ਜਾਂਦੇ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ \'ਤੇ ਟੈਪ ਨਹੀਂ ਕਰਦੇ।"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ਕੀ ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string> @@ -1889,7 +1889,7 @@ <string name="app_blocked_title" msgid="7353262160455028160">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ਇਹ ਐਪ Android ਦੇ ਕਿਸੇ ਵਧੇਰੇ ਪੁਰਾਣੇ ਵਰਜਨ ਲਈ ਬਣਾਈ ਗਈ ਸੀ ਅਤੇ ਸ਼ਾਇਦ ਸਹੀ ਢੰਗ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ। ਅੱਪਡੇਟਾਂ ਲਈ ਜਾਂਚ ਕਰੋ ਜਾਂ ਵਿਕਾਸਕਾਰ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"</string> - <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ਅੱਪਡੇਟ ਦੀ ਜਾਂਚ ਕਰੋ"</string> + <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ਅੱਪਡੇਟ ਲਈ ਜਾਂਚ ਕਰੋ"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"ਤੁਹਾਨੂੰ ਨਵੇਂ ਸੁਨੇਹੇ ਪ੍ਰਾਪਤ ਹੋਏ ਹਨ"</string> <string name="new_sms_notification_content" msgid="3197949934153460639">"ਦੇਖਣ ਲਈ SMS ਐਪ ਖੋਲ੍ਹੋ"</string> <string name="profile_encrypted_title" msgid="9001208667521266472">"ਕੁਝ ਪ੍ਰਕਾਰਜਾਤਮਕਤਾ ਸੀਮਤ ਹੋ ਸਕਦੀ ਹੈ"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ਗੱਲਬਾਤ"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ਗੁਰੱਪ ਗੱਲਬਾਤ"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ਨਿੱਜੀ"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ਕੰਮ"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ਵਿਅਕਤੀਗਤ ਦ੍ਰਿਸ਼"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index aa48ea6fa333..b2c760668a7e 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Rozmowa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Rozmowa grupowa"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobiste"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Do pracy"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Widok osobisty"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 3400cb1bb0c3..303a28f507ae 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1309,8 +1309,8 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Depuração USB conectada"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Toque para desativar a depuração USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecione para desativar a depuração USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração sem fio conectada"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração sem fio"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração por Wi-Fi conectada"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração por Wi-Fi"</string> <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecione para desativar a depuração sem fio."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modo Arcabouço de testes ativado"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Realize uma redefinição para configuração original para desativar o modo Arcabouço de testes."</string> @@ -2044,7 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa em grupo"</string> - <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> + <string name="unread_convo_overflow" msgid="920517615597353833">"+ de <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Visualização pessoal"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 6ad26b5476ca..f07f23511ce4 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1183,7 +1183,7 @@ <string name="unsupported_display_size_show" msgid="980129850974919375">"Mostrar sempre"</string> <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"A aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> foi concebida para uma versão incompatível do SO Android e pode ter um comportamento inesperado. Pode estar disponível uma versão atualizada da aplicação."</string> <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Mostrar sempre"</string> - <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Verificar se existem atualizações"</string> + <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Verificar atualizações"</string> <string name="smv_application" msgid="3775183542777792638">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode auto-imposta."</string> <string name="smv_process" msgid="1398801497130695446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode auto-imposta."</string> <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"O telemóvel está a atualizar…"</string> @@ -1628,7 +1628,7 @@ <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Manter premidas ambas as teclas de volume durante alguns segundos ativa o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, uma funcionalidade de acessibilidade. Esta pode alterar a forma como o seu dispositivo funciona.\n\nPode alterar este atalho para outra funcionalidade em Definições > Acessibilidade."</string> <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ativar"</string> <string name="accessibility_shortcut_off" msgid="3651336255403648739">"Não ativar"</string> - <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Pretende permitir que o serviço <xliff:g id="SERVICE">%1$s</xliff:g> tenha controlo total sobre o seu dispositivo?"</string> + <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Permitir que o serviço <xliff:g id="SERVICE">%1$s</xliff:g> tenha controlo total sobre o seu dispositivo?"</string> <string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"Se ativar o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, o dispositivo não utilizará o bloqueio de ecrã para otimizar a encriptação de dados."</string> <string name="accessibility_service_warning_description" msgid="291674995220940133">"O controlo total é adequado para aplicações que ajudam nas necessidades de acessibilidade, mas não para a maioria das aplicações."</string> <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Ver e controlar o ecrã"</string> @@ -1870,8 +1870,8 @@ <string name="importance_from_user" msgid="2782756722448800447">"Definiu a importância destas notificações."</string> <string name="importance_from_person" msgid="4235804979664465383">"É importante devido às pessoas envolvidas."</string> <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação de app personalizada"</string> - <string name="user_creation_account_exists" msgid="2239146360099708035">"Pretende permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string> - <string name="user_creation_adding" msgid="7305185499667958364">"Pretende permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> + <string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string> + <string name="user_creation_adding" msgid="7305185499667958364">"Permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string> <string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string> <string name="search_language_hint" msgid="7004225294308793583">"Intr. nome do idioma"</string> @@ -1889,7 +1889,7 @@ <string name="app_blocked_title" msgid="7353262160455028160">"A app não está disponível"</string> <string name="app_blocked_message" msgid="542972921087873023">"De momento, a app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicação foi concebida para uma versão mais antiga do Android e pode não funcionar corretamente. Experimente verificar se existem atualizações ou contacte o programador."</string> - <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Verificar se existem atualizações"</string> + <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Verificar atualizações"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Tem mensagens novas"</string> <string name="new_sms_notification_content" msgid="3197949934153460639">"Abra a aplicação de SMS para ver"</string> <string name="profile_encrypted_title" msgid="9001208667521266472">"Algumas funcionalidades limitadas"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 3400cb1bb0c3..303a28f507ae 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1309,8 +1309,8 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Depuração USB conectada"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Toque para desativar a depuração USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecione para desativar a depuração USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração sem fio conectada"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração sem fio"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração por Wi-Fi conectada"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração por Wi-Fi"</string> <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecione para desativar a depuração sem fio."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modo Arcabouço de testes ativado"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Realize uma redefinição para configuração original para desativar o modo Arcabouço de testes."</string> @@ -2044,7 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa em grupo"</string> - <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> + <string name="unread_convo_overflow" msgid="920517615597353833">"+ de <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Visualização pessoal"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 3dbc019fbb9e..1db09174c0eb 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1329,9 +1329,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Remedierea erorilor prin USB este conectată"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Atingeți pentru a dezactiva remedierea erorilor prin USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selectați pentru a dezactiva remedierea erorilor prin USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Remedierea erorilor prin wireless este activă"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Atingeți pentru a dezactiva remedierea erorilor prin wireless"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selectați pentru a dezactiva remedierea erorilor prin wireless."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Remedierea erorilor wireless este activă"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Atingeți pentru a dezactiva remedierea erorilor wireless"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selectați pentru a dezactiva remedierea erorilor wireless."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modul Set de testare este activat"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Reveniți la setările din fabrică pentru a dezactiva modul Set de testare."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Consola din serie este activată"</string> @@ -2078,8 +2078,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversație"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversație de grup"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Serviciu"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Afișarea conținutului personal"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 7f4f005e8efa..3a96385e0709 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -307,7 +307,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"доступ к календарю"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"отправлять и просматривать SMS-сообщения"</string> - <string name="permgrouplab_storage" msgid="1938416135375282333">"Файлы и медиафайлы"</string> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Файлы и медиаконтент"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"доступ к фото, мультимедиа и файлам на вашем устройстве"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Микрофон"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"записывать аудио"</string> @@ -548,7 +548,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"Не распознано"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Аутентификация отменена"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Укажите PIN-код, пароль или графический ключ"</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Отсканирована только часть пальца. Повторите попытку."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Отсканирована только часть отпечатка. Повторите попытку."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Не удалось распознать отпечаток. Повторите попытку."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Очистите сканер и повторите попытку."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Вы слишком быстро убрали палец. Повторите попытку."</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Чат"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групповой чат"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Личный"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Рабочий"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Просмотр личных данных"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index a2e556dd15a6..a131b181f516 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -2046,8 +2046,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"සංවාදය"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"සමූහ සංවාදය"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"පුද්ගලික"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"කාර්යාල"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"පෞද්ගලික දසුන"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 8039c1afa014..aec983c0d653 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -533,7 +533,7 @@ <string name="permlab_manageFingerprint" msgid="7432667156322821178">"spravovať hardvér na snímanie odtlačkov prstov"</string> <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Umožňuje aplikácii zavolať metódy, ktoré pridávajú a odstraňujú vzory odtlačkov prstov."</string> <string name="permlab_useFingerprint" msgid="1001421069766751922">"použiť hardvér na snímanie odtlačkov prstov"</string> - <string name="permdesc_useFingerprint" msgid="412463055059323742">"Umožňuje aplikácii používať na overenie totožnosti hardvér na snímanie odtlačkov prstov."</string> + <string name="permdesc_useFingerprint" msgid="412463055059323742">"Umožňuje aplikácii používať na overenie hardvér na odtlačky prstov"</string> <string name="permlab_audioWrite" msgid="8501705294265669405">"upravovať hudobnú zbierku"</string> <string name="permdesc_audioWrite" msgid="8057399517013412431">"Umožňuje aplikácii upravovať hudobnú zbierku."</string> <string name="permlab_videoWrite" msgid="5940738769586451318">"upravovať zbierku videí"</string> @@ -1835,8 +1835,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizoval správca"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Odstránil správca"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hej Google“.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hej Google“."</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hey Google“.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hey Google“."</string> <string name="data_saver_description" msgid="4995164271550590517">"S cieľom znížiť spotrebu dát bráni šetrič dát niektorým aplikáciám odosielať alebo prijímať dáta na pozadí. Aplikácia, ktorú práve používate, môže využívať dáta, ale možno to bude robiť menej často. Znamená to napríklad, že sa nezobrazia obrázky, kým na ne neklepnete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnúť šetrič dát?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnúť"</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konverzácia"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Skupinová konverzácia"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobné"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Práca"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Osobné zobrazenie"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 2d742ef21e4b..5aa0e02e860b 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -566,7 +566,7 @@ <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Preveč poskusov. Poskusite znova pozneje."</string> <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Preveč poskusov. Tipalo prstnih odtisov je onemogočeno."</string> <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Poskusite znova."</string> - <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ni včlanjenih prstnih odtisov."</string> + <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ni registriranih prstnih odtisov."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ta naprava nima tipala prstnih odtisov."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tipalo je začasno onemogočeno."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> @@ -578,8 +578,8 @@ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"uporaba strojne opreme za odklepanje z obrazom"</string> <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Aplikaciji omogoča uporabo strojne opreme za odklepanje z obrazom za preverj. pristnosti"</string> <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Odklepanje z obrazom"</string> - <string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Znova prijavite obraz"</string> - <string name="face_recalibrate_notification_content" msgid="892757485125249962">"Za izboljšanje prepoznavanja znova prijavite svoj obraz"</string> + <string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Znova registrirajte obraz"</string> + <string name="face_recalibrate_notification_content" msgid="892757485125249962">"Za izboljšanje prepoznavanja znova registrirajte svoj obraz"</string> <string name="face_acquired_insufficient" msgid="2150805835949162453">"Točnih podatkov o obrazu ni bilo mogoče zajeti. Poskusite znova."</string> <string name="face_acquired_too_bright" msgid="8070756048978079164">"Presvetlo. Poskusite z blažjo osvetlitvijo."</string> <string name="face_acquired_too_dark" msgid="252573548464426546">"Pretemno. Poskusite z močnejšo osvetlitvijo."</string> @@ -592,7 +592,7 @@ <string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Glejte bolj naravnost v napravo."</string> <string name="face_acquired_not_detected" msgid="2945945257956443257">"Obraz nastavite naravnost pred telefon."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Preveč se premikate. Držite telefon pri miru."</string> - <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Znova prijavite svoj obraz."</string> + <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Znova registrirajte svoj obraz."</string> <string name="face_acquired_too_different" msgid="4699657338753282542">"Obraza ni več mogoče prepoznati. Poskusite znova."</string> <string name="face_acquired_too_similar" msgid="7684650785108399370">"Preveč podobno, spremenite položaj."</string> <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Glejte malce bolj naravnost."</string> @@ -1560,7 +1560,7 @@ <string name="data_usage_limit_snoozed_body" msgid="545146591766765678">"Nastavljeno omejitev ste presegli za <xliff:g id="SIZE">%s</xliff:g>"</string> <string name="data_usage_restricted_title" msgid="126711424380051268">"Podatki v ozadju so omejeni"</string> <string name="data_usage_restricted_body" msgid="5338694433686077733">"Dotaknite se za odstr. omejitve."</string> - <string name="data_usage_rapid_title" msgid="2950192123248740375">"Visoka poraba mobilnih podatkov"</string> + <string name="data_usage_rapid_title" msgid="2950192123248740375">"Velik prenos mobilnih podatkov"</string> <string name="data_usage_rapid_body" msgid="3886676853263693432">"Vaše aplikacije so porabile več podatkov kot običajno"</string> <string name="data_usage_rapid_app_body" msgid="5425779218506513861">"Aplikacija <xliff:g id="APP">%s</xliff:g> je porabila več podatkov kot običajno"</string> <string name="ssl_certificate" msgid="5690020361307261997">"Varnostno potrdilo"</string> @@ -1837,7 +1837,7 @@ <string name="confirm_battery_saver" msgid="5247976246208245754">"V redu"</string> <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Funkcija varčevanja z energijo baterije tako podaljša čas delovanja baterije:\n·Vklopi temno temo,\n·izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«.\n\n"<annotation id="url">"Več o tem"</annotation></string> <string name="battery_saver_description" msgid="7618492104632328184">"Funkcija varčevanja z energijo baterije tako podaljša čas delovanja baterije:\n·Vklopi temno temo,\n·izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«."</string> - <string name="data_saver_description" msgid="4995164271550590517">"Zaradi zmanjševanja prenesene količine podatkov varčevanje s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string> + <string name="data_saver_description" msgid="4995164271550590517">"Zaradi zmanjševanja prenesene količine podatkov funkcija varčevanja s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Vklop varčevanja s podatki?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Vklop"</string> <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273"> @@ -2063,7 +2063,7 @@ <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutinsko informativno obvestilo o načinu delovanja"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumulator se bo morda izpraznil, preden ga običajno priključite na polnjenje"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Vklopilo se je varčevanje z energijo akumulatorja za podaljšanje časa delovanja akumulatorja"</string> - <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Varčevanje z energijo akumulatorja"</string> + <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Varčevanje z energijo baterije"</string> <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Varčevanje z energijo baterije je izklopljeno"</string> <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Baterija v telefonu je dovolj napolnjena. Funkcije niso več omejene."</string> <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Baterija v tabličnem računalniku je dovolj napolnjena. Funkcije niso več omejene."</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Pogovor"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Skupinski pogovor"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osebno"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Služba"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Pogled osebnega profila"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 460287d64fac..5e7351a38820 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Korrigjuesi i USB-së është i lidhur"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Trokit për të çaktivizuar korrigjimin e USB-së"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Përzgjidhe për të çaktivizuar korrigjimin e gabimeve të USB-së"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Korrigjimi me lidhjen pa tel është lidhur"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Trokit për të çaktivizuar korrigjimin me lidhjen pa tel"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Zgjidhe për të çaktivizuar korrigjimin me lidhjen pa tel"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Korrigjimi përmes Wi-Fi është lidhur"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Trokit për të çaktivizuar korrigjimin përmes Wi-Fi"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Zgjidh për të çaktivizuar korrigjimin përmes Wi-Fi"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modaliteti i lidhjes së testimit është aktivizuar"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Kryej një rivendosje në cilësimet e fabrikës për të çaktivizuar \"Modalitetin e lidhjes së testimit\"."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Paneli komandues i serisë është aktivizuar"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index d72c209714ba..995e949f72b3 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -701,7 +701,7 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"Захтева да сачувани подаци апликације буду шифровани."</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"Онемогућавање камера"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Спречите коришћење свих камера уређаја."</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Онемогућава функције закључавања екрана"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Онемогућавање функција закљ. екрана"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Спречава коришћење неких функција закључавања екрана."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Кућа"</item> @@ -2078,8 +2078,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Конверзација"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групна конверзација"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Пословни"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Лични приказ"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 9b7318bedfe0..54eec00de8a1 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konversation"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppkonversation"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personlig vy"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index f6a831aa7275..7e9a1ea541c0 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Mazungumzo"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Mazungumzo ya Kikundi"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Binafsi"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Kazini"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Mwonekano wa binafsi"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 43eca0e927fb..71352403b8ed 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -237,10 +237,8 @@ <string name="global_actions" product="default" msgid="6410072189971495460">"தொலைபேசி விருப்பங்கள்"</string> <string name="global_action_lock" msgid="6949357274257655383">"திரைப் பூட்டு"</string> <string name="global_action_power_off" msgid="4404936470711393203">"பவர் ஆஃப்"</string> - <!-- no translation found for global_action_power_options (1185286119330160073) --> - <skip /> - <!-- no translation found for global_action_restart (4678451019561687074) --> - <skip /> + <string name="global_action_power_options" msgid="1185286119330160073">"பவர் பட்டன்"</string> + <string name="global_action_restart" msgid="4678451019561687074">"மீண்டும் தொடங்கு"</string> <string name="global_action_emergency" msgid="1387617624177105088">"அவசர அழைப்பு"</string> <string name="global_action_bug_report" msgid="5127867163044170003">"பிழை அறிக்கை"</string> <string name="global_action_logout" msgid="6093581310002476511">"அமர்வை முடிக்கிறது"</string> @@ -440,8 +438,7 @@ <string name="permlab_camera" msgid="6320282492904119413">"படங்கள் மற்றும் வீடியோக்களை எடுத்தல்"</string> <string name="permdesc_camera" msgid="1354600178048761499">"இந்த ஆப்ஸ் எப்போது வேண்டுமானாலும் கேமராவைப் பயன்படுத்தி படங்களை எடுக்கலாம், வீடியோக்களை ரெக்கார்டு செய்யலாம்."</string> <string name="permlab_systemCamera" msgid="3642917457796210580">"படங்களையும் வீடியோக்களையும் எடுப்பதற்கு சிஸ்டம் கேமராக்களை அணுக ஆப்ஸையோ சேவையையோ அனுமதி"</string> - <!-- no translation found for permdesc_systemCamera (5938360914419175986) --> - <skip /> + <string name="permdesc_systemCamera" msgid="5938360914419175986">"இந்த முன்னுரிமை பெற்ற அல்லது சிஸ்டம் ஆப்ஸால் சிஸ்டம் கேமராவைப் பயன்படுத்தி எப்போது வேண்டுமானாலும் படங்களை எடுக்கவோ வீடியோக்களை ரெக்கார்டு செய்யவோ முடியும். android.permission.CAMERA அனுமதியும் ஆப்ஸிற்குத் தேவை"</string> <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"கேமரா சாதனங்கள் திறக்கப்படும்போதோ மூடப்படும்போதோ அது குறித்த கால்பேக்குகளைப் பெற ஒரு ஆப்ஸையோ சேவையையோ அனுமதிக்கவும்."</string> <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"எந்தக் கேமரா சாதனமும் (எந்த ஆப்ஸாலும்) திறக்கப்படும்போதோ மூடப்படும்போதோ இந்த ஆப்ஸால் கால்பேக்குகளைப் பெற முடியும்."</string> <string name="permlab_vibrate" msgid="8596800035791962017">"அதிர்வைக் கட்டுப்படுத்துதல்"</string> @@ -1312,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB பிழைதிருத்தம் இணைக்கப்பட்டது"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB பிழைதிருத்தத்தை ஆஃப் செய்ய தட்டவும்"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB பிழைதிருத்தத்தை முடக்க, தேர்ந்தெடுக்கவும்."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"வயர்லெஸ் பிழைதிருத்தம் இணைக்கப்பட்டது"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"வயர்லெஸ் பிழைதிருத்தத்தை ஆஃப் செய்ய தட்டவும்"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"வயர்லெஸ் பிழைதிருத்தத்தை முடக்க தேர்ந்தெடுக்கவும்."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"வைஃபை பிழைதிருத்தம் இணைக்கப்பட்டது"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"வைஃபை பிழைதிருத்தத்தை ஆஃப் செய்ய தட்டவும்"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"வைஃபை பிழைதிருத்தத்தை முடக்க தேர்ந்தெடுக்கவும்."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"\'தன்னியக்க சோதனைப்\' பயன்முறை இயக்கப்பட்டது"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"’தன்னியக்க சோதனைப்\' பயன்முறையை முடக்க ஆரம்பநிலைக்கு மீட்டமைக்கவும்."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"சீரியல் கன்சோல் இயக்கப்பட்டது"</string> @@ -1354,8 +1351,7 @@ <string name="ext_media_unsupported_notification_title" msgid="4358280700537030333">"ஆதரிக்கப்படாத <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"சாதனம் இந்த <xliff:g id="NAME">%s</xliff:g>ஐ ஆதரிக்கவில்லை. ஆதரிக்கப்படும் வடிவமைப்பில் அமைக்க, தட்டவும்."</string> <string name="ext_media_unsupported_notification_message" product="tv" msgid="7744945987775645685">"சாதனம் இந்த <xliff:g id="NAME">%s</xliff:g>ஐ ஆதரிக்கவில்லை. ஆதரிக்கப்படும் வடிவமைப்பில் அமைக்க, தேர்ந்தெடுக்கவும்."</string> - <!-- no translation found for ext_media_unsupported_notification_message (7657357085538772913) --> - <skip /> + <string name="ext_media_unsupported_notification_message" product="automotive" msgid="7657357085538772913">"இந்தச் சாதனத்தில் இந்த <xliff:g id="NAME">%s</xliff:g> ஆதரிக்கப்படவில்லை."</string> <string name="ext_media_badremoval_notification_title" msgid="4114625551266196872">"<xliff:g id="NAME">%s</xliff:g> அகற்றப்பட்டது"</string> <string name="ext_media_badremoval_notification_message" msgid="1986514704499809244">"உள்ளடக்கத்தை இழக்காமலிருக்க, அகற்றும் முன்பாக மீடியாவை வெளியேற்றவும்"</string> <string name="ext_media_nomedia_notification_title" msgid="742671636376975890">"<xliff:g id="NAME">%s</xliff:g> அகற்றப்பட்டது"</string> @@ -1623,24 +1619,15 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"பரிந்துரைத்த அளவை விட ஒலியை அதிகரிக்கவா?\n\nநீண்ட நேரத்திற்கு அதிகளவில் ஒலி கேட்பது கேட்கும் திறனைப் பாதிக்கலாம்."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"அணுகல்தன்மை ஷார்ட்கட்டைப் பயன்படுத்தவா?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ஷார்ட்கட் இயக்கத்தில் இருக்கும்போது ஒலியளவு பட்டன்கள் இரண்டையும் 3 வினாடிகளுக்கு அழுத்தினால் அணுகல்தன்மை அம்சம் இயக்கப்படும்."</string> - <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (8417489297036013065) --> - <skip /> - <!-- no translation found for accessibility_shortcut_multiple_service_warning (3740723309483706911) --> - <skip /> - <!-- no translation found for accessibility_shortcut_multiple_service_list (6935581470716541531) --> - <skip /> - <!-- no translation found for accessibility_shortcut_talkback_warning_title (3410100187167382427) --> - <skip /> - <!-- no translation found for accessibility_shortcut_talkback_warning (8412954203626349109) --> - <skip /> - <!-- no translation found for accessibility_shortcut_single_service_warning_title (2819109500943271385) --> - <skip /> - <!-- no translation found for accessibility_shortcut_single_service_warning (6363127705112844257) --> - <skip /> - <!-- no translation found for accessibility_shortcut_on (5463618449556111344) --> - <skip /> - <!-- no translation found for accessibility_shortcut_off (3651336255403648739) --> - <skip /> + <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"அணுகல்தன்மை அம்சங்களை ஆன் செய்யவா?"</string> + <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருந்தால் அணுகல்தன்மை அம்சங்கள் ஆன் செய்யப்படும். இதனால் உங்கள் சாதனம் வேலை செய்யும் முறை மாறக்கூடும்.\n\nதற்போதைய அம்சங்கள்:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nதேர்ந்தெடுத்த அம்சங்களை அமைப்புகள் > அணுகல்தன்மைக்குச் சென்று உங்களால் மாற்ற முடியும்."</string> + <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string> + <string name="accessibility_shortcut_talkback_warning_title" msgid="3410100187167382427">"TalkBackகை ஆன் செய்யவா?"</string> + <string name="accessibility_shortcut_talkback_warning" msgid="8412954203626349109">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருப்பதால் கண் பார்வையற்ற அல்லது பார்வைக் குறைபாடு உள்ளவர்களுக்கு உதவும் TalkBack எனும் ஸ்கிரீன் ரீடர் ஆன் ஆகும். உங்கள் சாதனம் வேலை செய்யும் முறையை TalkBack முழுமையாக மாற்றும்.\n\nஅமைப்புகள் > அணுகல்தன்மைக்குச் சென்று இந்த ஷார்ட்கட்டை வேறு அம்சத்திற்கு மாற்ற முடியும்."</string> + <string name="accessibility_shortcut_single_service_warning_title" msgid="2819109500943271385">"<xliff:g id="SERVICE">%1$s</xliff:g> ஐ ஆன் செய்யவா?"</string> + <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருப்பதால் அணுகல்தன்மை அம்சமான <xliff:g id="SERVICE">%1$s</xliff:g> ஆன் ஆகும். இதனால் உங்கள் சாதனம் வேலை செய்யும் முறை மாறக்கூடும்.\n\nஅமைப்புகள் > அணுகல்தன்மைக்குச் சென்று இந்த ஷார்ட்கட்டை வேறு அம்சத்திற்கு மாற்ற முடியும்."</string> + <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ஆன் செய்"</string> + <string name="accessibility_shortcut_off" msgid="3651336255403648739">"ஆன் செய்யாதே"</string> <string name="accessibility_enable_service_title" msgid="3931558336268541484">"உங்கள் சாதனத்தை முழுமையாகக் கட்டுப்படுத்த <xliff:g id="SERVICE">%1$s</xliff:g> சேவையை அனுமதிக்க வேண்டுமா?"</string> <string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"<xliff:g id="SERVICE">%1$s</xliff:g> சேவையை ஆன் செய்தால் தரவு என்க்ரிப்ஷனை மேம்படுத்த சாதனம் திரைப் பூட்டைப் பயன்படுத்தாது."</string> <string name="accessibility_service_warning_description" msgid="291674995220940133">"உங்களுக்கு உதவக்கூடிய ஆப்ஸுக்குக் தேவையான அணுகல்தன்மையை அளித்து முழுக் கட்டுப்பாட்டையும் அளிக்கலாம், ஆனால் பெரும்பாலான ஆப்ஸுக்கு இது பொருந்தாது."</string> @@ -1651,10 +1638,8 @@ <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"அனுமதி"</string> <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"நிராகரி"</string> <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"ஒரு அம்சத்தைப் பயன்படுத்த அதைத் தட்டவும்:"</string> - <!-- no translation found for accessibility_edit_shortcut_menu_button_title (239446795930436325) --> - <skip /> - <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (1077294237378645981) --> - <skip /> + <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"அணுகல்தன்மை பட்டன் மூலம் பயன்படுத்த விரும்பும் அம்சங்களைத் தேர்வுசெய்யுங்கள்"</string> + <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"ஒலியளவு விசை ஷார்ட்கட் மூலம் பயன்படுத்த விரும்பும் அம்சங்களைத் தேர்வுசெய்யுங்கள்"</string> <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ஆஃப் செய்யப்பட்டுள்ளது"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ஷார்ட்கட்களை மாற்று"</string> <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"முடிந்தது"</string> @@ -1662,23 +1647,15 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ஷார்ட்கட்டைப் பயன்படுத்து"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"வண்ணத்தை நேர் எதிராக மாற்றுதல்"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"வண்ணத் திருத்தம்"</string> - <!-- no translation found for accessibility_shortcut_enabling_service (5473495203759847687) --> - <skip /> - <!-- no translation found for accessibility_shortcut_disabling_service (8675244165062700619) --> - <skip /> + <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆன் செய்யப்பட்டது."</string> + <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆஃப் செய்யப்பட்டது."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐப் பயன்படுத்த 3 விநாடிகளுக்கு இரண்டு ஒலியளவு பட்டன்களையும் அழுத்திப் பிடிக்கவும்"</string> - <!-- no translation found for accessibility_button_prompt_text (8343213623338605305) --> - <skip /> - <!-- no translation found for accessibility_gesture_prompt_text (8742535972130563952) --> - <skip /> - <!-- no translation found for accessibility_gesture_3finger_prompt_text (5211827854510660203) --> - <skip /> - <!-- no translation found for accessibility_button_instructional_text (8853928358872550500) --> - <skip /> - <!-- no translation found for accessibility_gesture_instructional_text (9196230728837090497) --> - <skip /> - <!-- no translation found for accessibility_gesture_3finger_instructional_text (3425123684990193765) --> - <skip /> + <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"அணுகல்தன்மை பட்டனைத் தட்டுவதன் மூலம் பயன்படுத்த விரும்பும் அம்சத்தைத் தேர்ந்தெடுக்கவும்:"</string> + <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"அணுகல்தன்மை சைகைக்கான அம்சத்தைத் தேர்வுசெய்யவும் (இரண்டு விரல்களால் திரையின் கீழிருந்து மேல் நோக்கி ஸ்வைப் செய்யவும்):"</string> + <string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"அணுகல்தன்மை சைகைக்கான அம்சத்தைத் தேர்வுசெய்யவும் (மூன்று விரல்களால் திரையின் கீழிருந்து மேல் நோக்கி ஸ்வைப் செய்யவும்):"</string> + <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"அம்சங்களுக்கு இடையே மாற அணுகல்தன்மை பட்டனைத் தொட்டுப் பிடித்திருக்கவும்."</string> + <string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"அம்சங்களுக்கு இடையே மாற இரண்டு விரல்களால் மேல்நோக்கி ஸ்வைப் செய்து பிடித்திருக்கவும்."</string> + <string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"அம்சங்களுக்கு இடையே மாற மூன்று விரல்களால் மேல்நோக்கி ஸ்வைப் செய்து பிடித்திருக்கவும்."</string> <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"பெரிதாக்கல்"</string> <string name="user_switched" msgid="7249833311585228097">"நடப்பு பயனர் <xliff:g id="NAME">%1$s</xliff:g>."</string> <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>க்கு மாறுகிறது…"</string> @@ -2049,8 +2026,7 @@ <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ஃபைல்கள்</item> <item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> ஃபைல்</item> </plurals> - <!-- no translation found for chooser_no_direct_share_targets (1511722103987329028) --> - <skip /> + <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"பகிர்வதற்கு எவரும் பரிந்துரைக்கப்படவில்லை"</string> <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"ஆப்ஸ் பட்டியல்"</string> <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"இந்த ஆப்ஸிற்கு ரெக்கார்டு செய்வதற்கான அனுமதி வழங்கப்படவில்லை, எனினும் இந்த USB சாதனம் மூலம் ஆடியோவைப் பதிவுசெய்ய முடியும்."</string> <string name="accessibility_system_action_home_label" msgid="3234748160850301870">"முகப்பு"</string> @@ -2088,220 +2064,112 @@ <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"இந்த உள்ளடக்கத்தை எந்தவொரு பணி ஆப்ஸாலும் திறக்க முடியாது"</string> <string name="resolver_no_personal_apps_available_share" msgid="5639102815174748732">"இந்த உள்ளடக்கத்தை எந்தவொரு தனிப்பட்ட ஆப்ஸும் ஆதரிக்காது"</string> <string name="resolver_no_personal_apps_available_resolve" msgid="5120671970531446978">"இந்த உள்ளடக்கத்தை எந்தவொரு தனிப்பட்ட ஆப்ஸாலும் திறக்க முடியாது"</string> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_ENTRY (8050953231914637819) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_ENTRY (7164399703751688214) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_ENTRY (4447629474818217364) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_ENTRY (973059024670737358) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_ENTRY (4487435301206073787) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_PUK_ENTRY (768060297218652809) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ENTRY (7129527319490548930) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_PUK_ENTRY (2876126640607573252) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ENTRY (8952595089930109282) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_PUK_ENTRY (3013902515773728996) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_ENTRY (2974411408893410289) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_ENTRY (687618528751880721) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_ENTRY (6810596579655575381) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_ENTRY (2715929642540980259) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ENTRY (8557791623303951590) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_ENTRY (7382468767274580323) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_PUK_ENTRY (6730880791104286987) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_PUK_ENTRY (6432126539782267026) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_PUK_ENTRY (1730510161529488920) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ENTRY (3369885925003346830) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_PUK_ENTRY (9129139686191167829) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_PUK_ENTRY (2869929685874615358) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SPN_ENTRY (1238663472392741771) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SP_EHPLMN_ENTRY (3988705848553894358) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_ICCID_ENTRY (6186770686690993200) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_IMPI_ENTRY (7043865376145617024) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NS_SP_ENTRY (6144227308185112176) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_IN_PROGRESS (4233355366318061180) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_IN_PROGRESS (6742563947637715645) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_IN_PROGRESS (2033399698172403560) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_IN_PROGRESS (4795977251920732254) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_PUK_IN_PROGRESS (1090425878157254446) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_IN_PROGRESS (6476898876518094438) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_PUK_IN_PROGRESS (6006806734293747731) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_IN_PROGRESS (6546680489620881893) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_PUK_IN_PROGRESS (3506845511000727015) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_IN_PROGRESS (6709169861932992750) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_IN_PROGRESS (4013870911606478520) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_IN_PROGRESS (9032651188219523434) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_IN_PROGRESS (6584576506344491207) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_IN_PROGRESS (830981927724888114) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_IN_PROGRESS (7851790973098894802) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SPN_IN_PROGRESS (1149560739586960121) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SP_EHPLMN_IN_PROGRESS (5708964693522116025) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_ICCID_IN_PROGRESS (7288103122966483455) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_IMPI_IN_PROGRESS (4036752174056147753) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NS_SP_IN_PROGRESS (5089536274515338566) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_IN_PROGRESS (6737197986936251958) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_PUK_IN_PROGRESS (5658767775619998623) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_PUK_IN_PROGRESS (665978313257653727) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_PUK_IN_PROGRESS (3857142652251836850) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_PUK_IN_PROGRESS (2695664012344346788) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_IN_PROGRESS (2695678959963807782) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_PUK_IN_PROGRESS (1230605365926493599) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_ERROR (1924844017037151535) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_ERROR (3372797822292089708) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_ERROR (1878443146720411381) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_ERROR (7664778312218023192) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_ERROR (2472944311643350302) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_ERROR (828089694480999120) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_ERROR (17619001007092511) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_ERROR (807214229604353614) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_ERROR (8644184447744175747) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ERROR (3801002648649640407) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_ERROR (707397021218680753) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_PUK_ERROR (894358680773257820) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ERROR (352466878146726991) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_PUK_ERROR (7353389721907138671) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ERROR (2655263155490857920) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_PUK_ERROR (6903740900892931310) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_PUK_ERROR (5165901670447518687) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_PUK_ERROR (2856763216589267623) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_PUK_ERROR (817542684437829139) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ERROR (5178635064113393143) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_PUK_ERROR (5391587926974531008) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_PUK_ERROR (4895494864493315868) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SPN_ERROR (9017576601595353649) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SP_EHPLMN_ERROR (1116993930995545742) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_ICCID_ERROR (7559167306794441462) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_IMPI_ERROR (2782926139511136588) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NS_SP_ERROR (1890493954453456758) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUCCESS (4886243367747126325) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_SUCCESS (4053809277733513987) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_SUCCESS (8249342930499801740) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_SUCCESS (2339794542560381270) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_SUCCESS (6975608174152828954) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_SUCCESS (2846699261330463192) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_SUCCESS (5335414726057102801) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_SUCCESS (8868100318474971969) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_SUCCESS (6020936629725666932) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_SUCCESS (6944873647584595489) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_SUCCESS (2526483514124121988) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_PUK_SUCCESS (7662200333621664621) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_SUCCESS (2861223407953766632) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_PUK_SUCCESS (5345648571175243272) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_SUCCESS (3725278343103422466) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_PUK_SUCCESS (6998502547560297983) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_PUK_SUCCESS (8555433771162560361) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_PUK_SUCCESS (3555767296933606232) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_PUK_SUCCESS (6778051818199974237) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_PUK_SUCCESS (4080108758498911429) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_SUCCESS (7873675303000794343) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_PUK_SUCCESS (1763198215069819523) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SPN_SUCCESS (2053891977727320532) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SP_EHPLMN_SUCCESS (8146602361895007345) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_ICCID_SUCCESS (8058678548991999545) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_IMPI_SUCCESS (2545608067978550571) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NS_SP_SUCCESS (4352382949744625007) --> - <skip /> + <string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"சிம் நெட்வொர்க் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_ENTRY" msgid="7164399703751688214">"சிம் நெட்வொர்க் சப்செட் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_ENTRY" msgid="4447629474818217364">"கார்ப்பரேட் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_ENTRY" msgid="973059024670737358">"சிம் சேவை வழங்குநர் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_SIM_ENTRY" msgid="4487435301206073787">"சிம் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_ENTRY" msgid="768060297218652809">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ENTRY" msgid="7129527319490548930">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_ENTRY" msgid="2876126640607573252">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ENTRY" msgid="8952595089930109282">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_ENTRY" msgid="3013902515773728996">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_ENTRY" msgid="2974411408893410289">"RUIM network1 அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_ENTRY" msgid="687618528751880721">"RUIM network2 அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_ENTRY" msgid="6810596579655575381">"hrpd அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_ENTRY" msgid="2715929642540980259">"RUIM கார்ப்பரேட் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ENTRY" msgid="8557791623303951590">"RUIM சேவை வழங்குநர் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_ENTRY" msgid="7382468767274580323">"RUIM அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_ENTRY" msgid="6730880791104286987">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_ENTRY" msgid="6432126539782267026">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_ENTRY" msgid="1730510161529488920">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ENTRY" msgid="3369885925003346830">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_ENTRY" msgid="9129139686191167829">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_ENTRY" msgid="2869929685874615358">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_SIM_SPN_ENTRY" msgid="1238663472392741771">"SPN அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_ENTRY" msgid="3988705848553894358">"SP Equivalent Home PLMN அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_ICCID_ENTRY" msgid="6186770686690993200">"ICCID அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_IMPI_ENTRY" msgid="7043865376145617024">"IMPI அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_NS_SP_ENTRY" msgid="6144227308185112176">"நெட்வொர்க் சப்செட் சேவை வழங்குநர் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_IN_PROGRESS" msgid="4233355366318061180">"சிம் நெட்வொர்க் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_IN_PROGRESS" msgid="6742563947637715645">"சிம் நெட்வொர்க் சப்செட் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_IN_PROGRESS" msgid="2033399698172403560">"சிம் சேவை வழங்குநர் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_IN_PROGRESS" msgid="4795977251920732254">"கார்ப்பரேட் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_IN_PROGRESS" msgid="1090425878157254446">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_IN_PROGRESS" msgid="6476898876518094438">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_IN_PROGRESS" msgid="6006806734293747731">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_IN_PROGRESS" msgid="6546680489620881893">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_IN_PROGRESS" msgid="3506845511000727015">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SIM_IN_PROGRESS" msgid="6709169861932992750">"சிம் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_IN_PROGRESS" msgid="4013870911606478520">"RUIM network1 அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_IN_PROGRESS" msgid="9032651188219523434">"RUIM network2 அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_IN_PROGRESS" msgid="6584576506344491207">"hrpd அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_IN_PROGRESS" msgid="830981927724888114">"RUIM சேவை வழங்குநர் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_IN_PROGRESS" msgid="7851790973098894802">"RUIM கார்ப்பரேட் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SPN_IN_PROGRESS" msgid="1149560739586960121">"SPN அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_IN_PROGRESS" msgid="5708964693522116025">"SP Equivalent Home PLMN அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_ICCID_IN_PROGRESS" msgid="7288103122966483455">"ICCID அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_IMPI_IN_PROGRESS" msgid="4036752174056147753">"IMPI அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_NS_SP_IN_PROGRESS" msgid="5089536274515338566">"நெட்வொர்க் சப்செட் சேவை வழங்குநர் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_IN_PROGRESS" msgid="6737197986936251958">"RUIM அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_IN_PROGRESS" msgid="5658767775619998623">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_IN_PROGRESS" msgid="665978313257653727">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_IN_PROGRESS" msgid="3857142652251836850">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_IN_PROGRESS" msgid="2695664012344346788">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_IN_PROGRESS" msgid="2695678959963807782">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_IN_PROGRESS" msgid="1230605365926493599">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_ERROR" msgid="1924844017037151535">"சிம் நெட்வொர்க் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_ERROR" msgid="3372797822292089708">"சிம் நெட்வொர்க் சப்செட் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_ERROR" msgid="1878443146720411381">"சிம் சேவை வழங்குநர் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_ERROR" msgid="7664778312218023192">"கார்ப்பரேட் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SIM_ERROR" msgid="2472944311643350302">"சிம் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_ERROR" msgid="828089694480999120">"RUIM Network1 அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_ERROR" msgid="17619001007092511">"RUIM Network2 அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_ERROR" msgid="807214229604353614">"hrpd அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_ERROR" msgid="8644184447744175747">"RUIM கார்ப்பரேட் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ERROR" msgid="3801002648649640407">"RUIM சேவை வழங்குநர் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_ERROR" msgid="707397021218680753">"RUIM அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_ERROR" msgid="894358680773257820">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ERROR" msgid="352466878146726991">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_ERROR" msgid="7353389721907138671">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ERROR" msgid="2655263155490857920">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_ERROR" msgid="6903740900892931310">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_ERROR" msgid="5165901670447518687">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_ERROR" msgid="2856763216589267623">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_ERROR" msgid="817542684437829139">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ERROR" msgid="5178635064113393143">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_ERROR" msgid="5391587926974531008">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_ERROR" msgid="4895494864493315868">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SPN_ERROR" msgid="9017576601595353649">"SPN அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_ERROR" msgid="1116993930995545742">"SP Equivalent Home PLMN அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_ICCID_ERROR" msgid="7559167306794441462">"ICCID அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_IMPI_ERROR" msgid="2782926139511136588">"IMPI அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_NS_SP_ERROR" msgid="1890493954453456758">"நெட்வொர்க் சப்செட் சேவை வழங்குநர் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUCCESS" msgid="4886243367747126325">"சிம் நெட்வொர்க் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_SUCCESS" msgid="4053809277733513987">"சிம் நெட்வொர்க் சப்செட் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_SUCCESS" msgid="8249342930499801740">"சிம் சேவை வழங்குநர் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_SUCCESS" msgid="2339794542560381270">"கார்ப்பரேட் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SIM_SUCCESS" msgid="6975608174152828954">"சிம் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_SUCCESS" msgid="2846699261330463192">"RUIM Network1 அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_SUCCESS" msgid="5335414726057102801">"RUIM Network2 அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_SUCCESS" msgid="8868100318474971969">"hrpd அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_SUCCESS" msgid="6020936629725666932">"RUIM சேவை வழங்குநர் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_SUCCESS" msgid="6944873647584595489">"RUIM கார்ப்பரேட் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_SUCCESS" msgid="2526483514124121988">"RUIM அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_SUCCESS" msgid="7662200333621664621">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_SUCCESS" msgid="2861223407953766632">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_SUCCESS" msgid="5345648571175243272">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="3725278343103422466">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_SUCCESS" msgid="6998502547560297983">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_SUCCESS" msgid="8555433771162560361">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_SUCCESS" msgid="3555767296933606232">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_SUCCESS" msgid="6778051818199974237">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_SUCCESS" msgid="4080108758498911429">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="7873675303000794343">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_SUCCESS" msgid="1763198215069819523">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SPN_SUCCESS" msgid="2053891977727320532">"SPN அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_SUCCESS" msgid="8146602361895007345">"SP Equivalent Home PLMN அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"நெட்வொர்க் சப்செட் சேவை வழங்குநர் அன்லாக் செயல்படுத்தப்பட்டது."</string> </resources> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index f9e95a6ed9c4..e0990a2740e7 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -293,7 +293,7 @@ <string name="android_system_label" msgid="5974767339591067210">"Android సిస్టమ్"</string> <string name="user_owner_label" msgid="8628726904184471211">"వ్యక్తిగత ప్రొఫైల్కి మార్చు"</string> <string name="managed_profile_label" msgid="7316778766973512382">"కార్యాలయ ప్రొఫైల్కి మార్చు"</string> - <string name="permgrouplab_contacts" msgid="4254143639307316920">"పరిచయాలు"</string> + <string name="permgrouplab_contacts" msgid="4254143639307316920">"కాంటాక్ట్లు"</string> <string name="permgroupdesc_contacts" msgid="9163927941244182567">"మీ పరిచయాలను యాక్సెస్ చేయడానికి"</string> <string name="permgrouplab_location" msgid="1858277002233964394">"స్థానం"</string> <string name="permgroupdesc_location" msgid="1995955142118450685">"ఈ పరికర స్థానాన్ని యాక్సెస్ చేయడానికి"</string> @@ -571,7 +571,7 @@ <string name="permdesc_manageFace" msgid="6204569688492710471">"వినియోగం కోసం ముఖ టెంప్లేట్లను జోడించే మరియు తొలగించే పద్ధతులను అమలు చేయడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ముఖంతో అన్లాక్ చేయగల హార్డ్వేర్ వినియోగం"</string> <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"ప్రమాణీకరణ కోసం ముఖంతో అన్లాక్ చేయగల హార్డ్వేర్ను ఉపయోగించడానికి యాప్ను అనుమతిస్తుంది"</string> - <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ముఖంతో అన్లాక్"</string> + <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ఫేస్ అన్లాక్"</string> <string name="face_recalibrate_notification_title" msgid="5944930528030496897">"మీ ముఖాన్ని తిరిగి నమోదు చేయండి"</string> <string name="face_recalibrate_notification_content" msgid="892757485125249962">"గుర్తింపును మెరుగుపరచడానికి, దయచేసి మీ ముఖంను తిరిగి నమోదు చేసుకోండి"</string> <string name="face_acquired_insufficient" msgid="2150805835949162453">"ముఖం డేటా సరిగ్గా రాలేదు. మళ్లీ ప్రయత్నించండి."</string> @@ -905,7 +905,7 @@ <string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"అన్లాక్ ప్రాంతాన్ని విస్తరింపజేయండి."</string> <string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"స్లయిడ్ అన్లాక్."</string> <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"ఆకృతి అన్లాక్."</string> - <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ముఖంతో అన్లాక్."</string> + <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ఫేస్ అన్లాక్."</string> <string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"పిన్ అన్లాక్."</string> <string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim పిన్ అన్లాక్."</string> <string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim Puk అన్లాక్."</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"సంభాషణ"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"గ్రూప్ సంభాషణ"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"వ్యక్తిగతం"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"కార్యాలయం"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"వ్యక్తిగత వీక్షణ"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 041423d9b0d8..83f7a1bcf6ab 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -567,11 +567,11 @@ <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ไอคอนลายนิ้วมือ"</string> - <string name="permlab_manageFace" msgid="4569549381889283282">"จัดการฮาร์ดแวร์ Face Unlock"</string> + <string name="permlab_manageFace" msgid="4569549381889283282">"จัดการฮาร์ดแวร์การปลดล็อกด้วยใบหน้า"</string> <string name="permdesc_manageFace" msgid="6204569688492710471">"อนุญาตให้แอปเรียกใช้วิธีเพิ่มและลบเทมเพลตใบหน้าสำหรับการใช้งาน"</string> - <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ใช้ฮาร์ดแวร์ Face Unlock"</string> - <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"อนุญาตให้แอปใช้ฮาร์ดแวร์ Face Unlock เพื่อตรวจสอบสิทธิ์"</string> - <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face Unlock"</string> + <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ใช้ฮาร์ดแวร์การปลดล็อกด้วยใบหน้า"</string> + <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"อนุญาตให้แอปใช้ฮาร์ดแวร์การปลดล็อกด้วยใบหน้าเพื่อตรวจสอบสิทธิ์"</string> + <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ปลดล็อกด้วยใบหน้า"</string> <string name="face_recalibrate_notification_title" msgid="5944930528030496897">"ลงทะเบียนใบหน้าอีกครั้ง"</string> <string name="face_recalibrate_notification_content" msgid="892757485125249962">"โปรดลงทะเบียนใบหน้าอีกครั้งเพื่อปรับปรุงการจดจำ"</string> <string name="face_acquired_insufficient" msgid="2150805835949162453">"บันทึกข้อมูลใบหน้าที่ถูกต้องไม่ได้ ลองอีกครั้ง"</string> @@ -597,15 +597,15 @@ <string-array name="face_acquired_vendor"> </string-array> <string name="face_error_hw_not_available" msgid="5085202213036026288">"ยืนยันใบหน้าไม่ได้ ฮาร์ดแวร์ไม่พร้อมใช้งาน"</string> - <string name="face_error_timeout" msgid="522924647742024699">"ลองใช้ Face Unlock อีกครั้ง"</string> + <string name="face_error_timeout" msgid="522924647742024699">"ลองใช้การปลดล็อกด้วยใบหน้าอีกครั้ง"</string> <string name="face_error_no_space" msgid="5649264057026021723">"จัดเก็บข้อมูลใบหน้าใหม่ไม่ได้ ลบข้อมูลเก่าออกไปก่อน"</string> <string name="face_error_canceled" msgid="2164434737103802131">"ยกเลิกการดำเนินการกับใบหน้าแล้ว"</string> - <string name="face_error_user_canceled" msgid="8553045452825849843">"ผู้ใช้ยกเลิกการใช้ Face Unlock"</string> + <string name="face_error_user_canceled" msgid="8553045452825849843">"ผู้ใช้ยกเลิกการใช้การปลดล็อกด้วยใบหน้า"</string> <string name="face_error_lockout" msgid="7864408714994529437">"ดำเนินการหลายครั้งเกินไป ลองอีกครั้งในภายหลัง"</string> - <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ลองหลายครั้งเกินไป ปิดใช้ Face Unlock แล้ว"</string> + <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ลองหลายครั้งเกินไป ปิดใช้การปลดล็อกด้วยใบหน้าแล้ว"</string> <string name="face_error_unable_to_process" msgid="5723292697366130070">"ยืนยันใบหน้าไม่ได้ ลองอีกครั้ง"</string> - <string name="face_error_not_enrolled" msgid="7369928733504691611">"คุณยังไม่ได้ตั้งค่า Face Unlock"</string> - <string name="face_error_hw_not_present" msgid="1070600921591729944">"อุปกรณ์นี้ไม่รองรับ Face Unlock"</string> + <string name="face_error_not_enrolled" msgid="7369928733504691611">"คุณยังไม่ได้ตั้งค่าการปลดล็อกด้วยใบหน้า"</string> + <string name="face_error_hw_not_present" msgid="1070600921591729944">"อุปกรณ์นี้ไม่รองรับการปลดล็อกด้วยใบหน้า"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string> <string name="face_name_template" msgid="3877037340223318119">"ใบหน้า <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> @@ -835,7 +835,7 @@ <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ลองอีกครั้ง"</string> <string name="lockscreen_password_wrong" msgid="8605355913868947490">"ลองอีกครั้ง"</string> <string name="lockscreen_storage_locked" msgid="634993789186443380">"ปลดล็อกฟีเจอร์และข้อมูลทั้งหมด"</string> - <string name="faceunlock_multiple_failures" msgid="681991538434031708">"มีความพยายามที่จะใช้ Face Unlock เกินขีดจำกัด"</string> + <string name="faceunlock_multiple_failures" msgid="681991538434031708">"ลองใช้การปลดล็อกด้วยใบหน้าเกินจำนวนครั้งที่กำหนดแล้ว"</string> <string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"ไม่มีซิมการ์ด"</string> <string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"ไม่มีซิมการ์ดในแท็บเล็ต"</string> <string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"ไม่มีซิมการ์ดในอุปกรณ์ Android TV"</string> @@ -1789,8 +1789,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"อัปเดตโดยผู้ดูแลระบบ"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ลบโดยผู้ดูแลระบบ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ตกลง"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Hey Google”\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Hey Google”"</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Ok Google”\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Ok Google”"</string> <string name="data_saver_description" msgid="4995164271550590517">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลโดยการใช้อินเทอร์เน็ตอยู่เบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงอินเทอร์เน็ตได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"เปิด"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"การสนทนา"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"บทสนทนากลุ่ม"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ส่วนตัว"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"งาน"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"มุมมองส่วนตัว"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 0b1ee6549424..773020b0c88e 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Pag-uusap"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Panggrupong Pag-uusap"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabaho"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personal na view"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 5861589e5ff8..69f41dd9a52b 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Görüşme"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grup Görüşmesi"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Kişisel"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Kişisel görünüm"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 0cb185c11533..c9d29a224329 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1349,9 +1349,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Налагодження USB підключено"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Торкніться, щоб вимкнути налагоджувач USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Виберіть, щоб вимкнути налагодження за USB"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Бездротове налагодження підключено"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Натисніть, щоб вимкнути бездротове налагодження"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Виберіть, щоб вимкнути бездротове налагодження."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Налагодження через Wi-Fi активне"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Натисніть, щоб вимкнути налагодження через Wi-Fi"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Виберіть, щоб вимкнути налагодження через Wi-Fi."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Увімкнено режим автоматизованого тестування"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Щоб вимкнути режим автоматизованого тестування, відновіть заводські налаштування."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Послідовну консоль увімкнено"</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Чат"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Груповий чат"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Особисте"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Робоче"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Особистий перегляд"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index e71789802ba1..216f62425d81 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -698,8 +698,8 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"مطالبہ کریں کہ اسٹور کردہ ایپ کا ڈیٹا مرموز کیا جائے۔"</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"کیمروں کو غیر فعال کریں"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"سبھی آلے کے کیمروں کا استعمال روکیں۔"</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"کچھ سکرین قفل خصوصیات غیر فعال کریں"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"اسکرین قفل کی کچھ خصوصیات کے استعمال کو روکیں۔"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"کچھ اسکرین لاک خصوصیات غیرفعال کریں"</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"اسکرین لاک کی کچھ خصوصیات کے استعمال کو روکیں۔"</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"گھر"</item> <item msgid="7740243458912727194">"موبائل"</item> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"گفتگو"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"گروپ گفتگو"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"+<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ذاتی"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"دفتر"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ذاتی ملاحظہ"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index d2dde7104834..a1c9faa7d2f5 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB orqali nosozliklarni aniqlash"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB orqali nosozliklarni aniqlashni faolsizlantirish uchun bosing"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB orqali nosozliklarni tuzatishni o‘chirib qo‘yish uchun bosing."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Simsiz tarmoq nosozliklari faqat ulangan tarmoqda aniqlanadi"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Simsiz tarmoqdagi nosozliklar aniqlanishini faolsizlantirish uchun bosing"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Simsiz tarmoqdagi nosozliklar aniqlanishini faolsizlantirish uchun bosing."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wi-Fi orqali debagging yoqildi"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Wi-Fi orqali debagging uzilishi uchun bosing"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Wi-Fi orqali debaggingni faolsizlantirish uchun bosing."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Xavfsizlik sinovi rejimi yoqildi"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Xavfsizlik sinovi rejimini faolsizlantirish uchun zavod sozlamalariga qaytaring."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Davomiy port terminali yoqildi"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index cbe131fca08c..7e24e64199bc 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1299,7 +1299,7 @@ <string name="usb_supplying_notification_title" msgid="5378546632408101811">"Đang sạc thiết bị được kết nối qua USB"</string> <string name="usb_mtp_notification_title" msgid="1065989144124499810">"Đã bật truyền tệp qua USB"</string> <string name="usb_ptp_notification_title" msgid="5043437571863443281">"Đã bật chế độ PTP qua USB"</string> - <string name="usb_tether_notification_title" msgid="8828527870612663771">"Đã bật chia sẻ kết nối qua USB"</string> + <string name="usb_tether_notification_title" msgid="8828527870612663771">"Đã bật tính năng chia sẻ Internet qua USB"</string> <string name="usb_midi_notification_title" msgid="7404506788950595557">"Đã bật chế độ MIDI qua USB"</string> <string name="usb_accessory_notification_title" msgid="1385394660861956980">"Đã kết nối phụ kiện USB"</string> <string name="usb_notification_message" msgid="4715163067192110676">"Nhấn để biết thêm tùy chọn."</string> @@ -1573,7 +1573,7 @@ <string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string> <string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", an toàn"</string> <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"Đã quên hình"</string> - <string name="kg_wrong_pattern" msgid="1342812634464179931">"Hình không chính xác"</string> + <string name="kg_wrong_pattern" msgid="1342812634464179931">"Hình mở khóa không chính xác"</string> <string name="kg_wrong_password" msgid="2384677900494439426">"Mật khẩu sai"</string> <string name="kg_wrong_pin" msgid="3680925703673166482">"PIN sai"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568"> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Cuộc trò chuyện"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Cuộc trò chuyện nhóm"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Cá nhân"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Cơ quan"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Chế độ xem cá nhân"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 5f921bc65bdf..18eb7d998aac 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -681,7 +681,7 @@ <string name="policylab_resetPassword" msgid="214556238645096520">"更改锁屏方式"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"更改锁屏方式。"</string> <string name="policylab_forceLock" msgid="7360335502968476434">"锁定屏幕"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"控制屏幕锁定的方式和时间。"</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"控制锁屏的方式和时间。"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"清除所有数据"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"恢复出厂设置时,系统会在不发出警告的情况下清除平板电脑上的数据。"</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"不事先发出警告就以恢复出厂设置的方式清空 Android TV 设备中的数据。"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"对话"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"群组对话"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"个人"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"个人视图"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index d85b271a37c6..e6d539541b63 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1561,7 +1561,7 @@ <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"螢幕投放到裝置"</string> <string name="media_route_chooser_searching" msgid="6119673534251329535">"正在搜尋裝置…"</string> <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"設定"</string> - <string name="media_route_controller_disconnect" msgid="7362617572732576959">"停止連接"</string> + <string name="media_route_controller_disconnect" msgid="7362617572732576959">"中斷連線"</string> <string name="media_route_status_scanning" msgid="8045156315309594482">"正在掃瞄…"</string> <string name="media_route_status_connecting" msgid="5845597961412010540">"正在連線..."</string> <string name="media_route_status_available" msgid="1477537663492007608">"可用"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"對話"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"群組對話"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"公司"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"個人檢視模式"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 88301a9cc41a..59b5cdcbd90d 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"對話"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"群組對話"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"個人檢視模式"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 340dd4d7d89a..fba237936f6e 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3397,7 +3397,7 @@ <!-- Inactivity threshold (in milliseconds) used in JobScheduler. JobScheduler will consider the device to be "idle" after being inactive for this long. --> - <integer name="config_jobSchedulerInactivityIdleThreshold">4260000</integer> + <integer name="config_jobSchedulerInactivityIdleThreshold">1860000</integer> <!-- The alarm window (in milliseconds) that JobScheduler uses to enter the idle state --> <integer name="config_jobSchedulerIdleWindowSlop">300000</integer> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 7edb86b2db18..e4aef861198a 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -820,7 +820,9 @@ <dimen name="resolver_empty_state_height">212dp</dimen> <dimen name="resolver_empty_state_height_with_tabs">268dp</dimen> <dimen name="resolver_max_collapsed_height">192dp</dimen> - <dimen name="resolver_max_collapsed_height_with_tabs">248dp</dimen> + <dimen name="resolver_max_collapsed_height_with_tabs">268dp</dimen> + <dimen name="resolver_max_collapsed_height_with_default">144dp</dimen> + <dimen name="resolver_max_collapsed_height_with_default_with_tabs">300dp</dimen> <dimen name="resolver_tab_text_size">14sp</dimen> <dimen name="chooser_action_button_icon_size">18dp</dimen> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 1c851d6a89f2..717f326d0378 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3233,12 +3233,13 @@ <java-symbol type="string" name="accessibility_enable_service_title" /> <java-symbol type="string" name="accessibility_enable_service_encryption_warning" /> + <java-symbol type="layout" name="accessibility_shortcut_chooser_item" /> + <java-symbol type="id" name="accessibility_shortcut_target_checkbox" /> + <java-symbol type="id" name="accessibility_shortcut_target_icon" /> + <java-symbol type="id" name="accessibility_shortcut_target_label" /> + <java-symbol type="id" name="accessibility_shortcut_target_switch_item" /> + <!-- Accessibility Button --> - <java-symbol type="layout" name="accessibility_button_chooser_item" /> - <java-symbol type="id" name="accessibility_button_target_checkbox" /> - <java-symbol type="id" name="accessibility_button_target_icon" /> - <java-symbol type="id" name="accessibility_button_target_label" /> - <java-symbol type="id" name="accessibility_button_target_switch_item" /> <java-symbol type="string" name="accessibility_magnification_chooser_text" /> <java-symbol type="string" name="edit_accessibility_shortcut_menu_button" /> <java-symbol type="string" name="done_accessibility_shortcut_menu_button" /> @@ -3496,6 +3497,7 @@ <java-symbol type="id" name="clip_children_set_tag" /> <java-symbol type="id" name="clip_to_padding_tag" /> <java-symbol type="id" name="clip_children_tag" /> + <java-symbol type="id" name="bubble_button" /> <java-symbol type="dimen" name="messaging_avatar_size" /> <java-symbol type="dimen" name="messaging_group_sending_progress_size" /> <java-symbol type="dimen" name="messaging_image_rounding" /> @@ -3937,6 +3939,7 @@ <java-symbol type="dimen" name="resolver_empty_state_height" /> <java-symbol type="dimen" name="resolver_empty_state_height_with_tabs" /> <java-symbol type="dimen" name="resolver_max_collapsed_height_with_tabs" /> + <java-symbol type="dimen" name="resolver_max_collapsed_height_with_default_with_tabs" /> <java-symbol type="bool" name="resolver_landscape_phone" /> <java-symbol type="dimen" name="resolver_tab_text_size" /> diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 8d51a6000086..1e16ee052899 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -72,6 +72,7 @@ android_test { ":BinderDeathRecipientHelperApp1", ":BinderDeathRecipientHelperApp2", ], + required: ["com.android.cts.helpers.aosp"], } // Rules to copy all the test apks to the intermediate raw resource directory diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml index ed9d3f54ef3d..04952bdfa389 100644 --- a/core/tests/coretests/AndroidTest.xml +++ b/core/tests/coretests/AndroidTest.xml @@ -24,6 +24,9 @@ <option name="test-file-name" value="BinderDeathRecipientHelperApp1.apk" /> <option name="test-file-name" value="BinderDeathRecipientHelperApp2.apk" /> </target_preparer> + + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DeviceInteractionHelperInstaller" /> + <option name="test-tag" value="FrameworksCoreTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.frameworks.coretests" /> diff --git a/core/tests/coretests/src/android/app/WindowContextTest.java b/core/tests/coretests/src/android/app/WindowContextTest.java new file mode 100644 index 000000000000..630e16ac80d4 --- /dev/null +++ b/core/tests/coretests/src/android/app/WindowContextTest.java @@ -0,0 +1,74 @@ +/* + * 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 android.app; + +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.content.Context; +import android.hardware.display.DisplayManager; +import android.os.IBinder; +import android.platform.test.annotations.Presubmit; +import android.view.Display; +import android.view.IWindowManager; +import android.view.WindowManagerGlobal; + +import androidx.test.filters.FlakyTest; +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link WindowContext} + * + * <p>Build/Install/Run: + * atest FrameworksCoreTests:WindowContextTest + * + * <p>This test class is a part of Window Manager Service tests and specified in + * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. + */ +@FlakyTest(bugId = 150812449, detail = "Remove after confirmed it's stable.") +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class WindowContextTest { + @Test + public void testWindowContextRelease_doRemoveWindowToken() throws Throwable { + final Context instContext = InstrumentationRegistry.getInstrumentation() + .getTargetContext(); + final Display display = instContext.getSystemService(DisplayManager.class) + .getDisplay(DEFAULT_DISPLAY); + final Context context = instContext.createDisplayContext(display); + final WindowContext windowContext = new WindowContext(context, TYPE_APPLICATION_OVERLAY, + null /* options */); + + final IBinder token = windowContext.getActivityToken(); + + final IWindowManager wms = WindowManagerGlobal.getWindowManagerService(); + assertTrue("Token must be registered to WMS", wms.isWindowToken(token)); + + windowContext.release(); + + assertFalse("Token must be unregistered to WMS", wms.isWindowToken(token)); + } +} diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index f4fbefe9dde4..3766cf72d99e 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -63,7 +63,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; -import java.util.List; import java.util.Map; /** @@ -213,6 +212,7 @@ public class TransactionParcelTests { int procState = 4; Bundle bundle = new Bundle(); bundle.putString("key", "value"); + bundle.putParcelable("data", new ParcelableData(1)); PersistableBundle persistableBundle = new PersistableBundle(); persistableBundle.putInt("k", 4); @@ -374,6 +374,47 @@ public class TransactionParcelTests { mParcel.setDataPosition(0); } + /** + * The parcelable class to make sure that when comparing the {@link LaunchActivityItem} or + * getting its hash code, the bundle is not unparceled. System shouldn't touch the data from + * application, otherwise it will cause exception as: + * android.os.BadParcelableException: ClassNotFoundException when unmarshalling: + * android.app.servertransaction.TransactionParcelTests$ParcelableData". + */ + public static class ParcelableData implements Parcelable { + int mValue; + + ParcelableData() {} + + ParcelableData(int value) { + mValue = value; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mValue); + } + + public static final Creator<ParcelableData> CREATOR = new Creator<ParcelableData>() { + @Override + public ParcelableData createFromParcel(Parcel source) { + final ParcelableData data = new ParcelableData(); + data.mValue = source.readInt(); + return data; + } + + @Override + public ParcelableData[] newArray(int size) { + return new ParcelableData[size]; + } + }; + } + /** Stub implementation of IApplicationThread that can be presented as {@link Binder}. */ class StubAppThread extends android.app.IApplicationThread.Stub { diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java index 94d85e63cc5f..4dd4d1c7bd12 100644 --- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java +++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java @@ -41,6 +41,7 @@ import android.print.test.services.PrintServiceCallbacks; import android.print.test.services.PrinterDiscoverySessionCallbacks; import android.print.test.services.StubbablePrinterDiscoverySession; import android.printservice.recommendation.IRecommendationsChangeListener; +import android.support.test.uiautomator.UiDevice; import androidx.test.filters.LargeTest; import androidx.test.filters.MediumTest; @@ -71,6 +72,10 @@ public class IPrintManagerParametersTest extends BasePrintTest { private IPrintManager mIPrintManager; + public static UiDevice getUiDevice() { + return UiDevice.getInstance(getInstrumentation()); + } + /** * Create a new IPrintManagerParametersTest and setup basic fields. */ diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index cbb379bf8207..d432dda4a1be 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -696,8 +696,7 @@ public class InsetsControllerTest { // Simulate binder behavior by copying SurfaceControl. Otherwise, InsetsController will // attempt to release mLeash directly. - SurfaceControl copy = new SurfaceControl(); - copy.copyFrom(mLeash); + SurfaceControl copy = new SurfaceControl(mLeash); return new InsetsSourceControl(type, copy, new Point()); } diff --git a/core/tests/coretests/src/android/view/WindowMetricsTest.java b/core/tests/coretests/src/android/view/WindowMetricsTest.java index 74524bf6d76f..ddc977d380ae 100644 --- a/core/tests/coretests/src/android/view/WindowMetricsTest.java +++ b/core/tests/coretests/src/android/view/WindowMetricsTest.java @@ -56,17 +56,17 @@ public class WindowMetricsTest { @Before public void setUp() { - final Context insetContext = InstrumentationRegistry.getInstrumentation() + final Context instContext = InstrumentationRegistry.getInstrumentation() .getTargetContext(); - final Display display = insetContext.getSystemService(DisplayManager.class) + final Display display = instContext.getSystemService(DisplayManager.class) .getDisplay(DEFAULT_DISPLAY); - mWindowContext = insetContext.createDisplayContext(display) + mWindowContext = instContext.createDisplayContext(display) .createWindowContext(TYPE_APPLICATION_OVERLAY, null /* options */); mWm = mWindowContext.getSystemService(WindowManager.class); } @Test - public void testAddViewANdRemoveView_GetMetrics_DoNotCrash() { + public void testAddViewAndRemoveView_GetMetrics_DoNotCrash() { final View view = new View(mWindowContext); final WindowManager.LayoutParams params = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY); diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java index 4bfffd72d835..a9f251e5c3a7 100644 --- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java +++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java @@ -69,7 +69,6 @@ import java.util.concurrent.atomic.AtomicLong; @RunWith(AndroidJUnit4.class) @MediumTest -@Presubmit public class EditorCursorDragTest { private static final String LOG_TAG = EditorCursorDragTest.class.getSimpleName(); @@ -97,6 +96,7 @@ public class EditorCursorDragTest { mMotionEvents.clear(); } + @Presubmit @Test public void testCursorDrag_horizontal_whenTextViewContentsFitOnScreen() throws Throwable { String text = "Hello world!"; 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 bc0cdc1e029b..583c75102d52 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -1339,15 +1339,8 @@ public class ChooserActivityTest { createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(workProfileTargets); - when(sOverrides.workResolverListController.getUserStateIndependentResolversAsUser( - Mockito.isA(List.class), - Mockito.isA(UserHandle.class))) - .thenReturn(new ArrayList<>(workResolvedComponentInfos)); sOverrides.isQuietModeEnabled = true; - // When work profile is disabled, we get 0 results when we query the work profile - // intents. - setupResolverControllers(personalResolvedComponentInfos, - /* workResolvedComponentInfos */ new ArrayList<>()); + setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); Intent sendIntent = createSendTextIntent(); sendIntent.setType("TestType"); diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java index 8cf146ea801d..769c57835662 100644 --- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java @@ -213,13 +213,9 @@ public class IntentForwarderActivityTest { } @Test - public void forwardToManagedProfile_canForward_chooserIntent() throws Exception { + public void launchInSameProfile_chooserIntent() { sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME; - // Intent can be forwarded. - when(mIPm.canForwardTo( - any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true); - // Manage profile exists. List<UserInfo> profiles = new ArrayList<>(); profiles.add(CURRENT_USER_INFO); @@ -235,10 +231,6 @@ public class IntentForwarderActivityTest { intent.putExtra(Intent.EXTRA_INTENT, sendIntent); IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent); - ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); - verify(mIPm).canForwardTo(intentCaptor.capture(), eq(TYPE_PLAIN_TEXT), anyInt(), anyInt()); - assertEquals(Intent.ACTION_SEND, intentCaptor.getValue().getAction()); - assertNotNull(activity.mStartActivityIntent); assertEquals(Intent.ACTION_CHOOSER, activity.mStartActivityIntent.getAction()); assertNull(activity.mStartActivityIntent.getPackage()); @@ -249,9 +241,9 @@ public class IntentForwarderActivityTest { assertEquals(Intent.ACTION_SEND, innerIntent.getAction()); assertNull(innerIntent.getComponent()); assertNull(innerIntent.getPackage()); - assertEquals(CURRENT_USER_INFO.id, innerIntent.getContentUserHint()); + assertEquals(UserHandle.USER_CURRENT, innerIntent.getContentUserHint()); - assertEquals(MANAGED_PROFILE_INFO.id, activity.mUserIdActivityLaunchedIn); + assertEquals(CURRENT_USER_INFO.id, activity.mUserIdActivityLaunchedIn); } @Test @@ -656,6 +648,12 @@ public class IntentForwarderActivityTest { } @Override + public void startActivity(Intent intent) { + mStartActivityIntent = intent; + mUserIdActivityLaunchedIn = getUserId(); + } + + @Override protected MetricsLogger getMetricsLogger() { return mMetricsLogger; } diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java index 0bf8663c7a85..eb39d58019d9 100644 --- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java @@ -614,15 +614,8 @@ public class ResolverActivityTest { createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(workProfileTargets); - when(sOverrides.workResolverListController.getUserStateIndependentResolversAsUser( - Mockito.isA(List.class), - Mockito.isA(UserHandle.class))) - .thenReturn(new ArrayList<>(workResolvedComponentInfos)); sOverrides.isQuietModeEnabled = true; - // When work profile is disabled, we get 0 results when we query the work profile - // intents. - setupResolverControllers(personalResolvedComponentInfos, - /* workResolvedComponentInfos */ new ArrayList<>()); + setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); Intent sendIntent = createSendImageIntent(); sendIntent.setType("TestType"); diff --git a/core/tests/overlaytests/host/Android.bp b/core/tests/overlaytests/host/Android.bp index a2fcef56b780..2b38cca2db36 100644 --- a/core/tests/overlaytests/host/Android.bp +++ b/core/tests/overlaytests/host/Android.bp @@ -16,7 +16,7 @@ java_test_host { name: "OverlayHostTests", srcs: ["src/**/*.java"], libs: ["tradefed"], - test_suites: ["general-tests"], + test_suites: ["device-tests"], target_required: [ "OverlayHostTests_NonPlatformSignatureOverlay", "OverlayHostTests_PlatformSignatureStaticOverlay", diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java index eec7be22c78b..d898d222b8de 100644 --- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java +++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java @@ -78,14 +78,9 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { } @Test - public void failToInstallPlatformSignedStaticOverlay() throws Exception { - try { - installPackage("OverlayHostTests_PlatformSignatureStaticOverlay.apk"); - fail("installed a static overlay"); - } catch (Exception e) { - // Expected. - } - assertFalse(overlayManagerContainsPackage(SIG_OVERLAY_PACKAGE_NAME)); + public void installedIsStaticOverlayIsMutable() throws Exception { + installPackage("OverlayHostTests_PlatformSignatureStaticOverlay.apk"); + assertTrue(isOverlayMutable(SIG_OVERLAY_PACKAGE_NAME)); } @Test @@ -229,6 +224,10 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { return shell("cmd overlay list").contains(pkg); } + private boolean isOverlayMutable(String pkg) throws Exception { + return shell("cmd overlay dump ismutable " + pkg).contains("true"); + } + private String shell(final String cmd) throws Exception { return getDevice().executeShellCommand(cmd); } diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk index cc7704b0ce98..f3c0abd8293f 100644 --- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk +++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk @@ -20,7 +20,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_NonPlatformSignatureOverlay LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_bad include $(BUILD_PACKAGE) @@ -28,7 +28,8 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureStaticOverlay LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests +LOCAL_CERTIFICATE := platform LOCAL_MANIFEST_FILE := static/AndroidManifest.xml LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_static include $(BUILD_PACKAGE) @@ -37,7 +38,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureOverlay LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1 LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1 diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk index f8607f44bda6..878f05d57662 100644 --- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk +++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk @@ -19,7 +19,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_PACKAGE_NAME := OverlayHostTests_UpdateOverlay LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules LOCAL_USE_AAPT2 := true LOCAL_AAPT_FLAGS := --no-resource-removal @@ -31,7 +31,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV1 LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1 LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1 @@ -43,7 +43,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV2 LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2 LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2 @@ -57,7 +57,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV1 LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1 LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v1/res @@ -68,7 +68,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV2 LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2 LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v2/res diff --git a/core/tests/overlaytests/remount/host/Android.bp b/core/tests/overlaytests/remount/Android.bp index 3825c55f3b4b..5757cfe75514 100644 --- a/core/tests/overlaytests/remount/host/Android.bp +++ b/core/tests/overlaytests/remount/Android.bp @@ -21,8 +21,12 @@ java_test_host { ], test_suites: ["general-tests"], java_resources: [ + ":com.android.overlaytest.overlaid", + ":com.android.overlaytest.overlay", ":OverlayRemountedTest_SharedLibrary", ":OverlayRemountedTest_SharedLibraryOverlay", ":OverlayRemountedTest_Target", + ":OverlayRemountedTest_TargetUpgrade", + ":OverlayRemountedTest_Overlay", ], } diff --git a/core/tests/overlaytests/remount/host/AndroidTest.xml b/core/tests/overlaytests/remount/AndroidTest.xml index 087b7313693d..087b7313693d 100644 --- a/core/tests/overlaytests/remount/host/AndroidTest.xml +++ b/core/tests/overlaytests/remount/AndroidTest.xml diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayApexTest.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayApexTest.java new file mode 100644 index 000000000000..3fa8bcd6cbf0 --- /dev/null +++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayApexTest.java @@ -0,0 +1,66 @@ +/* + * 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.overlaytest.remounted; + +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class OverlayApexTest extends OverlayRemountedTestBase { + private static final String OVERLAID_APEX = "com.android.overlaytest.overlaid.apex"; + private static final String OVERLAY_APEX = "com.android.overlaytest.overlay.apex"; + + @Test + public void testApkInApexCanBeOverlaid() throws Exception { + final String targetResource = resourceName(TARGET_PACKAGE, "bool", "target_overlaid"); + + // The target APK will be installed inside the overlaid APEX. + mPreparer.pushResourceFile(OVERLAID_APEX, + "/system/apex/com.android.overlaytest.overlaid.apex") + .installResourceApk(OVERLAY_APK, OVERLAY_PACKAGE) + .reboot() + .setOverlayEnabled(OVERLAY_PACKAGE, false); + + // The resource is not currently overlaid. + assertResource(targetResource, "false"); + + // Overlay the resource. + mPreparer.setOverlayEnabled(OVERLAY_PACKAGE, true); + assertResource(targetResource, "true"); + } + + @Test + public void testApkInApexCanOverlay() throws Exception { + final String targetResource = resourceName(TARGET_PACKAGE, "bool", "target_overlaid"); + + // The overlay APK will be installed inside the overlay APEX. + mPreparer.pushResourceFile(OVERLAY_APEX, + "/system/apex/com.android.overlaytest.overlay.apex") + .installResourceApk(TARGET_APK, TARGET_PACKAGE) + .reboot() + .setOverlayEnabled(OVERLAY_PACKAGE, false); + + // The resource is not currently overlaid. + assertResource(targetResource, "false"); + + // Overlay the resource. + mPreparer.setOverlayEnabled(OVERLAY_PACKAGE, true); + assertResource(targetResource, "true"); + } +} diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java new file mode 100644 index 000000000000..14b5bf6eacba --- /dev/null +++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java @@ -0,0 +1,74 @@ +/* + * 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.overlaytest.remounted; + +import static org.junit.Assert.fail; + +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.RuleChain; +import org.junit.rules.TemporaryFolder; + +public class OverlayRemountedTestBase extends BaseHostJUnit4Test { + private static final long ASSERT_RESOURCE_TIMEOUT_MS = 30000; + static final String TARGET_APK = "OverlayRemountedTest_Target.apk"; + static final String TARGET_PACKAGE = "com.android.overlaytest.remounted.target"; + static final String OVERLAY_APK = "OverlayRemountedTest_Overlay.apk"; + static final String OVERLAY_PACKAGE = "com.android.overlaytest.remounted.target.overlay"; + + private final TemporaryFolder mTemporaryFolder = new TemporaryFolder(); + protected final SystemPreparer mPreparer = new SystemPreparer(mTemporaryFolder, + this::getDevice); + + @Rule + public final RuleChain ruleChain = RuleChain.outerRule(mTemporaryFolder).around(mPreparer); + + @Before + public void startBefore() throws DeviceNotAvailableException { + getDevice().waitForDeviceAvailable(); + } + + /** Builds the full name of a resource in the form package:type/entry. */ + String resourceName(String pkg, String type, String entry) { + return String.format("%s:%s/%s", pkg, type, entry); + } + + void assertResource(String resourceName, String expectedValue) + throws DeviceNotAvailableException { + String result = null; + + final long endMillis = System.currentTimeMillis() + ASSERT_RESOURCE_TIMEOUT_MS; + while (System.currentTimeMillis() <= endMillis) { + result = getDevice().executeShellCommand( + String.format("cmd overlay lookup %s %s", TARGET_PACKAGE, resourceName)); + if (result.equals(expectedValue + "\n") || + result.endsWith("-> " + expectedValue + "\n")) { + return; + } + + try { + Thread.sleep(200); + } catch (InterruptedException ignore) { + } + } + + fail(String.format("expected: <[%s]> in: <[%s]>", expectedValue, result)); + } +} diff --git a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java index 06b2ac8f9e22..7f2c060b13fc 100644 --- a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java +++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java @@ -16,23 +16,13 @@ package com.android.overlaytest.remounted; -import static org.junit.Assert.assertTrue; - -import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; -import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; @RunWith(DeviceJUnit4ClassRunner.class) -public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { - private static final String TARGET_APK = "OverlayRemountedTest_Target.apk"; - private static final String TARGET_PACKAGE = "com.android.overlaytest.remounted.target"; +public class OverlaySharedLibraryTest extends OverlayRemountedTestBase { private static final String SHARED_LIBRARY_APK = "OverlayRemountedTest_SharedLibrary.apk"; private static final String SHARED_LIBRARY_PACKAGE = @@ -42,17 +32,6 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { private static final String SHARED_LIBRARY_OVERLAY_PACKAGE = "com.android.overlaytest.remounted.shared_library.overlay"; - public final TemporaryFolder temporaryFolder = new TemporaryFolder(); - public final SystemPreparer preparer = new SystemPreparer(temporaryFolder, this::getDevice); - - @Rule - public final RuleChain ruleChain = RuleChain.outerRule(temporaryFolder).around(preparer); - - @Before - public void startBefore() throws DeviceNotAvailableException { - getDevice().waitForDeviceAvailable(); - } - @Test public void testSharedLibrary() throws Exception { final String targetResource = resourceName(TARGET_PACKAGE, "bool", @@ -60,7 +39,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool", "shared_library_overlaid"); - preparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk") + mPreparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk") .installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE) .reboot() .setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, false) @@ -71,7 +50,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { assertResource(libraryResource, "false"); // Overlay the shared library resource. - preparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true); + mPreparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true); assertResource(targetResource, "true"); assertResource(libraryResource, "true"); } @@ -83,7 +62,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool", "shared_library_overlaid"); - preparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk") + mPreparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk") .installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE) .setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true) .reboot() @@ -92,18 +71,4 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { assertResource(targetResource, "true"); assertResource(libraryResource, "true"); } - - /** Builds the full name of a resource in the form package:type/entry. */ - String resourceName(String pkg, String type, String entry) { - return String.format("%s:%s/%s", pkg, type, entry); - } - - void assertResource(String resourceName, String expectedValue) - throws DeviceNotAvailableException { - final String result = getDevice().executeShellCommand( - String.format("cmd overlay lookup %s %s", TARGET_PACKAGE, resourceName)); - assertTrue(String.format("expected: <[%s]> in: <[%s]>", expectedValue, result), - result.equals(expectedValue + "\n") || - result.endsWith("-> " + expectedValue + "\n")); - } } diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java new file mode 100644 index 000000000000..70e342370545 --- /dev/null +++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java @@ -0,0 +1,66 @@ +/* + * 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.overlaytest.remounted; + +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class PackagedUpgradedTest extends OverlayRemountedTestBase { + private static final String TARGET_UPGRADE_APK = "OverlayRemountedTest_TargetUpgrade.apk"; + + @Test + public void testTargetUpgrade() throws Exception { + final String targetOverlaid = resourceName(TARGET_PACKAGE, "bool", "target_overlaid"); + final String targetReference = resourceName(TARGET_PACKAGE, "bool", "target_reference"); + + mPreparer.pushResourceFile(TARGET_APK, "/product/app/OverlayTarget.apk") + .reboot() + .installResourceApk(OVERLAY_APK, OVERLAY_PACKAGE) + .setOverlayEnabled(OVERLAY_PACKAGE, true); + + assertResource(targetReference, "@" + 0x7f010000 + " -> true"); + assertResource(targetOverlaid, "true"); + + mPreparer.installResourceApk(TARGET_UPGRADE_APK, TARGET_PACKAGE); + + assertResource(targetReference, "@" + 0x7f0100ff + " -> true"); + assertResource(targetOverlaid, "true"); + } + + @Test + public void testTargetRelocated() throws Exception { + final String targetOverlaid = resourceName(TARGET_PACKAGE, "bool", "target_overlaid"); + final String originalPath = "/product/app/OverlayTarget.apk"; + + mPreparer.pushResourceFile(TARGET_APK, originalPath) + .reboot() + .installResourceApk(OVERLAY_APK, OVERLAY_PACKAGE) + .setOverlayEnabled(OVERLAY_PACKAGE, true); + + assertResource(targetOverlaid, "true"); + + mPreparer.remount(); + getDevice().deleteFile(originalPath); + mPreparer.pushResourceFile(TARGET_UPGRADE_APK, "/product/app/OverlayTarget2.apk") + .reboot(); + + assertResource(targetOverlaid, "true"); + } +} diff --git a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java index 8696091239c2..bb72d0ee1d03 100644 --- a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java +++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java @@ -18,8 +18,6 @@ package com.android.overlaytest.remounted; import static org.junit.Assert.assertTrue; -import static java.util.concurrent.TimeUnit.MILLISECONDS; - import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.ITestDevice; @@ -32,10 +30,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeoutException; class SystemPreparer extends ExternalResource { private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000; @@ -58,7 +52,7 @@ class SystemPreparer extends ExternalResource { SystemPreparer pushResourceFile(String resourcePath, String outputPath) throws DeviceNotAvailableException, IOException { final ITestDevice device = mDeviceProvider.getDevice(); - device.executeAdbCommand("remount"); + remount(); assertTrue(device.pushFile(copyResourceToTemp(resourcePath), outputPath)); mPushedFiles.add(outputPath); return this; @@ -69,42 +63,37 @@ class SystemPreparer extends ExternalResource { throws DeviceNotAvailableException, IOException { final ITestDevice device = mDeviceProvider.getDevice(); final File tmpFile = copyResourceToTemp(resourcePath); - final String result = device.installPackage(tmpFile, true); + final String result = device.installPackage(tmpFile, true /* reinstall */); Assert.assertNull(result); mInstalledPackages.add(packageName); return this; } - /** Sets the enable state of an overlay pacakage. */ + /** Sets the enable state of an overlay package. */ SystemPreparer setOverlayEnabled(String packageName, boolean enabled) - throws ExecutionException, DeviceNotAvailableException { + throws DeviceNotAvailableException { final ITestDevice device = mDeviceProvider.getDevice(); + final String enable = enabled ? "enable" : "disable"; // Wait for the overlay to change its enabled state. - final FutureTask<Boolean> enabledListener = new FutureTask<>(() -> { - while (true) { - device.executeShellCommand(String.format("cmd overlay %s %s", - enabled ? "enable" : "disable", packageName)); - - final String result = device.executeShellCommand("cmd overlay dump " + packageName); - final int startIndex = result.indexOf("mIsEnabled"); - final int endIndex = result.indexOf('\n', startIndex); - if (result.substring(startIndex, endIndex).contains((enabled) ? "true" : "false")) { - return true; - } + final long endMillis = System.currentTimeMillis() + OVERLAY_ENABLE_TIMEOUT_MS; + String result; + while (System.currentTimeMillis() <= endMillis) { + device.executeShellCommand(String.format("cmd overlay %s %s", enable, packageName)); + result = device.executeShellCommand("cmd overlay dump isenabled " + + packageName); + if (((enabled) ? "true\n" : "false\n").equals(result)) { + return this; } - }); - final Executor executor = (cmd) -> new Thread(cmd).start(); - executor.execute(enabledListener); - try { - enabledListener.get(OVERLAY_ENABLE_TIMEOUT_MS, MILLISECONDS); - } catch (InterruptedException ignored) { - } catch (TimeoutException e) { - throw new IllegalStateException(device.executeShellCommand("cmd overlay list")); + try { + Thread.sleep(200); + } catch (InterruptedException ignore) { + } } - return this; + throw new IllegalStateException(String.format("Failed to %s overlay %s:\n%s", enable, + packageName, device.executeShellCommand("cmd overlay list"))); } /** Restarts the device and waits until after boot is completed. */ @@ -114,6 +103,11 @@ class SystemPreparer extends ExternalResource { return this; } + SystemPreparer remount() throws DeviceNotAvailableException { + mDeviceProvider.getDevice().executeAdbCommand("remount"); + return this; + } + /** Copies a file within the host test jar to a temporary file on the host machine. */ private File copyResourceToTemp(String resourcePath) throws IOException { final File tempFile = mHostTempFolder.newFile(resourcePath); @@ -138,7 +132,7 @@ class SystemPreparer extends ExternalResource { protected void after() { final ITestDevice device = mDeviceProvider.getDevice(); try { - device.executeAdbCommand("remount"); + remount(); for (final String file : mPushedFiles) { device.deleteFile(file); } diff --git a/core/tests/overlaytests/remount/target/Android.bp b/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp index 83f9f28b3f48..a1fdbfd3542c 100644 --- a/core/tests/overlaytests/remount/target/Android.bp +++ b/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp @@ -1,4 +1,4 @@ -// Copyright (C) 2018 The Android Open Source Project +// 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. @@ -13,8 +13,9 @@ // limitations under the License. android_test_helper_app { - name: "OverlayRemountedTest_Target", - srcs: ["src/**/*.java"], - sdk_version: "test_current", - libs: ["OverlayRemountedTest_SharedLibrary"], + name: "OverlayRemountedTest_Overlay", + sdk_version: "current", + apex_available: [ + "com.android.overlaytest.overlay", + ], } diff --git a/core/tests/overlaytests/remount/test-apps/Overlay/AndroidManifest.xml b/core/tests/overlaytests/remount/test-apps/Overlay/AndroidManifest.xml new file mode 100644 index 000000000000..d6d706c2da62 --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Overlay/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.overlaytest.remounted.target.overlay"> + <application android:hasCode="false" /> + <overlay android:targetPackage="com.android.overlaytest.remounted.target" + android:targetName="TestResources" /> +</manifest>
\ No newline at end of file diff --git a/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml new file mode 100644 index 000000000000..675e44f19f95 --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<resources> + <bool name="target_overlaid">true</bool> +</resources> diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/Android.bp b/core/tests/overlaytests/remount/test-apps/SharedLibrary/Android.bp index ffb0572c3fd0..ffb0572c3fd0 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/Android.bp +++ b/core/tests/overlaytests/remount/test-apps/SharedLibrary/Android.bp diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/AndroidManifest.xml b/core/tests/overlaytests/remount/test-apps/SharedLibrary/AndroidManifest.xml index 06e3f6a99410..06e3f6a99410 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/AndroidManifest.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibrary/AndroidManifest.xml diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/overlayable.xml b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/overlayable.xml index 1b06f6d7530b..1b06f6d7530b 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/overlayable.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/overlayable.xml diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/public.xml b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/public.xml index 5b9db163a274..5b9db163a274 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/public.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/public.xml diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/values.xml index 2dc47a7ecf61..2dc47a7ecf61 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/values.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/values.xml diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/Android.bp b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/Android.bp index 0d29aec909d5..0d29aec909d5 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/Android.bp +++ b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/Android.bp diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/AndroidManifest.xml b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/AndroidManifest.xml index 53a4e61949da..53a4e61949da 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/AndroidManifest.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/AndroidManifest.xml diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/res/values/values.xml index f66448a8d991..f66448a8d991 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/res/values/values.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/res/values/values.xml diff --git a/core/tests/overlaytests/remount/test-apps/Target/Android.bp b/core/tests/overlaytests/remount/test-apps/Target/Android.bp new file mode 100644 index 000000000000..19947b1ea51a --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Target/Android.bp @@ -0,0 +1,28 @@ +// 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. + +android_test_helper_app { + name: "OverlayRemountedTest_Target", + sdk_version: "test_current", + apex_available: [ + "com.android.overlaytest.overlaid", + ], + libs: ["OverlayRemountedTest_SharedLibrary"], +} + +android_test_helper_app { + name: "OverlayRemountedTest_TargetUpgrade", + resource_dirs: ["res_upgrade"], + sdk_version: "test_current", +} diff --git a/core/tests/overlaytests/remount/target/AndroidManifest.xml b/core/tests/overlaytests/remount/test-apps/Target/AndroidManifest.xml index dc07dca16718..d1c7b7e8bb9d 100644 --- a/core/tests/overlaytests/remount/target/AndroidManifest.xml +++ b/core/tests/overlaytests/remount/test-apps/Target/AndroidManifest.xml @@ -19,8 +19,7 @@ package="com.android.overlaytest.remounted.target"> <application> - <uses-library android:name="android.test.runner" /> <uses-library android:name="com.android.overlaytest.remounted.shared_library" - android:required="true" /> + android:required="false" /> </application> </manifest> diff --git a/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml b/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml new file mode 100644 index 000000000000..4aa5bcee8f3d --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<resources> + <overlayable name="TestResources"> + <policy type="public"> + <item type="bool" name="target_overlaid" /> + </policy> + </overlayable> +</resources> diff --git a/core/tests/overlaytests/remount/target/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml index b5f444a5eb72..76253a95b766 100644 --- a/core/tests/overlaytests/remount/target/res/values/values.xml +++ b/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml @@ -17,4 +17,10 @@ <resources xmlns:sharedlib="http://schemas.android.com/apk/res/com.android.overlaytest.remounted.shared_library"> <bool name="uses_shared_library_overlaid">@sharedlib:bool/shared_library_overlaid</bool> + + <!-- This resource has a different id in the updated version of this target app to test that the + idmap is regenerated when the target is updated. --> + <bool name="target_overlaid">false</bool> + <public type="bool" name="target_overlaid" id="0x7f010000" /> + <bool name="target_reference">@bool/target_overlaid</bool> </resources> diff --git a/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/overlayable.xml b/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/overlayable.xml new file mode 100644 index 000000000000..4aa5bcee8f3d --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/overlayable.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<resources> + <overlayable name="TestResources"> + <policy type="public"> + <item type="bool" name="target_overlaid" /> + </policy> + </overlayable> +</resources> diff --git a/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/values.xml b/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/values.xml new file mode 100644 index 000000000000..f552cb0776ab --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/values.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<resources> + <!-- This resource has a different id in the updated target app than the base target app to test + that the idmap is regenerated when the target is updated. --> + <bool name="target_overlaid">false</bool> + <public type="bool" name="target_overlaid" id="0x7f0100ff" /> + <bool name="target_reference">@bool/target_overlaid</bool> +</resources>
\ No newline at end of file diff --git a/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp b/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp new file mode 100644 index 000000000000..e6ebd5ea76d8 --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp @@ -0,0 +1,42 @@ +// 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. + +genrule { + name: "com.android.overlaytest.overlaid.pem", + out: ["com.android.overlaytest.overlaid.pem"], + cmd: "openssl genrsa -out $(out) 4096", +} + +genrule { + name: "com.android.overlaytest.overlaid.pubkey", + srcs: [":com.android.overlaytest.overlaid.pem"], + out: ["com.android.overlaytest.overlaid.pubkey"], + tools: ["avbtool"], + cmd: "$(location avbtool) extract_public_key --key $(in) --output $(out)", +} + +apex_key { + name: "com.android.overlaytest.overlaid.key", + public_key: ":com.android.overlaytest.overlaid.pubkey", + private_key: ":com.android.overlaytest.overlaid.pem", +} + +apex { + name: "com.android.overlaytest.overlaid", + manifest: "manifest.json", + file_contexts: ":apex.test-file_contexts", + key: "com.android.overlaytest.overlaid.key", + apps: ["OverlayRemountedTest_Target"], + installable: false, +} diff --git a/core/tests/overlaytests/remount/test-apps/overlaid_apex/manifest.json b/core/tests/overlaytests/remount/test-apps/overlaid_apex/manifest.json new file mode 100644 index 000000000000..9a5102fde11f --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/overlaid_apex/manifest.json @@ -0,0 +1,4 @@ +{ + "name": "com.android.overlaytest.overlaid", + "version": "1" +} diff --git a/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp b/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp new file mode 100644 index 000000000000..07f27ee55d39 --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp @@ -0,0 +1,42 @@ +// 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. + +genrule { + name: "com.android.overlaytest.overlay.pem", + out: ["com.android.overlaytest.overlay.pem"], + cmd: "openssl genrsa -out $(out) 4096", +} + +genrule { + name: "com.android.overlaytest.overlay.pubkey", + srcs: [":com.android.overlaytest.overlay.pem"], + out: ["com.android.overlaytest.overlay.pubkey"], + tools: ["avbtool"], + cmd: "$(location avbtool) extract_public_key --key $(in) --output $(out)", +} + +apex_key { + name: "com.android.overlaytest.overlay.key", + public_key: ":com.android.overlaytest.overlay.pubkey", + private_key: ":com.android.overlaytest.overlay.pem", +} + +apex { + name: "com.android.overlaytest.overlay", + manifest: "manifest.json", + file_contexts: ":apex.test-file_contexts", + key: "com.android.overlaytest.overlay.key", + apps: ["OverlayRemountedTest_Overlay"], + installable: false, +} diff --git a/core/tests/overlaytests/remount/test-apps/overlay_apex/manifest.json b/core/tests/overlaytests/remount/test-apps/overlay_apex/manifest.json new file mode 100644 index 000000000000..ac5f84659eef --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/overlay_apex/manifest.json @@ -0,0 +1,4 @@ +{ + "name": "com.android.overlaytest.overlay", + "version": "1" +}
\ No newline at end of file diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 59bdf3dad43e..0389639e9edb 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -137,6 +137,7 @@ applications that come with the platform <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE" /> <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" /> <permission name="android.permission.PACKAGE_USAGE_STATS" /> + <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" /> </privapp-permissions> <privapp-permissions package="com.android.phone"> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 07cf41560cf3..18086ec0313e 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -883,6 +883,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "-242787066": { + "message": "addTaskToRecentsAnimationIfNeeded, control: %s, task: %s, transit: %s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/WindowContainer.java" + }, "-198463978": { "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b", "level": "VERBOSE", @@ -901,6 +907,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" }, + "-172900257": { + "message": "addTaskToTargets, target: %s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, "-167822951": { "message": "Attempted to add starting window to token with already existing starting window", "level": "WARN", @@ -1201,6 +1213,12 @@ "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/WindowSurfaceController.java" }, + "315395835": { + "message": "Trying to add window with invalid user=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, "342460966": { "message": "DRAG %s: pos=(%d,%d)", "level": "INFO", @@ -1507,12 +1525,30 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, + "838570988": { + "message": "Could not report token removal to the window token client.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowToken.java" + }, + "845234215": { + "message": "App is requesting an orientation, return %d for display id=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "853091290": { "message": "Moved stack=%s behind stack=%s", "level": "DEBUG", "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, + "854237232": { + "message": "addTaskToRecentsAnimationIfNeeded, control: %s, task: %s, transit: %s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/Task.java" + }, "873914452": { "message": "goodToGo()", "level": "DEBUG", diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java index ce8ff7dc38ba..1aeafa391b41 100644 --- a/graphics/java/android/graphics/ColorSpace.java +++ b/graphics/java/android/graphics/ColorSpace.java @@ -199,6 +199,11 @@ public abstract class ColorSpace { private static final float[] SRGB_PRIMARIES = { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f }; private static final float[] NTSC_1953_PRIMARIES = { 0.67f, 0.33f, 0.21f, 0.71f, 0.14f, 0.08f }; + /** + * A gray color space does not have meaningful primaries, so we use this arbitrary set. + */ + private static final float[] GRAY_PRIMARIES = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; + private static final float[] ILLUMINANT_D50_XYZ = { 0.964212f, 1.0f, 0.825188f }; private static final Rgb.TransferParameters SRGB_TRANSFER_PARAMETERS = @@ -1457,6 +1462,7 @@ public abstract class ColorSpace { "sRGB IEC61966-2.1", SRGB_PRIMARIES, ILLUMINANT_D65, + null, SRGB_TRANSFER_PARAMETERS, Named.SRGB.ordinal() ); @@ -1491,6 +1497,7 @@ public abstract class ColorSpace { "Rec. ITU-R BT.709-5", new float[] { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f }, ILLUMINANT_D65, + null, new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45), Named.BT709.ordinal() ); @@ -1498,6 +1505,7 @@ public abstract class ColorSpace { "Rec. ITU-R BT.2020-1", new float[] { 0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f }, ILLUMINANT_D65, + null, new Rgb.TransferParameters(1 / 1.0993, 0.0993 / 1.0993, 1 / 4.5, 0.08145, 1 / 0.45), Named.BT2020.ordinal() ); @@ -1513,6 +1521,7 @@ public abstract class ColorSpace { "Display P3", new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f }, ILLUMINANT_D65, + null, SRGB_TRANSFER_PARAMETERS, Named.DISPLAY_P3.ordinal() ); @@ -1520,6 +1529,7 @@ public abstract class ColorSpace { "NTSC (1953)", NTSC_1953_PRIMARIES, ILLUMINANT_C, + null, new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45), Named.NTSC_1953.ordinal() ); @@ -1527,6 +1537,7 @@ public abstract class ColorSpace { "SMPTE-C RGB", new float[] { 0.630f, 0.340f, 0.310f, 0.595f, 0.155f, 0.070f }, ILLUMINANT_D65, + null, new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45), Named.SMPTE_C.ordinal() ); @@ -1542,6 +1553,7 @@ public abstract class ColorSpace { "ROMM RGB ISO 22028-2:2013", new float[] { 0.7347f, 0.2653f, 0.1596f, 0.8404f, 0.0366f, 0.0001f }, ILLUMINANT_D50, + null, new Rgb.TransferParameters(1.0, 0.0, 1 / 16.0, 0.031248, 1.8), Named.PRO_PHOTO_RGB.ordinal() ); @@ -2471,7 +2483,11 @@ public abstract class ColorSpace { @NonNull @Size(min = 1) String name, @NonNull @Size(9) float[] toXYZ, @NonNull TransferParameters function) { - this(name, computePrimaries(toXYZ), computeWhitePoint(toXYZ), function, MIN_ID); + // Note: when isGray() returns false, this passes null for the transform for + // consistency with other constructors, which compute the transform from the primaries + // and white point. + this(name, isGray(toXYZ) ? GRAY_PRIMARIES : computePrimaries(toXYZ), + computeWhitePoint(toXYZ), isGray(toXYZ) ? toXYZ : null, function, MIN_ID); } /** @@ -2511,7 +2527,7 @@ public abstract class ColorSpace { @NonNull @Size(min = 6, max = 9) float[] primaries, @NonNull @Size(min = 2, max = 3) float[] whitePoint, @NonNull TransferParameters function) { - this(name, primaries, whitePoint, function, MIN_ID); + this(name, primaries, whitePoint, null, function, MIN_ID); } /** @@ -2534,6 +2550,8 @@ public abstract class ColorSpace { * @param name Name of the color space, cannot be null, its length must be >= 1 * @param primaries RGB primaries as an array of 6 (xy) or 9 (XYZ) floats * @param whitePoint Reference white as an array of 2 (xy) or 3 (XYZ) floats + * @param transform Computed transform matrix that converts from RGB to XYZ, or + * {@code null} to compute it from {@code primaries} and {@code whitePoint}. * @param function Parameters for the transfer functions * @param id ID of this color space as an integer between {@link #MIN_ID} and {@link #MAX_ID} * @@ -2552,9 +2570,10 @@ public abstract class ColorSpace { @NonNull @Size(min = 1) String name, @NonNull @Size(min = 6, max = 9) float[] primaries, @NonNull @Size(min = 2, max = 3) float[] whitePoint, + @Nullable @Size(9) float[] transform, @NonNull TransferParameters function, @IntRange(from = MIN_ID, to = MAX_ID) int id) { - this(name, primaries, whitePoint, null, + this(name, primaries, whitePoint, transform, function.e == 0.0 && function.f == 0.0 ? x -> rcpResponse(x, function.a, function.b, function.c, function.d, function.g) : @@ -2846,7 +2865,7 @@ public abstract class ColorSpace { * * @return The destination array passed as a parameter * - * @see #getWhitePoint(float[]) + * @see #getWhitePoint() */ @NonNull @Size(min = 2) @@ -2864,7 +2883,7 @@ public abstract class ColorSpace { * * @return A new non-null array of 2 floats * - * @see #getWhitePoint() + * @see #getWhitePoint(float[]) */ @NonNull @Size(2) @@ -2878,12 +2897,16 @@ public abstract class ColorSpace { * destination. The x and y components of the first primary are written * in the array at positions 0 and 1 respectively. * + * <p>Note: Some ColorSpaces represent gray profiles. The concept of + * primaries for such a ColorSpace does not make sense, so we use a special + * set of primaries that are all 1s.</p> + * * @param primaries The destination array, cannot be null, its length * must be >= 6 * * @return The destination array passed as a parameter * - * @see #getPrimaries(float[]) + * @see #getPrimaries() */ @NonNull @Size(min = 6) @@ -2898,9 +2921,13 @@ public abstract class ColorSpace { * the destination. The x and y components of the first primary are * written in the array at positions 0 and 1 respectively. * + * <p>Note: Some ColorSpaces represent gray profiles. The concept of + * primaries for such a ColorSpace does not make sense, so we use a special + * set of primaries that are all 1s.</p> + * * @return A new non-null array of 2 floats * - * @see #getWhitePoint() + * @see #getPrimaries(float[]) */ @NonNull @Size(6) @@ -2922,7 +2949,7 @@ public abstract class ColorSpace { * * @return The destination array passed as a parameter * - * @see #getInverseTransform() + * @see #getTransform() */ @NonNull @Size(min = 9) @@ -2942,7 +2969,7 @@ public abstract class ColorSpace { * * @return A new array of 9 floats * - * @see #getInverseTransform(float[]) + * @see #getTransform(float[]) */ @NonNull @Size(9) @@ -2964,7 +2991,7 @@ public abstract class ColorSpace { * * @return The destination array passed as a parameter * - * @see #getTransform() + * @see #getInverseTransform() */ @NonNull @Size(min = 9) @@ -2984,7 +3011,7 @@ public abstract class ColorSpace { * * @return A new array of 9 floats * - * @see #getTransform(float[]) + * @see #getInverseTransform(float[]) */ @NonNull @Size(9) @@ -3287,6 +3314,16 @@ public abstract class ColorSpace { return true; } + /** + * Report whether this matrix is a special gray matrix. + * @param toXYZ A XYZD50 matrix. Skia uses a special form for a gray profile. + * @return true if this is a special gray matrix. + */ + private static boolean isGray(@NonNull @Size(9) float[] toXYZ) { + return toXYZ.length == 9 && toXYZ[1] == 0 && toXYZ[2] == 0 && toXYZ[3] == 0 + && toXYZ[5] == 0 && toXYZ[6] == 0 && toXYZ[7] == 0; + } + private static boolean compare(double point, @NonNull DoubleUnaryOperator a, @NonNull DoubleUnaryOperator b) { double rA = a.applyAsDouble(point); diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index 918e7af12d31..05f4d6b63a4c 100644 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -385,7 +385,7 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap const StringPiece idmap_data( reinterpret_cast<const char*>(idmap_asset->getBuffer(true /*wordAligned*/)), static_cast<size_t>(idmap_asset->getLength())); - std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(idmap_data); + std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(idmap_path, idmap_data); if (loaded_idmap == nullptr) { LOG(ERROR) << "failed to load IDMAP " << idmap_path; return {}; @@ -538,8 +538,9 @@ bool ApkAssets::IsUpToDate() const { // Loaders are invalidated by the app, not the system, so assume they are up to date. return true; } + return (!loaded_idmap_ || loaded_idmap_->IsUpToDate()) && + last_mod_time_ == getFileModDate(path_.c_str()); - return last_mod_time_ == getFileModDate(path_.c_str()); } } // namespace android diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index eaf452b5fa71..b9765ea7212c 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -331,6 +331,11 @@ bool AssetManager2::GetOverlayablesToString(const android::StringPiece& package_ return true; } +bool AssetManager2::ContainsAllocatedTable() const { + return std::find_if(apk_assets_.begin(), apk_assets_.end(), + std::mem_fn(&ApkAssets::IsTableAllocated)) != apk_assets_.end(); +} + void AssetManager2::SetConfiguration(const ResTable_config& configuration) { const int diff = configuration_.diff(configuration); configuration_ = configuration; diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp index 0b2fd9ec982d..eb6ee9525bb9 100644 --- a/libs/androidfw/Idmap.cpp +++ b/libs/androidfw/Idmap.cpp @@ -20,6 +20,7 @@ #include "android-base/logging.h" #include "android-base/stringprintf.h" +#include "androidfw/misc.h" #include "androidfw/ResourceTypes.h" #include "androidfw/Util.h" #include "utils/ByteOrder.h" @@ -192,7 +193,9 @@ static bool IsValidIdmapHeader(const StringPiece& data) { return true; } -LoadedIdmap::LoadedIdmap(const Idmap_header* header, +LoadedIdmap::LoadedIdmap(std::string&& idmap_path, + const time_t last_mod_time, + const Idmap_header* header, const Idmap_data_header* data_header, const Idmap_target_entry* target_entries, const Idmap_overlay_entry* overlay_entries, @@ -201,7 +204,9 @@ LoadedIdmap::LoadedIdmap(const Idmap_header* header, data_header_(data_header), target_entries_(target_entries), overlay_entries_(overlay_entries), - string_pool_(string_pool) { + string_pool_(string_pool), + idmap_path_(std::move(idmap_path)), + idmap_last_mod_time_(last_mod_time) { size_t length = strnlen(reinterpret_cast<const char*>(header_->overlay_path), arraysize(header_->overlay_path)); @@ -212,7 +217,8 @@ LoadedIdmap::LoadedIdmap(const Idmap_header* header, target_apk_path_.assign(reinterpret_cast<const char*>(header_->target_path), length); } -std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_data) { +std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_path, + const StringPiece& idmap_data) { ATRACE_CALL(); if (!IsValidIdmapHeader(idmap_data)) { return {}; @@ -275,10 +281,14 @@ std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_da // Can't use make_unique because LoadedIdmap constructor is private. std::unique_ptr<LoadedIdmap> loaded_idmap = std::unique_ptr<LoadedIdmap>( - new LoadedIdmap(header, data_header, target_entries, overlay_entries, - idmap_string_pool.release())); + new LoadedIdmap(idmap_path.to_string(), getFileModDate(idmap_path.data()), header, + data_header, target_entries, overlay_entries, idmap_string_pool.release())); return std::move(loaded_idmap); } +bool LoadedIdmap::IsUpToDate() const { + return idmap_last_mod_time_ == getFileModDate(idmap_path_.c_str()); +} + } // namespace android diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h index 879b050b65bd..e57490aab2d8 100644 --- a/libs/androidfw/include/androidfw/ApkAssets.h +++ b/libs/androidfw/include/androidfw/ApkAssets.h @@ -119,31 +119,36 @@ class ApkAssets { package_property_t flags = 0U, std::unique_ptr<const AssetsProvider> override_asset = nullptr); - inline const std::string& GetPath() const { + const std::string& GetPath() const { return path_; } - inline const AssetsProvider* GetAssetsProvider() const { + const AssetsProvider* GetAssetsProvider() const { return assets_provider_.get(); } // This is never nullptr. - inline const LoadedArsc* GetLoadedArsc() const { + const LoadedArsc* GetLoadedArsc() const { return loaded_arsc_.get(); } - inline const LoadedIdmap* GetLoadedIdmap() const { + const LoadedIdmap* GetLoadedIdmap() const { return loaded_idmap_.get(); } - inline bool IsLoader() const { + bool IsLoader() const { return (property_flags_ & PROPERTY_LOADER) != 0; } - inline bool IsOverlay() const { + bool IsOverlay() const { return loaded_idmap_ != nullptr; } + // Returns whether the resources.arsc is allocated in RAM (not mmapped). + bool IsTableAllocated() const { + return resources_asset_ && resources_asset_->isAllocated(); + } + bool IsUpToDate() const; // Creates an Asset from a file on disk. diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index e21abade99a4..30ef25c6a516 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -134,6 +134,9 @@ class AssetManager2 { const std::unordered_map<std::string, std::string>* GetOverlayableMapForPackage(uint32_t package_id) const; + // Returns whether the resources.arsc of any loaded apk assets is allocated in RAM (not mmapped). + bool ContainsAllocatedTable() const; + // Sets/resets the configuration for this AssetManager. This will cause all // caches that are related to the configuration change to be invalidated. void SetConfiguration(const ResTable_config& configuration); diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h index ccb57f373473..ecc1ce65d124 100644 --- a/libs/androidfw/include/androidfw/Idmap.h +++ b/libs/androidfw/include/androidfw/Idmap.h @@ -142,7 +142,13 @@ class IdmapResMap { class LoadedIdmap { public: // Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed. - static std::unique_ptr<const LoadedIdmap> Load(const StringPiece& idmap_data); + static std::unique_ptr<const LoadedIdmap> Load(const StringPiece& idmap_path, + const StringPiece& idmap_data); + + // Returns the path to the IDMAP. + inline const std::string& IdmapPath() const { + return idmap_path_; + } // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated. inline const std::string& OverlayApkPath() const { @@ -167,6 +173,10 @@ class LoadedIdmap { return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id); } + // Returns whether the idmap file on disk has not been modified since the construction of this + // LoadedIdmap. + bool IsUpToDate() const; + protected: // Exposed as protected so that tests can subclass and mock this class out. LoadedIdmap() = default; @@ -177,13 +187,17 @@ class LoadedIdmap { const Idmap_overlay_entry* overlay_entries_; const std::unique_ptr<ResStringPool> string_pool_; + const std::string idmap_path_; std::string overlay_apk_path_; std::string target_apk_path_; + const time_t idmap_last_mod_time_; private: DISALLOW_COPY_AND_ASSIGN(LoadedIdmap); - explicit LoadedIdmap(const Idmap_header* header, + explicit LoadedIdmap(std::string&& idmap_path, + time_t last_mod_time, + const Idmap_header* header, const Idmap_data_header* data_header, const Idmap_target_entry* target_entries, const Idmap_overlay_entry* overlay_entries, diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp index 41ba637da5d7..7aa0dbbafab3 100644 --- a/libs/androidfw/tests/Idmap_test.cpp +++ b/libs/androidfw/tests/Idmap_test.cpp @@ -38,7 +38,7 @@ class IdmapTest : public ::testing::Test { protected: void SetUp() override { // Move to the test data directory so the idmap can locate the overlay APK. - std::string original_path = base::GetExecutableDirectory(); + original_path = base::GetExecutableDirectory(); chdir(GetTestDataPath().c_str()); system_assets_ = ApkAssets::Load("system/system.apk"); @@ -49,10 +49,14 @@ class IdmapTest : public ::testing::Test { overlayable_assets_ = ApkAssets::Load("overlayable/overlayable.apk"); ASSERT_NE(nullptr, overlayable_assets_); + } + + void TearDown() override { chdir(original_path.c_str()); } protected: + std::string original_path; std::unique_ptr<const ApkAssets> system_assets_; std::unique_ptr<const ApkAssets> overlay_assets_; std::unique_ptr<const ApkAssets> overlayable_assets_; @@ -221,8 +225,7 @@ TEST_F(IdmapTest, OverlaidResourceHasSameName) { TEST_F(IdmapTest, OverlayLoaderInterop) { std::string contents; - auto loader_assets = ApkAssets::LoadTable(GetTestDataPath() + "/loader/resources.arsc", - PROPERTY_LOADER); + auto loader_assets = ApkAssets::LoadTable("loader/resources.arsc", PROPERTY_LOADER); AssetManager2 asset_manager; asset_manager.SetApkAssets({overlayable_assets_.get(), loader_assets.get(), @@ -241,4 +244,25 @@ TEST_F(IdmapTest, OverlayLoaderInterop) { ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "loader"); } +TEST_F(IdmapTest, OverlayAssetsIsUpToDate) { + std::string idmap_contents; + ASSERT_TRUE(base::ReadFileToString("overlay/overlay.idmap", &idmap_contents)); + + TemporaryFile temp_file; + ASSERT_TRUE(base::WriteStringToFile(idmap_contents, temp_file.path)); + + auto apk_assets = ApkAssets::LoadOverlay(temp_file.path); + ASSERT_NE(nullptr, apk_assets); + ASSERT_TRUE(apk_assets->IsUpToDate()); + + unlink(temp_file.path); + ASSERT_FALSE(apk_assets->IsUpToDate()); + sleep(2); + + base::WriteStringToFile("hello", temp_file.path); + sleep(2); + + ASSERT_FALSE(apk_assets->IsUpToDate()); +} + } // namespace diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index ac2fd98248d0..aa842ff6a7b7 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -171,7 +171,6 @@ cc_library_headers { cc_defaults { name: "android_graphics_apex", - host_supported: true, cflags: [ "-Wno-unused-parameter", "-Wno-non-virtual-dtor", @@ -231,7 +230,6 @@ cc_library_headers { cc_defaults { name: "android_graphics_jni", - host_supported: true, cflags: [ "-Wno-unused-parameter", "-Wno-non-virtual-dtor", @@ -537,7 +535,11 @@ cc_defaults { cc_test { name: "hwui_unit_tests", - defaults: ["hwui_test_defaults"], + defaults: [ + "hwui_test_defaults", + "android_graphics_apex", + "android_graphics_jni", + ], static_libs: [ "libgmock", @@ -549,6 +551,7 @@ cc_test { srcs: [ "tests/unit/main.cpp", + "tests/unit/ABitmapTests.cpp", "tests/unit/CacheManagerTests.cpp", "tests/unit/CanvasContextTests.cpp", "tests/unit/CommonPoolTests.cpp", diff --git a/libs/hwui/apex/android_bitmap.cpp b/libs/hwui/apex/android_bitmap.cpp index b56a619b00aa..3780ba072308 100644 --- a/libs/hwui/apex/android_bitmap.cpp +++ b/libs/hwui/apex/android_bitmap.cpp @@ -163,10 +163,9 @@ jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat forma void ABitmap_notifyPixelsChanged(ABitmap* bitmapHandle) { Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle); - if (bitmap->isImmutable()) { - ALOGE("Attempting to modify an immutable Bitmap!"); + if (!bitmap->isImmutable()) { + bitmap->notifyPixelsChanged(); } - return bitmap->notifyPixelsChanged(); } namespace { diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp index 055075d0c42a..1ff156593c41 100644 --- a/libs/hwui/jni/AnimatedImageDrawable.cpp +++ b/libs/hwui/jni/AnimatedImageDrawable.cpp @@ -183,7 +183,7 @@ public: } ~InvokeListener() override { - auto* env = get_env_or_die(mJvm); + auto* env = requireEnv(mJvm); env->DeleteWeakGlobalRef(mWeakRef); } diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp index ba669053ed63..c0663a9bc699 100755 --- a/libs/hwui/jni/Bitmap.cpp +++ b/libs/hwui/jni/Bitmap.cpp @@ -601,6 +601,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { android::Parcel* p = parcelForJavaObject(env, parcel); + const bool isMutable = p->readInt32() != 0; const SkColorType colorType = (SkColorType)p->readInt32(); const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); const uint32_t colorSpaceSize = p->readUint32(); @@ -649,7 +650,9 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { // Map the bitmap in place from the ashmem region if possible otherwise copy. sk_sp<Bitmap> nativeBitmap; - if (blob.fd() >= 0 && !blob.isMutable()) { + // If the blob is mutable we have ownership of the region and can always use it + // If the blob is immutable _and_ we're immutable, we can then still use it + if (blob.fd() >= 0 && (blob.isMutable() || !isMutable)) { #if DEBUG_PARCEL ALOGD("Bitmap.createFromParcel: mapped contents of bitmap from %s blob " "(fds %s)", @@ -669,7 +672,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { // Map the pixels in place and take ownership of the ashmem region. We must also respect the // rowBytes value already set on the bitmap instead of attempting to compute our own. nativeBitmap = Bitmap::createFrom(bitmap->info(), bitmap->rowBytes(), dupFd, - const_cast<void*>(blob.data()), size, true); + const_cast<void*>(blob.data()), size, !isMutable); if (!nativeBitmap) { close(dupFd); blob.release(); @@ -707,7 +710,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { } return createBitmap(env, nativeBitmap.release(), - getPremulBitmapCreateFlags(false), NULL, NULL, density); + getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); #else doThrowRE(env, "Cannot use parcels outside of Android"); return NULL; @@ -728,6 +731,7 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle); bitmapWrapper->getSkBitmap(&bitmap); + p->writeInt32(!bitmap.isImmutable()); p->writeInt32(bitmap.colorType()); p->writeInt32(bitmap.alphaType()); SkColorSpace* colorSpace = bitmap.colorSpace(); @@ -754,7 +758,7 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, // Transfer the underlying ashmem region if we have one and it's immutable. android::status_t status; int fd = bitmapWrapper->bitmap().getAshmemFd(); - if (fd >= 0 && p->allowFds()) { + if (fd >= 0 && bitmap.isImmutable() && p->allowFds()) { #if DEBUG_PARCEL ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " "immutable blob (fds %s)", @@ -775,9 +779,10 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, p->allowFds() ? "allowed" : "forbidden"); #endif + const bool mutableCopy = !bitmap.isImmutable(); size_t size = bitmap.computeByteSize(); android::Parcel::WritableBlob blob; - status = p->writeBlob(size, false, &blob); + status = p->writeBlob(size, mutableCopy, &blob); if (status) { doThrowRE(env, "Could not copy bitmap to parcel blob."); return JNI_FALSE; diff --git a/libs/hwui/jni/ByteBufferStreamAdaptor.cpp b/libs/hwui/jni/ByteBufferStreamAdaptor.cpp index db5f6f6c684f..b10540cb3fbd 100644 --- a/libs/hwui/jni/ByteBufferStreamAdaptor.cpp +++ b/libs/hwui/jni/ByteBufferStreamAdaptor.cpp @@ -9,24 +9,6 @@ using namespace android; static jmethodID gByteBuffer_getMethodID; static jmethodID gByteBuffer_setPositionMethodID; -/** - * Helper method for accessing the JNI interface pointer. - * - * Image decoding (which this supports) is started on a thread that is already - * attached to the Java VM. But an AnimatedImageDrawable continues decoding on - * the AnimatedImageThread, which is not attached. This will attach if - * necessary. - */ -static JNIEnv* requireEnv(JavaVM* jvm) { - JNIEnv* env; - if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { - if (jvm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) { - LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!"); - } - } - return env; -} - class ByteBufferStream : public SkStreamAsset { private: ByteBufferStream(JavaVM* jvm, jobject jbyteBuffer, size_t initialPosition, size_t length, @@ -304,7 +286,7 @@ std::unique_ptr<SkStream> CreateByteBufferStreamAdaptor(JNIEnv* env, jobject jby auto* context = new release_proc_context{jvm, jbyteBuffer}; auto releaseProc = [](const void*, void* context) { auto* c = reinterpret_cast<release_proc_context*>(context); - JNIEnv* env = get_env_or_die(c->jvm); + JNIEnv* env = requireEnv(c->jvm); env->DeleteGlobalRef(c->jbyteBuffer); delete c; }; diff --git a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp index 39483b55992b..f1c6b29204b2 100644 --- a/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp +++ b/libs/hwui/jni/CreateJavaOutputStreamAdaptor.cpp @@ -49,13 +49,13 @@ public: } ~JavaInputStreamAdaptor() override { - auto* env = android::get_env_or_die(fJvm); + auto* env = android::requireEnv(fJvm); env->DeleteGlobalRef(fJavaInputStream); env->DeleteGlobalRef(fJavaByteArray); } size_t read(void* buffer, size_t size) override { - auto* env = android::get_env_or_die(fJvm); + auto* env = android::requireEnv(fJvm); if (!fSwallowExceptions && checkException(env)) { // Just in case the caller did not clear from a previous exception. return 0; diff --git a/libs/hwui/jni/Utils.cpp b/libs/hwui/jni/Utils.cpp index 17c194d04f84..34fd6687d52c 100644 --- a/libs/hwui/jni/Utils.cpp +++ b/libs/hwui/jni/Utils.cpp @@ -159,3 +159,13 @@ JNIEnv* android::get_env_or_die(JavaVM* jvm) { } return env; } + +JNIEnv* android::requireEnv(JavaVM* jvm) { + JNIEnv* env; + if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + if (jvm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) { + LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!"); + } + } + return env; +} diff --git a/libs/hwui/jni/Utils.h b/libs/hwui/jni/Utils.h index 89255177ba2e..f628cc3c85ed 100644 --- a/libs/hwui/jni/Utils.h +++ b/libs/hwui/jni/Utils.h @@ -78,6 +78,16 @@ bool isSeekable(int descriptor); JNIEnv* get_env_or_die(JavaVM* jvm); +/** + * Helper method for accessing the JNI interface pointer. + * + * Image decoding (which this supports) is started on a thread that is already + * attached to the Java VM. But an AnimatedImageDrawable continues decoding on + * the AnimatedImageThread, which is not attached. This will attach if + * necessary. + */ +JNIEnv* requireEnv(JavaVM* jvm); + }; // namespace android #endif // _ANDROID_GRAPHICS_UTILS_H_ diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 41aa1ff80e3c..5088494d6a07 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -418,9 +418,9 @@ void SkiaPipeline::endCapture(SkSurface* surface) { auto data = picture->serialize(); savePictureAsync(data, mCapturedFile); mCaptureSequence = 0; + mCaptureMode = CaptureMode::None; } } - mCaptureMode = CaptureMode::None; mRecorder.reset(); } } diff --git a/libs/hwui/tests/unit/ABitmapTests.cpp b/libs/hwui/tests/unit/ABitmapTests.cpp new file mode 100644 index 000000000000..8e2f7e09d406 --- /dev/null +++ b/libs/hwui/tests/unit/ABitmapTests.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 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. + */ + +#include <gtest/gtest.h> + +#include "android/graphics/bitmap.h" +#include "apex/TypeCast.h" +#include "hwui/Bitmap.h" +#include "tests/common/TestUtils.h" + +using namespace android; +using namespace android::uirenderer; + +TEST(ABitmap, notifyPixelsChanged) { + // generate a bitmap and its public API handle + sk_sp<Bitmap> bitmap(TestUtils::createBitmap(1, 1)); + ABitmap* abmp = android::TypeCast::toABitmap(bitmap.get()); + + // verify that notification changes the genID + uint32_t genID = bitmap->getGenerationID(); + ABitmap_notifyPixelsChanged(abmp); + ASSERT_TRUE(bitmap->getGenerationID() != genID); + + // mark the bitmap as immutable + ASSERT_FALSE(bitmap->isImmutable()); + bitmap->setImmutable(); + ASSERT_TRUE(bitmap->isImmutable()); + + // attempt to notify that the pixels have changed + genID = bitmap->getGenerationID(); + ABitmap_notifyPixelsChanged(abmp); + ASSERT_TRUE(bitmap->getGenerationID() == genID); +} diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index 90bcd1c0e370..1208062d9da0 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -403,3 +403,40 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) { renderThread.destroyRenderingContext(); EXPECT_FALSE(pipeline->isSurfaceReady()); } + +RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, pictureCallback) { + // create a pipeline and add a picture callback + auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); + int callbackCount = 0; + pipeline->setPictureCapturedCallback( + [&callbackCount](sk_sp<SkPicture>&& picture) { callbackCount += 1; }); + + // create basic red frame and render it + auto redNode = TestUtils::createSkiaNode( + 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) { + redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); + }); + LayerUpdateQueue layerUpdateQueue; + SkRect dirty = SkRectMakeLargest(); + std::vector<sp<RenderNode>> renderNodes; + renderNodes.push_back(redNode); + bool opaque = true; + android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1); + auto surface = SkSurface::MakeRasterN32Premul(1, 1); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, + SkMatrix::I()); + + // verify the callback was called + EXPECT_EQ(1, callbackCount); + + // render a second frame and check the callback count + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, + SkMatrix::I()); + EXPECT_EQ(2, callbackCount); + + // unset the callback, render another frame, check callback was not invoked + pipeline->setPictureCapturedCallback(nullptr); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, + SkMatrix::I()); + EXPECT_EQ(2, callbackCount); +} diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 415092623531..75ea0cbada92 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -47,10 +47,10 @@ interface ILocationManager Location getLastLocation(in LocationRequest request, String packageName, String featureId); boolean getCurrentLocation(in LocationRequest request, in ICancellationSignal cancellationSignal, in ILocationListener listener, - String packageName, String featureId); + String packageName, String featureId, String listenerId); void requestLocationUpdates(in LocationRequest request, in ILocationListener listener, - in PendingIntent intent, String packageName, String featureId); + in PendingIntent intent, String packageName, String featureId, String listenerId); void removeUpdates(in ILocationListener listener, in PendingIntent intent); void requestGeofence(in LocationRequest request, in Geofence geofence, diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index fcbd3e540291..d1b41dfccf63 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -718,7 +718,7 @@ public class LocationManager { currentLocationRequest.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS); } - GetCurrentLocationTransport listenerTransport = new GetCurrentLocationTransport(executor, + GetCurrentLocationTransport transport = new GetCurrentLocationTransport(executor, consumer); if (cancellationSignal != null) { @@ -729,14 +729,15 @@ public class LocationManager { try { if (mService.getCurrentLocation(currentLocationRequest, remoteCancellationSignal, - listenerTransport, mContext.getPackageName(), mContext.getAttributionTag())) { - listenerTransport.register(mContext.getSystemService(AlarmManager.class), + transport, mContext.getPackageName(), mContext.getAttributionTag(), + transport.getListenerId())) { + transport.register(mContext.getSystemService(AlarmManager.class), remoteCancellationSignal); if (cancellationSignal != null) { - cancellationSignal.setOnCancelListener(listenerTransport::cancel); + cancellationSignal.setOnCancelListener(transport::cancel); } } else { - listenerTransport.fail(); + transport.fail(); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1175,7 +1176,8 @@ public class LocationManager { boolean registered = false; try { mService.requestLocationUpdates(locationRequest, transport, null, - mContext.getPackageName(), mContext.getAttributionTag()); + mContext.getPackageName(), mContext.getAttributionTag(), + transport.getListenerId()); registered = true; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1220,7 +1222,7 @@ public class LocationManager { try { mService.requestLocationUpdates(locationRequest, null, pendingIntent, - mContext.getPackageName(), mContext.getAttributionTag()); + mContext.getPackageName(), mContext.getAttributionTag(), null); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2558,6 +2560,10 @@ public class LocationManager { mRemoteCancellationSignal = null; } + public String getListenerId() { + return mConsumer.getClass().getName() + "@" + System.identityHashCode(mConsumer); + } + public synchronized void register(AlarmManager alarmManager, ICancellationSignal remoteCancellationSignal) { if (mConsumer == null) { @@ -2683,6 +2689,10 @@ public class LocationManager { return mListener; } + public String getListenerId() { + return mListener.getClass().getName() + "@" + System.identityHashCode(mListener); + } + public void register(@NonNull Executor executor) { Preconditions.checkArgument(executor != null, "invalid null executor"); mExecutor = executor; diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java index 4dd1a29d8595..5f0acc8f7647 100644 --- a/location/java/android/location/LocationRequest.java +++ b/location/java/android/location/LocationRequest.java @@ -264,8 +264,8 @@ public final class LocationRequest implements Parcelable { /* numUpdates= */ Integer.MAX_VALUE, /* smallestDisplacement= */ 0, /* hideFromAppOps= */ false, - /* lowPowerMode= */ false, /* locationSettingsIgnored= */ false, + /* lowPowerMode= */ false, /* workSource= */ null); } @@ -282,8 +282,8 @@ public final class LocationRequest implements Parcelable { src.mNumUpdates, src.mSmallestDisplacement, src.mHideFromAppOps, - src.mLowPowerMode, src.mLocationSettingsIgnored, + src.mLowPowerMode, src.mWorkSource); } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 8477aa3ca26e..3e1f72da8731 100644..100755 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -6145,6 +6145,17 @@ public class AudioManager { } } + /** @hide + * TODO: make this a @SystemApi */ + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public void setMultiAudioFocusEnabled(boolean enabled) { + try { + getService().setMultiAudioFocusEnabled(enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + //--------------------------------------------------------- // Inner classes //-------------------- diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index d2379757f226..ed566a50ec58 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -31,6 +31,7 @@ import android.system.OsConstants; import android.util.Log; import android.util.Pair; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import libcore.io.IoUtils; @@ -586,7 +587,9 @@ public class ExifInterface { private static final int WEBP_CHUNK_SIZE_BYTE_LENGTH = 4; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + @GuardedBy("sFormatter") private static SimpleDateFormat sFormatter; + @GuardedBy("sFormatterTz") private static SimpleDateFormat sFormatterTz; // See Exchangeable image file format for digital still cameras: Exif version 2.2. @@ -2426,12 +2429,17 @@ public class ExifInterface { try { // The exif field is in local time. Parsing it as if it is UTC will yield time // since 1/1/1970 local time - Date datetime = sFormatter.parse(dateTimeString, pos); + Date datetime; + synchronized (sFormatter) { + datetime = sFormatter.parse(dateTimeString, pos); + } if (offsetString != null) { dateTimeString = dateTimeString + " " + offsetString; ParsePosition position = new ParsePosition(0); - datetime = sFormatterTz.parse(dateTimeString, position); + synchronized (sFormatterTz) { + datetime = sFormatterTz.parse(dateTimeString, position); + } } if (datetime == null) return -1; @@ -2473,7 +2481,10 @@ public class ExifInterface { ParsePosition pos = new ParsePosition(0); try { - Date datetime = sFormatter.parse(dateTimeString, pos); + final Date datetime; + synchronized (sFormatter) { + datetime = sFormatter.parse(dateTimeString, pos); + } if (datetime == null) return -1; return datetime.getTime(); } catch (IllegalArgumentException e) { diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index bb10e1fe2f2c..e3b67f86a367 100644..100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -301,4 +301,6 @@ interface IAudioService { // WARNING: read warning at top of file, new methods that need to be used by native // code via IAudioManager.h need to be added to the top section. + + oneway void setMultiAudioFocusEnabled(in boolean enabled); } diff --git a/media/java/android/media/MediaMetrics.java b/media/java/android/media/MediaMetrics.java index 88a829546989..540955f3b393 100644 --- a/media/java/android/media/MediaMetrics.java +++ b/media/java/android/media/MediaMetrics.java @@ -17,6 +17,7 @@ package android.media; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.TestApi; import android.os.Bundle; @@ -24,6 +25,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.Objects; /** * MediaMetrics is the Java interface to the MediaMetrics service. @@ -50,6 +52,77 @@ public class MediaMetrics { private static final Charset MEDIAMETRICS_CHARSET = StandardCharsets.UTF_8; /** + * Key interface. + * + * The presence of this {@code Key} interface on an object allows + * it to be used to set metrics. + * + * @param <T> type of value associated with {@code Key}. + */ + public interface Key<T> { + /** + * Returns the internal name of the key. + */ + @NonNull + String getName(); + + /** + * Returns the class type of the associated value. + */ + @NonNull + Class<T> getValueClass(); + } + + /** + * Returns a Key object with the correct interface for MediaMetrics. + * + * @param name The name of the key. + * @param type The class type of the value represented by the key. + * @param <T> The type of value. + * @return a new key interface. + */ + @NonNull + public static <T> Key<T> createKey(@NonNull String name, @NonNull Class<T> type) { + // Implementation specific. + return new Key<T>() { + private final String mName = name; + private final Class<T> mType = type; + + @Override + @NonNull + public String getName() { + return mName; + } + + @Override + @NonNull + public Class<T> getValueClass() { + return mType; + } + + /** + * Return true if the name and the type of two objects are the same. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Key)) { + return false; + } + Key<?> other = (Key<?>) obj; + return mName.equals(other.getName()) && mType.equals(other.getValueClass()); + } + + @Override + public int hashCode() { + return Objects.hash(mName, mType); + } + }; + } + + /** * Item records properties and delivers to the MediaMetrics service * */ @@ -202,6 +275,28 @@ public class MediaMetrics { } /** + * Sets a metrics typed key + * @param key + * @param value + * @param <T> + * @return + */ + @NonNull + public <T> Item set(@NonNull Key<T> key, @Nullable T value) { + if (value instanceof Integer) { + putInt(key.getName(), (int) value); + } else if (value instanceof Long) { + putLong(key.getName(), (long) value); + } else if (value instanceof Double) { + putDouble(key.getName(), (double) value); + } else if (value instanceof String) { + putString(key.getName(), (String) value); + } + // if value is null, etc. no error is raised. + return this; + } + + /** * Sets the property with key to an integer (32 bit) value. * * @param key diff --git a/media/java/android/media/midi/MidiDeviceInfo.java b/media/java/android/media/midi/MidiDeviceInfo.java index c2229850b4ce..dd3b6dbd6a39 100644 --- a/media/java/android/media/midi/MidiDeviceInfo.java +++ b/media/java/android/media/midi/MidiDeviceInfo.java @@ -19,7 +19,6 @@ package android.media.midi; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; - import android.util.Log; /** @@ -205,6 +204,20 @@ public final class MidiDeviceInfo implements Parcelable { public MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts, String[] inputPortNames, String[] outputPortNames, Bundle properties, boolean isPrivate) { + // Check num ports for out-of-range values. Typical values will be + // between zero and three. More than 16 would be very unlikely + // because the port index field in the USB packet is only 4 bits. + // This check is mainly just to prevent OutOfMemoryErrors when + // fuzz testing. + final int maxPorts = 256; // arbitrary and very high + if (numInputPorts < 0 || numInputPorts > maxPorts) { + throw new IllegalArgumentException("numInputPorts out of range = " + + numInputPorts); + } + if (numOutputPorts < 0 || numOutputPorts > maxPorts) { + throw new IllegalArgumentException("numOutputPorts out of range = " + + numOutputPorts); + } mType = type; mId = id; mInputPortCount = numInputPorts; diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 48aed349c39a..861eeea3bc34 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -394,7 +394,7 @@ public class Tuner implements AutoCloseable { private native Lnb nativeOpenLnbByName(String name); private native Descrambler nativeOpenDescramblerByHandle(int handle); - private native Descrambler nativeOpenDemuxByhandle(int handle); + private native int nativeOpenDemuxByhandle(int handle); private native DvrRecorder nativeOpenDvrRecorder(long bufferSize); private native DvrPlayback nativeOpenDvrPlayback(long bufferSize); @@ -985,7 +985,7 @@ public class Tuner implements AutoCloseable { boolean granted = mTunerResourceManager.requestDescrambler(request, descramblerHandle); if (granted) { mDescramblerHandle = descramblerHandle[0]; - nativeOpenDescramblerByHandle(mDescramblerHandle); + mDescrambler = nativeOpenDescramblerByHandle(mDescramblerHandle); } return granted; } diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index fc9b91c76a4f..a31f177d66ab 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -676,8 +676,6 @@ status_t JMediaCodec::getOutputFrame( if (buffer->size() > 0) { std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer(); if (c2Buffer) { - // asC2Buffer clears internal reference, so set the reference again. - buffer->copy(c2Buffer); switch (c2Buffer->data().type()) { case C2BufferData::LINEAR: { std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock}; @@ -2526,7 +2524,7 @@ static void android_media_MediaCodec_setAudioPresentation( codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId); } -static void android_media_MediaCodec_native_init(JNIEnv *env) { +static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) { ScopedLocalRef<jclass> clazz( env, env->FindClass("android/media/MediaCodec")); CHECK(clazz.get() != NULL); @@ -2983,7 +2981,7 @@ static void android_media_MediaCodec_LinearBlock_native_obtain( } static jboolean android_media_MediaCodec_LinearBlock_checkCompatible( - JNIEnv *env, jobjectArray codecNames) { + JNIEnv *env, jclass, jobjectArray codecNames) { std::vector<std::string> names; PopulateNamesVector(env, codecNames, &names); bool isCompatible = false; diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index ac7fe5d0403d..7579ca58b37b 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -880,10 +880,12 @@ jobject JTuner::getFrontendIds() { jobject JTuner::openFrontendById(int id) { sp<IFrontend> fe; - mTuner->openFrontendById(id, [&](Result, const sp<IFrontend>& frontend) { + Result res; + mTuner->openFrontendById(id, [&](Result r, const sp<IFrontend>& frontend) { fe = frontend; + res = r; }); - if (fe == nullptr) { + if (res != Result::SUCCESS || fe == nullptr) { ALOGE("Failed to open frontend"); return NULL; } @@ -906,7 +908,7 @@ jobject JTuner::openFrontendById(int id) { (jint) jId); } -jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V"); @@ -915,7 +917,7 @@ jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabil return env->NewObject(clazz, capsInit, typeCap, sifStandardCap); } -jobject JTuner::getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3FrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIII)V"); @@ -930,7 +932,7 @@ jobject JTuner::getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabili codeRateCap, fecCap, demodOutputFormatCap); } -jobject JTuner::getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AtscFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(I)V"); @@ -939,7 +941,7 @@ jobject JTuner::getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilit return env->NewObject(clazz, capsInit, modulationCap); } -jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(III)V"); @@ -950,7 +952,7 @@ jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilit return env->NewObject(clazz, capsInit, modulationCap, fecCap, annexCap); } -jobject JTuner::getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IJI)V"); @@ -961,7 +963,7 @@ jobject JTuner::getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilit return env->NewObject(clazz, capsInit, modulationCap, innerfecCap, standard); } -jobject JTuner::getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbtFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIIIZZ)V"); @@ -978,7 +980,7 @@ jobject JTuner::getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilit coderateCap, hierarchyCap, guardIntervalCap, isT2Supported, isMisoSupported); } -jobject JTuner::getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V"); @@ -988,7 +990,7 @@ jobject JTuner::getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabil return env->NewObject(clazz, capsInit, modulationCap, coderateCap); } -jobject JTuner::getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbsFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V"); @@ -998,7 +1000,7 @@ jobject JTuner::getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabili return env->NewObject(clazz, capsInit, modulationCap, coderateCap); } -jobject JTuner::getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbtFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIII)V"); @@ -1044,31 +1046,58 @@ jobject JTuner::getFrontendInfo(int id) { jobject jcaps = NULL; switch(feInfo.type) { case FrontendType::ANALOG: - jcaps = getAnalogFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::analogCaps + == caps.getDiscriminator()) { + jcaps = getAnalogFrontendCaps(env, caps); + } break; case FrontendType::ATSC3: - jcaps = getAtsc3FrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::atsc3Caps + == caps.getDiscriminator()) { + jcaps = getAtsc3FrontendCaps(env, caps); + } break; case FrontendType::ATSC: - jcaps = getAtscFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::atscCaps + == caps.getDiscriminator()) { + jcaps = getAtscFrontendCaps(env, caps); + } break; case FrontendType::DVBC: - jcaps = getDvbcFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbcCaps + == caps.getDiscriminator()) { + jcaps = getDvbcFrontendCaps(env, caps); + } break; case FrontendType::DVBS: - jcaps = getDvbsFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbsCaps + == caps.getDiscriminator()) { + jcaps = getDvbsFrontendCaps(env, caps); + } break; case FrontendType::DVBT: - jcaps = getDvbtFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbtCaps + == caps.getDiscriminator()) { + jcaps = getDvbtFrontendCaps(env, caps); + } break; case FrontendType::ISDBS: - jcaps = getIsdbsFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbsCaps + == caps.getDiscriminator()) { + jcaps = getIsdbsFrontendCaps(env, caps); + } break; case FrontendType::ISDBS3: - jcaps = getIsdbs3FrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbs3Caps + == caps.getDiscriminator()) { + jcaps = getIsdbs3FrontendCaps(env, caps); + } break; case FrontendType::ISDBT: - jcaps = getIsdbtFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbtCaps + == caps.getDiscriminator()) { + jcaps = getIsdbtFrontendCaps(env, caps); + } break; default: break; @@ -2308,7 +2337,7 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { gFields.dvrPlaybackContext = env->GetFieldID(dvrPlaybackClazz, "mNativeContext", "J"); gFields.dvrPlaybackInitID = env->GetMethodID(dvrPlaybackClazz, "<init>", "()V"); gFields.onDvrPlaybackStatusID = - env->GetMethodID(dvrRecorderClazz, "onPlaybackStatusChanged", "(I)V"); + env->GetMethodID(dvrPlaybackClazz, "onPlaybackStatusChanged", "(I)V"); jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock"); gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "<init>", "()V"); @@ -3101,6 +3130,11 @@ static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv* env, jobject thiz) return tuner->getDemuxCaps(); } +static jint android_media_tv_Tuner_open_demux(JNIEnv* env, jobject thiz, jint /* handle */) { + sp<JTuner> tuner = getTuner(env, thiz); + return (jint) tuner->openDemux(); +} + static jint android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<Dvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { @@ -3425,6 +3459,7 @@ static const JNINativeMethod gTunerMethods[] = { (void *)android_media_tv_Tuner_open_dvr_playback }, { "nativeGetDemuxCapabilities", "()Landroid/media/tv/tuner/DemuxCapabilities;", (void *)android_media_tv_Tuner_get_demux_caps }, + { "nativeOpenDemuxByhandle", "(I)I", (void *)android_media_tv_Tuner_open_demux }, }; static const JNINativeMethod gFilterMethods[] = { diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index 73fc38dbdec8..6749ba085739 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -188,9 +188,9 @@ struct JTuner : public RefBase { jobject openDvr(DvrType type, jlong bufferSize); jobject getDemuxCaps(); jobject getFrontendStatus(jintArray types); + Result openDemux(); protected: - Result openDemux(); virtual ~JTuner(); private: @@ -204,15 +204,15 @@ private: sp<ILnb> mLnb; sp<IDemux> mDemux; uint32_t mDemuxId; - static jobject getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); + static jobject getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); }; } // namespace android diff --git a/media/tests/AudioPolicyTest/Android.bp b/media/tests/AudioPolicyTest/Android.bp new file mode 100644 index 000000000000..ed3383752695 --- /dev/null +++ b/media/tests/AudioPolicyTest/Android.bp @@ -0,0 +1,17 @@ +android_test { + name: "audiopolicytest", + srcs: ["**/*.java"], + libs: [ + "android.test.runner", + "android.test.base", + ], + static_libs: [ + "mockito-target-minus-junit4", + "androidx.test.rules", + "android-ex-camera2", + "testng", + ], + platform_apis: true, + certificate: "platform", + resource_dirs: ["res"], +} diff --git a/media/tests/AudioPolicyTest/AndroidManifest.xml b/media/tests/AudioPolicyTest/AndroidManifest.xml new file mode 100644 index 000000000000..adb058c82870 --- /dev/null +++ b/media/tests/AudioPolicyTest/AndroidManifest.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.audiopolicytest"> + + <uses-permission android:name="android.permission.RECORD_AUDIO" /> + <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> + <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" /> + <uses-permission android:name="android.permission.CHANGE_ACCESSIBILITY_VOLUME" /> + + <application> + <uses-library android:name="android.test.runner" /> + <activity android:label="@string/app_name" android:name="AudioPolicyTest" + android:screenOrientation="landscape"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + </application> + + <!--instrumentation android:name=".AudioPolicyTestRunner" + android:targetPackage="com.android.audiopolicytest" + android:label="AudioManager policy oriented integration tests InstrumentationRunner"> + </instrumentation--> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.audiopolicytest" + android:label="AudioManager policy oriented integration tests InstrumentationRunner"> + </instrumentation> +</manifest> diff --git a/cmds/statsd/AndroidTest.xml b/media/tests/AudioPolicyTest/AndroidTest.xml index afe30a269093..f3ca9a165d1b 100644 --- a/cmds/statsd/AndroidTest.xml +++ b/media/tests/AudioPolicyTest/AndroidTest.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 The Android Open Source Project +<!-- 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. @@ -13,14 +13,15 @@ See the License for the specific language governing permissions and limitations under the License. --> -<configuration description="Config for statsd_test"> - <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> - <option name="cleanup" value="true" /> - <option name="push" value="statsd_test->/data/nativetest/statsd_test" /> +<configuration description="Runs Media Framework Tests"> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="audiopolicytest.apk" /> </target_preparer> - <option name="test-suite-tag" value="apct" /> - <test class="com.android.tradefed.testtype.GTest" > - <option name="native-test-device-path" value="/data/nativetest" /> - <option name="module-name" value="statsd_test" /> + + <option name="test-tag" value="AudioPolicyTest" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.audiopolicytest" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> </test> -</configuration>
\ No newline at end of file +</configuration> diff --git a/media/tests/AudioPolicyTest/res/layout/audiopolicytest.xml b/media/tests/AudioPolicyTest/res/layout/audiopolicytest.xml new file mode 100644 index 000000000000..17fdba6f7c15 --- /dev/null +++ b/media/tests/AudioPolicyTest/res/layout/audiopolicytest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:orientation="vertical"> +</LinearLayout> diff --git a/media/tests/AudioPolicyTest/res/values/strings.xml b/media/tests/AudioPolicyTest/res/values/strings.xml new file mode 100644 index 000000000000..036592770450 --- /dev/null +++ b/media/tests/AudioPolicyTest/res/values/strings.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- name of the app [CHAR LIMIT=25]--> + <string name="app_name">Audio Policy APIs Tests</string> +</resources> diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java new file mode 100644 index 000000000000..1131c623e428 --- /dev/null +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java @@ -0,0 +1,328 @@ +/* + * 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.audiopolicytest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.testng.Assert.assertThrows; + +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.media.AudioSystem; +import android.media.audiopolicy.AudioProductStrategy; +import android.media.audiopolicy.AudioVolumeGroup; +import android.util.Log; + +import com.google.common.primitives.Ints; + +import java.util.List; + +public class AudioManagerTest extends AudioVolumesTestBase { + private static final String TAG = "AudioManagerTest"; + + //----------------------------------------------------------------- + // Test getAudioProductStrategies and validate strategies + //----------------------------------------------------------------- + public void testGetAndValidateProductStrategies() throws Exception { + List<AudioProductStrategy> audioProductStrategies = + mAudioManager.getAudioProductStrategies(); + assertTrue(audioProductStrategies.size() > 0); + + List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); + assertTrue(audioVolumeGroups.size() > 0); + + // Validate Audio Product Strategies + for (final AudioProductStrategy audioProductStrategy : audioProductStrategies) { + AudioAttributes attributes = audioProductStrategy.getAudioAttributes(); + int strategyStreamType = + audioProductStrategy.getLegacyStreamTypeForAudioAttributes(attributes); + + assertTrue("Strategy shall support the attributes retrieved from its getter API", + audioProductStrategy.supportsAudioAttributes(attributes)); + + int volumeGroupId = + audioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes); + + // A strategy must be associated to a volume group + assertNotEquals("strategy not assigned to any volume group", + volumeGroupId, AudioVolumeGroup.DEFAULT_VOLUME_GROUP); + + // Valid Group ? + AudioVolumeGroup audioVolumeGroup = null; + for (final AudioVolumeGroup avg : audioVolumeGroups) { + if (avg.getId() == volumeGroupId) { + audioVolumeGroup = avg; + break; + } + } + assertNotNull("Volume Group not found", audioVolumeGroup); + + // Cross check: the group shall have at least one aa / stream types following the + // considered strategy + boolean strategyAttributesSupported = false; + for (final AudioAttributes aa : audioVolumeGroup.getAudioAttributes()) { + if (audioProductStrategy.supportsAudioAttributes(aa)) { + strategyAttributesSupported = true; + break; + } + } + assertTrue("Volume Group and Strategy mismatching", strategyAttributesSupported); + + // Some Product strategy may not have corresponding stream types as they intends + // to address volume setting per attributes to avoid adding new stream type + // and going on deprecating the stream type even for volume + if (strategyStreamType != AudioSystem.STREAM_DEFAULT) { + boolean strategStreamTypeSupported = false; + for (final int vgStreamType : audioVolumeGroup.getLegacyStreamTypes()) { + if (vgStreamType == strategyStreamType) { + strategStreamTypeSupported = true; + break; + } + } + assertTrue("Volume Group and Strategy mismatching", strategStreamTypeSupported); + } + } + } + + //----------------------------------------------------------------- + // Test getAudioVolumeGroups and validate volume groups + //----------------------------------------------------------------- + + public void testGetAndValidateVolumeGroups() throws Exception { + List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); + assertTrue(audioVolumeGroups.size() > 0); + + List<AudioProductStrategy> audioProductStrategies = + mAudioManager.getAudioProductStrategies(); + assertTrue(audioProductStrategies.size() > 0); + + // Validate Audio Volume Groups, check all + for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) { + List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes(); + int[] avgStreamTypes = audioVolumeGroup.getLegacyStreamTypes(); + + // for each volume group attributes, find the matching product strategy and ensure + // it is linked the considered volume group + for (final AudioAttributes aa : avgAttributes) { + if (aa.equals(sDefaultAttributes)) { + // Some volume groups may not have valid attributes, used for internal + // volume management like patch/rerouting + // so bailing out strategy retrieval from attributes + continue; + } + boolean isVolumeGroupAssociatedToStrategy = false; + for (final AudioProductStrategy strategy : audioProductStrategies) { + int groupId = strategy.getVolumeGroupIdForAudioAttributes(aa); + if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { + + assertEquals("Volume Group ID (" + audioVolumeGroup.toString() + + "), and Volume group ID associated to Strategy (" + + strategy.toString() + ") both supporting attributes " + + aa.toString() + " are mismatching", + audioVolumeGroup.getId(), groupId); + isVolumeGroupAssociatedToStrategy = true; + break; + } + } + assertTrue("Volume Group (" + audioVolumeGroup.toString() + + ") has no associated strategy for attributes " + aa.toString(), + isVolumeGroupAssociatedToStrategy); + } + + // for each volume group stream type, find the matching product strategy and ensure + // it is linked the considered volume group + for (final int avgStreamType : avgStreamTypes) { + if (avgStreamType == AudioSystem.STREAM_DEFAULT) { + // Some Volume Groups may not have corresponding stream types as they + // intends to address volume setting per attributes to avoid adding new + // stream type and going on deprecating the stream type even for volume + // so bailing out strategy retrieval from stream type + continue; + } + boolean isVolumeGroupAssociatedToStrategy = false; + for (final AudioProductStrategy strategy : audioProductStrategies) { + Log.i(TAG, "strategy:" + strategy.toString()); + int groupId = strategy.getVolumeGroupIdForLegacyStreamType(avgStreamType); + if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { + + assertEquals("Volume Group ID (" + audioVolumeGroup.toString() + + "), and Volume group ID associated to Strategy (" + + strategy.toString() + ") both supporting stream " + + AudioSystem.streamToString(avgStreamType) + "(" + + avgStreamType + ") are mismatching", + audioVolumeGroup.getId(), groupId); + isVolumeGroupAssociatedToStrategy = true; + break; + } + } + assertTrue("Volume Group (" + audioVolumeGroup.toString() + + ") has no associated strategy for stream " + + AudioSystem.streamToString(avgStreamType) + "(" + avgStreamType + ")", + isVolumeGroupAssociatedToStrategy); + } + } + } + + //----------------------------------------------------------------- + // Test Volume per Attributes setter/getters + //----------------------------------------------------------------- + public void testSetGetVolumePerAttributesWithInvalidAttributes() throws Exception { + AudioAttributes nullAttributes = null; + + assertThrows(NullPointerException.class, + () -> mAudioManager.getMaxVolumeIndexForAttributes(nullAttributes)); + + assertThrows(NullPointerException.class, + () -> mAudioManager.getMinVolumeIndexForAttributes(nullAttributes)); + + assertThrows(NullPointerException.class, + () -> mAudioManager.getVolumeIndexForAttributes(nullAttributes)); + + assertThrows(NullPointerException.class, + () -> mAudioManager.setVolumeIndexForAttributes( + nullAttributes, 0 /*index*/, 0/*flags*/)); + } + + public void testSetGetVolumePerAttributes() throws Exception { + for (int usage : AudioAttributes.SDK_USAGES) { + if (usage == AudioAttributes.USAGE_UNKNOWN) { + continue; + } + AudioAttributes aaForUsage = new AudioAttributes.Builder().setUsage(usage).build(); + int indexMin = 0; + int indexMax = 0; + int index = 0; + Exception ex = null; + + try { + indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aaForUsage); + } catch (Exception e) { + ex = e; // unexpected + } + assertNull("Exception was thrown for valid attributes", ex); + ex = null; + try { + indexMin = mAudioManager.getMinVolumeIndexForAttributes(aaForUsage); + } catch (Exception e) { + ex = e; // unexpected + } + assertNull("Exception was thrown for valid attributes", ex); + ex = null; + try { + index = mAudioManager.getVolumeIndexForAttributes(aaForUsage); + } catch (Exception e) { + ex = e; // unexpected + } + assertNull("Exception was thrown for valid attributes", ex); + ex = null; + try { + mAudioManager.setVolumeIndexForAttributes(aaForUsage, indexMin, 0/*flags*/); + } catch (Exception e) { + ex = e; // unexpected + } + assertNull("Exception was thrown for valid attributes", ex); + + index = mAudioManager.getVolumeIndexForAttributes(aaForUsage); + assertEquals(index, indexMin); + + mAudioManager.setVolumeIndexForAttributes(aaForUsage, indexMax, 0/*flags*/); + index = mAudioManager.getVolumeIndexForAttributes(aaForUsage); + assertEquals(index, indexMax); + } + } + + //----------------------------------------------------------------- + // Test register/unregister VolumeGroupCallback + //----------------------------------------------------------------- + public void testVolumeGroupCallback() throws Exception { + List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); + assertTrue(audioVolumeGroups.size() > 0); + + AudioVolumeGroupCallbackHelper vgCbReceiver = new AudioVolumeGroupCallbackHelper(); + mAudioManager.registerVolumeGroupCallback(mContext.getMainExecutor(), vgCbReceiver); + + final List<Integer> publicStreams = Ints.asList(PUBLIC_STREAM_TYPES); + try { + // Validate Audio Volume Groups callback reception + for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) { + int volumeGroupId = audioVolumeGroup.getId(); + + // Set the receiver to filter only the current group callback + vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); + + List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes(); + int[] avgStreamTypes = audioVolumeGroup.getLegacyStreamTypes(); + + int index = 0; + int indexMax = 0; + int indexMin = 0; + + // Set the volume per attributes (if valid) and wait the callback + for (final AudioAttributes aa : avgAttributes) { + if (aa.equals(sDefaultAttributes)) { + // Some volume groups may not have valid attributes, used for internal + // volume management like patch/rerouting + // so bailing out strategy retrieval from attributes + continue; + } + index = mAudioManager.getVolumeIndexForAttributes(aa); + indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aa); + indexMin = mAudioManager.getMinVolumeIndexForAttributes(aa); + index = incrementVolumeIndex(index, indexMin, indexMax); + + vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); + mAudioManager.setVolumeIndexForAttributes(aa, index, 0/*flags*/); + assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( + AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); + + int readIndex = mAudioManager.getVolumeIndexForAttributes(aa); + assertEquals(readIndex, index); + } + // Set the volume per stream type (if valid) and wait the callback + for (final int avgStreamType : avgStreamTypes) { + if (avgStreamType == AudioSystem.STREAM_DEFAULT) { + // Some Volume Groups may not have corresponding stream types as they + // intends to address volume setting per attributes to avoid adding new + // stream type and going on deprecating the stream type even for volume + // so bailing out strategy retrieval from stream type + continue; + } + if (!publicStreams.contains(avgStreamType) + || avgStreamType == AudioManager.STREAM_ACCESSIBILITY) { + // Limit scope of test to public stream that do not require any + // permission (e.g. Changing ACCESSIBILITY is subject to permission). + continue; + } + index = mAudioManager.getStreamVolume(avgStreamType); + indexMax = mAudioManager.getStreamMaxVolume(avgStreamType); + indexMin = mAudioManager.getStreamMinVolumeInt(avgStreamType); + index = incrementVolumeIndex(index, indexMin, indexMax); + + vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); + mAudioManager.setStreamVolume(avgStreamType, index, 0/*flags*/); + assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( + AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); + + int readIndex = mAudioManager.getStreamVolume(avgStreamType); + assertEquals(index, readIndex); + } + } + } finally { + mAudioManager.unregisterVolumeGroupCallback(vgCbReceiver); + } + } +} diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyTest.java new file mode 100644 index 000000000000..e0c7b223a2e4 --- /dev/null +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioPolicyTest.java @@ -0,0 +1,38 @@ +/* + * 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.audiopolicytest; + +import android.app.Activity; +import android.os.Bundle; + +public class AudioPolicyTest extends Activity { + + public AudioPolicyTest() { + } + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + setContentView(R.layout.audiopolicytest); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } +} diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java new file mode 100644 index 000000000000..c0f596b974e1 --- /dev/null +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioProductStrategyTest.java @@ -0,0 +1,213 @@ +/* + * 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.audiopolicytest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.media.AudioAttributes; +import android.media.AudioSystem; +import android.media.audiopolicy.AudioProductStrategy; +import android.media.audiopolicy.AudioVolumeGroup; +import android.util.Log; + +import java.util.List; + +public class AudioProductStrategyTest extends AudioVolumesTestBase { + private static final String TAG = "AudioProductStrategyTest"; + + //----------------------------------------------------------------- + // Test getAudioProductStrategies and validate strategies + //----------------------------------------------------------------- + public void testGetProductStrategies() throws Exception { + List<AudioProductStrategy> audioProductStrategies = + AudioProductStrategy.getAudioProductStrategies(); + + assertNotNull(audioProductStrategies); + assertTrue(audioProductStrategies.size() > 0); + + for (final AudioProductStrategy aps : audioProductStrategies) { + assertTrue(aps.getId() >= 0); + + AudioAttributes aa = aps.getAudioAttributes(); + assertNotNull(aa); + + // Ensure API consistency + assertTrue(aps.supportsAudioAttributes(aa)); + + int streamType = aps.getLegacyStreamTypeForAudioAttributes(aa); + if (streamType == AudioSystem.STREAM_DEFAULT) { + // bailing out test for volume group APIs consistency + continue; + } + final int volumeGroupFromStream = aps.getVolumeGroupIdForLegacyStreamType(streamType); + final int volumeGroupFromAttributes = aps.getVolumeGroupIdForAudioAttributes(aa); + assertNotEquals(volumeGroupFromStream, AudioVolumeGroup.DEFAULT_VOLUME_GROUP); + assertEquals(volumeGroupFromStream, volumeGroupFromAttributes); + } + } + + //----------------------------------------------------------------- + // Test stream to/from attributes conversion + //----------------------------------------------------------------- + public void testAudioAttributesFromStreamTypes() throws Exception { + List<AudioProductStrategy> audioProductStrategies = + AudioProductStrategy.getAudioProductStrategies(); + + assertNotNull(audioProductStrategies); + assertTrue(audioProductStrategies.size() > 0); + + for (final int streamType : PUBLIC_STREAM_TYPES) { + AudioAttributes aaFromStreamType = + AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( + streamType); + + // No strategy found for this stream type or no attributes defined for the strategy + // hosting this stream type; Bailing out the test, just ensure that any request + // for reciproque API with the unknown attributes would return default stream + // for volume control, aka STREAM_MUSIC. + if (aaFromStreamType.equals(sInvalidAttributes)) { + assertEquals(AudioSystem.STREAM_MUSIC, + AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes( + aaFromStreamType)); + } else { + // Attributes are valid, i.e. a strategy was found supporting this stream type + // with valid attributes. Ensure reciproque works fine + int streamTypeFromAttributes = + AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes( + aaFromStreamType); + assertEquals("stream " + AudioSystem.streamToString(streamType) + "(" + + streamType + ") expected to match attributes " + + aaFromStreamType.toString() + " got instead stream " + + AudioSystem.streamToString(streamTypeFromAttributes) + "(" + + streamTypeFromAttributes + ") expected to match attributes ", + streamType, streamTypeFromAttributes); + } + + // Now identify the strategy supporting this stream type, ensure uniqueness + boolean strategyFound = false; + for (final AudioProductStrategy aps : audioProductStrategies) { + AudioAttributes aaFromAps = + aps.getAudioAttributesForLegacyStreamType(streamType); + + if (aaFromAps == null) { + // not this one... + continue; + } + // Got it! + assertFalse("Unique ProductStrategy shall match for a given stream type", + strategyFound); + strategyFound = true; + + // Ensure getters aligned + assertEquals(aaFromStreamType, aaFromAps); + assertTrue(aps.supportsAudioAttributes(aaFromStreamType)); + + // Ensure reciproque works fine + assertEquals(streamType, + aps.getLegacyStreamTypeForAudioAttributes(aaFromStreamType)); + + // Ensure consistency of volume group getter API + final int volumeGroupFromStream = + aps.getVolumeGroupIdForLegacyStreamType(streamType); + final int volumeGroupFromAttributes = + aps.getVolumeGroupIdForAudioAttributes(aaFromStreamType); + assertNotEquals(volumeGroupFromStream, AudioVolumeGroup.DEFAULT_VOLUME_GROUP); + assertEquals(volumeGroupFromStream, volumeGroupFromAttributes); + } + if (!strategyFound) { + // No strategy found, ensure volume control is MUSIC + assertEquals(AudioSystem.STREAM_MUSIC, + AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes( + aaFromStreamType)); + } + } + } + + public void testAudioAttributesToStreamTypes() throws Exception { + List<AudioProductStrategy> audioProductStrategies = + AudioProductStrategy.getAudioProductStrategies(); + + assertNotNull(audioProductStrategies); + assertTrue(audioProductStrategies.size() > 0); + + for (int usage : AudioAttributes.SDK_USAGES) { + AudioAttributes aaForUsage = new AudioAttributes.Builder().setUsage(usage).build(); + + int streamTypeFromUsage = + AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes( + aaForUsage); + + // Cannot be undefined, always shall fall back on a valid stream type + // to be able to control the volume + assertNotEquals(streamTypeFromUsage, AudioSystem.STREAM_DEFAULT); + + Log.w(TAG, "GUSTAVE aaForUsage=" + aaForUsage.toString()); + + // Now identify the strategy hosting these Audio Attributes and ensure informations + // matches. + // Now identify the strategy supporting this stream type, ensure uniqueness + boolean strategyFound = false; + for (final AudioProductStrategy aps : audioProductStrategies) { + if (!aps.supportsAudioAttributes(aaForUsage)) { + // Not this one + continue; + } + // Got it! + String msg = "Unique ProductStrategy shall match for a given audio attributes " + + aaForUsage.toString() + " already associated also matches with" + + aps.toString(); + assertFalse(msg, strategyFound); + strategyFound = true; + + // It may not return the expected stream type if the strategy does not have + // associated stream type. + // Behavior of member function getLegacyStreamTypeForAudioAttributes is + // different than getLegacyStreamTypeForStrategyWithAudioAttributes since it + // does not fallback on MUSIC stream type for volume operation + int streamTypeFromAps = aps.getLegacyStreamTypeForAudioAttributes(aaForUsage); + if (streamTypeFromAps == AudioSystem.STREAM_DEFAULT) { + // No stream type assigned to this strategy + // Expect static API to return default stream type for volume (aka MUSIC) + assertEquals("Strategy (" + aps.toString() + ") has no associated stream " + + ", must fallback on MUSIC stream as default", + streamTypeFromUsage, AudioSystem.STREAM_MUSIC); + } else { + assertEquals("Attributes " + aaForUsage.toString() + " associated to stream " + + AudioSystem.streamToString(streamTypeFromUsage) + + " are supported by strategy (" + aps.toString() + ") which reports " + + " these attributes are associated to stream " + + AudioSystem.streamToString(streamTypeFromAps), + streamTypeFromUsage, streamTypeFromAps); + + // Ensure consistency of volume group getter API + int volumeGroupFromStream = + aps.getVolumeGroupIdForLegacyStreamType(streamTypeFromAps); + int volumeGroupFromAttributes = + aps.getVolumeGroupIdForAudioAttributes(aaForUsage); + assertNotEquals( + volumeGroupFromStream, AudioVolumeGroup.DEFAULT_VOLUME_GROUP); + assertEquals(volumeGroupFromStream, volumeGroupFromAttributes); + } + } + if (!strategyFound) { + // No strategy found for the given attributes, the expected stream must be MUSIC + assertEquals(streamTypeFromUsage, AudioSystem.STREAM_MUSIC); + } + } + } +} diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumeGroupCallbackHelper.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumeGroupCallbackHelper.java new file mode 100644 index 000000000000..0c1d52c57020 --- /dev/null +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumeGroupCallbackHelper.java @@ -0,0 +1,69 @@ +/* + * 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.audiopolicytest; + +import static org.junit.Assert.assertNotNull; + +import android.media.AudioManager; +import android.util.Log; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + + +final class AudioVolumeGroupCallbackHelper extends AudioManager.VolumeGroupCallback { + private static final String TAG = "AudioVolumeGroupCallbackHelper"; + public static final long ASYNC_TIMEOUT_MS = 800; + + private int mExpectedVolumeGroupId; + + private CountDownLatch mVolumeGroupChanged = null; + + void setExpectedVolumeGroup(int group) { + mVolumeGroupChanged = new CountDownLatch(1); + mExpectedVolumeGroupId = group; + } + + @Override + public void onAudioVolumeGroupChanged(int group, int flags) { + if (group != mExpectedVolumeGroupId) { + return; + } + if (mVolumeGroupChanged == null) { + Log.wtf(TAG, "Received callback but object not initialized"); + return; + } + if (mVolumeGroupChanged.getCount() <= 0) { + Log.i(TAG, "callback for group: " + group + " already received"); + return; + } + mVolumeGroupChanged.countDown(); + } + + public boolean waitForExpectedVolumeGroupChanged(long timeOutMs) { + assertNotNull("Call first setExpectedVolumeGroup before waiting...", mVolumeGroupChanged); + boolean timeoutReached = false; + if (mVolumeGroupChanged.getCount() == 0) { + // done already... + return true; + } + try { + timeoutReached = !mVolumeGroupChanged.await(ASYNC_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { } + return !timeoutReached; + } +} diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumeGroupChangeHandlerTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumeGroupChangeHandlerTest.java new file mode 100644 index 000000000000..221f1f7fef17 --- /dev/null +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumeGroupChangeHandlerTest.java @@ -0,0 +1,180 @@ +/* + * 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.audiopolicytest; + +import static org.junit.Assert.assertEquals; +import static org.testng.Assert.assertThrows; + +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.media.audiopolicy.AudioVolumeGroup; +import android.media.audiopolicy.AudioVolumeGroupChangeHandler; + +import java.util.ArrayList; +import java.util.List; + +public class AudioVolumeGroupChangeHandlerTest extends AudioVolumesTestBase { + private static final String TAG = "AudioVolumeGroupChangeHandlerTest"; + + public void testRegisterInvalidCallback() throws Exception { + final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler = + new AudioVolumeGroupChangeHandler(); + + audioAudioVolumeGroupChangedHandler.init(); + + assertThrows(NullPointerException.class, () -> { + AudioManager.VolumeGroupCallback nullCb = null; + audioAudioVolumeGroupChangedHandler.registerListener(nullCb); + }); + } + + public void testUnregisterInvalidCallback() throws Exception { + final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler = + new AudioVolumeGroupChangeHandler(); + + audioAudioVolumeGroupChangedHandler.init(); + + final AudioVolumeGroupCallbackHelper cb = new AudioVolumeGroupCallbackHelper(); + audioAudioVolumeGroupChangedHandler.registerListener(cb); + + assertThrows(NullPointerException.class, () -> { + AudioManager.VolumeGroupCallback nullCb = null; + audioAudioVolumeGroupChangedHandler.unregisterListener(nullCb); + }); + audioAudioVolumeGroupChangedHandler.unregisterListener(cb); + } + + public void testRegisterUnregisterCallback() throws Exception { + final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler = + new AudioVolumeGroupChangeHandler(); + + audioAudioVolumeGroupChangedHandler.init(); + final AudioVolumeGroupCallbackHelper validCb = new AudioVolumeGroupCallbackHelper(); + + // Should not assert, otherwise test will fail + audioAudioVolumeGroupChangedHandler.registerListener(validCb); + + // Should not assert, otherwise test will fail + audioAudioVolumeGroupChangedHandler.unregisterListener(validCb); + } + + public void testCallbackReceived() throws Exception { + final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler = + new AudioVolumeGroupChangeHandler(); + + audioAudioVolumeGroupChangedHandler.init(); + + final AudioVolumeGroupCallbackHelper validCb = new AudioVolumeGroupCallbackHelper(); + audioAudioVolumeGroupChangedHandler.registerListener(validCb); + + List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); + assertTrue(audioVolumeGroups.size() > 0); + + try { + for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) { + int volumeGroupId = audioVolumeGroup.getId(); + + List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes(); + // Set the volume per attributes (if valid) and wait the callback + if (avgAttributes.size() == 0 || avgAttributes.get(0).equals(sDefaultAttributes)) { + // Some volume groups may not have valid attributes, used for internal + // volume management like patch/rerouting + // so bailing out strategy retrieval from attributes + continue; + } + final AudioAttributes aa = avgAttributes.get(0); + + int index = mAudioManager.getVolumeIndexForAttributes(aa); + int indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aa); + int indexMin = mAudioManager.getMinVolumeIndexForAttributes(aa); + + final int indexForAa = incrementVolumeIndex(index, indexMin, indexMax); + + // Set the receiver to filter only the current group callback + validCb.setExpectedVolumeGroup(volumeGroupId); + mAudioManager.setVolumeIndexForAttributes(aa, indexForAa, 0/*flags*/); + assertTrue(validCb.waitForExpectedVolumeGroupChanged( + AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); + + final int readIndex = mAudioManager.getVolumeIndexForAttributes(aa); + assertEquals(readIndex, indexForAa); + } + } finally { + audioAudioVolumeGroupChangedHandler.unregisterListener(validCb); + } + } + + public void testMultipleCallbackReceived() throws Exception { + + final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler = + new AudioVolumeGroupChangeHandler(); + + audioAudioVolumeGroupChangedHandler.init(); + + final int callbackCount = 10; + final List<AudioVolumeGroupCallbackHelper> validCbs = + new ArrayList<AudioVolumeGroupCallbackHelper>(); + for (int i = 0; i < callbackCount; i++) { + validCbs.add(new AudioVolumeGroupCallbackHelper()); + } + for (final AudioVolumeGroupCallbackHelper cb : validCbs) { + audioAudioVolumeGroupChangedHandler.registerListener(cb); + } + + List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); + assertTrue(audioVolumeGroups.size() > 0); + + try { + for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) { + int volumeGroupId = audioVolumeGroup.getId(); + + List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes(); + // Set the volume per attributes (if valid) and wait the callback + if (avgAttributes.size() == 0 || avgAttributes.get(0).equals(sDefaultAttributes)) { + // Some volume groups may not have valid attributes, used for internal + // volume management like patch/rerouting + // so bailing out strategy retrieval from attributes + continue; + } + AudioAttributes aa = avgAttributes.get(0); + + int index = mAudioManager.getVolumeIndexForAttributes(aa); + int indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aa); + int indexMin = mAudioManager.getMinVolumeIndexForAttributes(aa); + + final int indexForAa = incrementVolumeIndex(index, indexMin, indexMax); + + // Set the receiver to filter only the current group callback + for (final AudioVolumeGroupCallbackHelper cb : validCbs) { + cb.setExpectedVolumeGroup(volumeGroupId); + } + mAudioManager.setVolumeIndexForAttributes(aa, indexForAa, 0/*flags*/); + + for (final AudioVolumeGroupCallbackHelper cb : validCbs) { + assertTrue(cb.waitForExpectedVolumeGroupChanged( + AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); + } + int readIndex = mAudioManager.getVolumeIndexForAttributes(aa); + assertEquals(readIndex, indexForAa); + } + } finally { + for (final AudioVolumeGroupCallbackHelper cb : validCbs) { + audioAudioVolumeGroupChangedHandler.unregisterListener(cb); + } + } + } +} diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumeGroupTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumeGroupTest.java new file mode 100644 index 000000000000..84b24b8fcab3 --- /dev/null +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumeGroupTest.java @@ -0,0 +1,131 @@ +/* + * 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.audiopolicytest; + +import static org.junit.Assert.assertNotEquals; + +import android.media.AudioAttributes; +import android.media.AudioSystem; +import android.media.audiopolicy.AudioProductStrategy; +import android.media.audiopolicy.AudioVolumeGroup; + +import java.util.List; + +public class AudioVolumeGroupTest extends AudioVolumesTestBase { + private static final String TAG = "AudioVolumeGroupTest"; + + //----------------------------------------------------------------- + // Test getAudioVolumeGroups and validate groud id + //----------------------------------------------------------------- + public void testGetVolumeGroupsFromNonServiceCaller() throws Exception { + // The transaction behind getAudioVolumeGroups will fail. Check is done at binder level + // with policy service. Error is not reported, the list is just empty. + // Request must come from service components + List<AudioVolumeGroup> audioVolumeGroup = AudioVolumeGroup.getAudioVolumeGroups(); + + assertNotNull(audioVolumeGroup); + assertEquals(audioVolumeGroup.size(), 0); + } + + //----------------------------------------------------------------- + // Test getAudioVolumeGroups and validate groud id + //----------------------------------------------------------------- + public void testGetVolumeGroups() throws Exception { + // Through AudioManager, the transaction behind getAudioVolumeGroups will succeed + final List<AudioVolumeGroup> audioVolumeGroup = mAudioManager.getAudioVolumeGroups(); + assertNotNull(audioVolumeGroup); + assertTrue(audioVolumeGroup.size() > 0); + + final List<AudioProductStrategy> audioProductStrategies = + mAudioManager.getAudioProductStrategies(); + assertTrue(audioProductStrategies.size() > 0); + + for (final AudioVolumeGroup avg : audioVolumeGroup) { + int avgId = avg.getId(); + assertNotEquals(avgId, AudioVolumeGroup.DEFAULT_VOLUME_GROUP); + + List<AudioAttributes> avgAttributes = avg.getAudioAttributes(); + assertNotNull(avgAttributes); + + final int[] avgStreamTypes = avg.getLegacyStreamTypes(); + assertNotNull(avgStreamTypes); + + // for each volume group attributes, find the matching product strategy and ensure + // it is linked the considered volume group + for (final AudioAttributes aa : avgAttributes) { + if (aa.equals(sDefaultAttributes)) { + // Some volume groups may not have valid attributes, used for internal + // volume management like patch/rerouting + // so bailing out strategy retrieval from attributes + continue; + } + boolean isVolumeGroupAssociatedToStrategy = false; + for (final AudioProductStrategy aps : audioProductStrategies) { + int groupId = aps.getVolumeGroupIdForAudioAttributes(aa); + if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { + // Note that Audio Product Strategies are priority ordered, and the + // the first one matching the AudioAttributes will be used to identify + // the volume group associated to the request. + assertTrue(aps.supportsAudioAttributes(aa)); + assertEquals("Volume Group ID (" + avg.toString() + + "), and Volume group ID associated to Strategy (" + + aps.toString() + ") both supporting attributes " + + aa.toString() + " are mismatching", + avgId, groupId); + isVolumeGroupAssociatedToStrategy = true; + break; + } + } + assertTrue("Volume Group (" + avg.toString() + + ") has no associated strategy for attributes " + aa.toString(), + isVolumeGroupAssociatedToStrategy); + } + + // for each volume group stream type, find the matching product strategy and ensure + // it is linked the considered volume group + for (final int avgStreamType : avgStreamTypes) { + if (avgStreamType == AudioSystem.STREAM_DEFAULT) { + // Some Volume Groups may not have corresponding stream types as they + // intends to address volume setting per attributes to avoid adding new + // stream type and going on deprecating the stream type even for volume + // so bailing out strategy retrieval from stream type + continue; + } + boolean isVolumeGroupAssociatedToStrategy = false; + for (final AudioProductStrategy aps : audioProductStrategies) { + int groupId = aps.getVolumeGroupIdForLegacyStreamType(avgStreamType); + if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { + + assertEquals("Volume Group ID (" + avg.toString() + + "), and Volume group ID associated to Strategy (" + + aps.toString() + ") both supporting stream " + + AudioSystem.streamToString(avgStreamType) + "(" + + avgStreamType + ") are mismatching", + avgId, groupId); + + isVolumeGroupAssociatedToStrategy = true; + break; + } + } + assertTrue("Volume Group (" + avg.toString() + + ") has no associated strategy for stream " + + AudioSystem.streamToString(avgStreamType) + "(" + avgStreamType + ")", + isVolumeGroupAssociatedToStrategy); + } + } + } +} diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumesTestBase.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumesTestBase.java new file mode 100644 index 000000000000..a17d65cf7376 --- /dev/null +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioVolumesTestBase.java @@ -0,0 +1,146 @@ +/* + * 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.audiopolicytest; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.media.audiopolicy.AudioProductStrategy; +import android.media.audiopolicy.AudioVolumeGroup; +import android.test.ActivityInstrumentationTestCase2; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class AudioVolumesTestBase extends ActivityInstrumentationTestCase2<AudioPolicyTest> { + public AudioManager mAudioManager; + Context mContext; + private Map<Integer, Integer> mOriginalStreamVolumes = new HashMap<>(); + private Map<Integer, Integer> mOriginalVolumeGroupVolumes = new HashMap<>(); + + // Default matches the invalid (empty) attributes from native. + // The difference is the input source default which is not aligned between native and java + public static final AudioAttributes sDefaultAttributes = + AudioProductStrategy.sDefaultAttributes; + + public static final AudioAttributes sInvalidAttributes = new AudioAttributes.Builder().build(); + + public final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL, + AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC, + AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION, + AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY }; + + public AudioVolumesTestBase() { + super("com.android.audiopolicytest", AudioPolicyTest.class); + } + + /** + * <p>Note: must be called with shell permission (MODIFY_AUDIO_ROUTING) + */ + private void storeAllVolumes() { + List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); + for (final AudioVolumeGroup avg : audioVolumeGroups) { + if (avg.getAudioAttributes().isEmpty()) { + // some volume group may not supports volume control per attributes + // like rerouting/patch since these groups are internal to audio policy manager + continue; + } + AudioAttributes avgAttributes = sDefaultAttributes; + for (final AudioAttributes aa : avg.getAudioAttributes()) { + if (!aa.equals(AudioProductStrategy.sDefaultAttributes)) { + avgAttributes = aa; + break; + } + } + if (avgAttributes.equals(sDefaultAttributes)) { + // This shall not happen, however, not purpose of this base class. + // so bailing out. + continue; + } + mOriginalVolumeGroupVolumes.put( + avg.getId(), mAudioManager.getVolumeIndexForAttributes(avgAttributes)); + } + } + + /** + * <p>Note: must be called with shell permission (MODIFY_AUDIO_ROUTING) + */ + private void restoreAllVolumes() { + List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); + for (Map.Entry<Integer, Integer> e : mOriginalVolumeGroupVolumes.entrySet()) { + for (final AudioVolumeGroup avg : audioVolumeGroups) { + if (avg.getId() == e.getKey()) { + assertTrue(!avg.getAudioAttributes().isEmpty()); + AudioAttributes avgAttributes = sDefaultAttributes; + for (final AudioAttributes aa : avg.getAudioAttributes()) { + if (!aa.equals(AudioProductStrategy.sDefaultAttributes)) { + avgAttributes = aa; + break; + } + } + assertTrue(!avgAttributes.equals(sDefaultAttributes)); + mAudioManager.setVolumeIndexForAttributes( + avgAttributes, e.getValue(), AudioManager.FLAG_ALLOW_RINGER_MODES); + } + } + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mContext = getActivity(); + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + + assertEquals(PackageManager.PERMISSION_GRANTED, + mContext.checkSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)); + + // Store the original volumes that that they can be recovered in tearDown(). + mOriginalStreamVolumes.clear(); + for (int streamType : PUBLIC_STREAM_TYPES) { + mOriginalStreamVolumes.put(streamType, mAudioManager.getStreamVolume(streamType)); + } + // Store the original volume per attributes so that they can be recovered in tearDown() + mOriginalVolumeGroupVolumes.clear(); + storeAllVolumes(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + + // Recover the volume and the ringer mode that the test may have overwritten. + for (Map.Entry<Integer, Integer> e : mOriginalStreamVolumes.entrySet()) { + mAudioManager.setStreamVolume(e.getKey(), e.getValue(), + AudioManager.FLAG_ALLOW_RINGER_MODES); + } + + // Recover the original volume per attributes + restoreAllVolumes(); + } + + public static int resetVolumeIndex(int indexMin, int indexMax) { + return (indexMax + indexMin) / 2; + } + + public static int incrementVolumeIndex(int index, int indexMin, int indexMax) { + return (index + 1 > indexMax) ? resetVolumeIndex(indexMin, indexMax) : ++index; + } +} diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml index 062f7bd8615e..d105e4415ca3 100644 --- a/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml +++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml @@ -18,15 +18,14 @@ Car has solid black background instead of a transparent one --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@android:color/black" - android:fitsSystemWindows="true"> + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@android:color/black" + android:fitsSystemWindows="true"> <include style="@style/BouncerSecurityContainer" layout="@layout/keyguard_host_view" android:layout_width="wrap_content" android:layout_height="wrap_content" /> -</FrameLayout> - +</FrameLayout>
\ No newline at end of file diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_container.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_container.xml new file mode 100644 index 000000000000..3e35df9d9b0c --- /dev/null +++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_container.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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. + --> + +<!-- Car customizations + Car has solid black background instead of a transparent one +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/keyguard_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center"/>
\ No newline at end of file diff --git a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml index 6ecab5182f13..534c51e0febe 100644 --- a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml +++ b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml @@ -18,7 +18,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fullscreen_user_switcher" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:background="@color/car_user_switcher_background_color"> <LinearLayout android:id="@+id/container" diff --git a/packages/CarSystemUI/res/layout/notification_center_activity.xml b/packages/CarSystemUI/res/layout/notification_center_activity.xml index 4fef48918c97..0af74c4462a6 100644 --- a/packages/CarSystemUI/res/layout/notification_center_activity.xml +++ b/packages/CarSystemUI/res/layout/notification_center_activity.xml @@ -20,8 +20,6 @@ android:id="@+id/notification_view" android:layout_width="match_parent" android:layout_height="match_parent" - android:visibility="invisible" - android:layout_marginBottom="@dimen/navigation_bar_height" android:background="@color/notification_shade_background_color"> <View diff --git a/packages/CarSystemUI/res/layout/notification_panel_container.xml b/packages/CarSystemUI/res/layout/notification_panel_container.xml index bf71396984b8..3b53c6aaeac3 100644 --- a/packages/CarSystemUI/res/layout/notification_panel_container.xml +++ b/packages/CarSystemUI/res/layout/notification_panel_container.xml @@ -18,4 +18,5 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/notification_container" android:layout_width="match_parent" - android:layout_height="match_parent"/> + android:layout_height="match_parent" + android:visibility="invisible"/> diff --git a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml index 1b0a211b733d..35423231bb97 100644 --- a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml +++ b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml @@ -22,10 +22,17 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + <!-- TODO(b/151617493): replace marginBottom with insets. --> <ViewStub android:id="@+id/notification_panel_stub" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout="@layout/notification_panel_container"/> + android:layout="@layout/notification_panel_container" + android:layout_marginBottom="@dimen/navigation_bar_height"/> + + <ViewStub android:id="@+id/keyguard_stub" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout="@layout/keyguard_container" /> <ViewStub android:id="@+id/fullscreen_user_switcher_stub" android:layout_width="match_parent" diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml index 0b56d05cc66f..bf1bf38cdb92 100644 --- a/packages/CarSystemUI/res/values/config.xml +++ b/packages/CarSystemUI/res/values/config.xml @@ -71,8 +71,9 @@ <!-- Car System UI's OverlayViewsMediator--> <string-array name="config_carSystemUIOverlayViewsMediators" translatable="false"> - <item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item> <item>com.android.systemui.car.notification.NotificationPanelViewMediator</item> + <item>com.android.systemui.car.keyguard.CarKeyguardViewMediator</item> + <item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item> </string-array> <!-- SystemUI Services: The classes of the stuff to start. --> diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index c275536e4d92..4ea48ba24fa9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -24,6 +24,7 @@ import android.content.Context; import com.android.keyguard.KeyguardViewController; import com.android.systemui.car.CarDeviceProvisionedController; import com.android.systemui.car.CarDeviceProvisionedControllerImpl; +import com.android.systemui.car.keyguard.CarKeyguardViewController; import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; @@ -146,7 +147,7 @@ public abstract class CarSystemUIModule { @Binds abstract KeyguardViewController bindKeyguardViewController( - CarStatusBarKeyguardViewManager keyguardViewManager); + CarKeyguardViewController carKeyguardViewController); @Binds abstract DeviceProvisionedController bindDeviceProvisionedController( diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedController.java b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedController.java index b057198d5177..44e43fe9af8c 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedController.java @@ -24,7 +24,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; */ public interface CarDeviceProvisionedController extends DeviceProvisionedController { /** - * Returns {@code true} then SUW is in progress for the given user. + * Returns {@code true} when SUW is in progress for the given user. */ boolean isUserSetupInProgress(int user); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java new file mode 100644 index 000000000000..1814fd0403d0 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java @@ -0,0 +1,374 @@ +/* + * 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.car.keyguard; + +import android.car.Car; +import android.car.user.CarUserManager; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewRootImpl; + +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardViewController; +import com.android.keyguard.ViewMediatorCallback; +import com.android.systemui.R; +import com.android.systemui.SystemUIFactory; +import com.android.systemui.car.CarServiceProvider; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.keyguard.DismissCallbackRegistry; +import com.android.systemui.navigationbar.car.CarNavigationBarController; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.statusbar.phone.BiometricUnlockController; +import com.android.systemui.statusbar.phone.KeyguardBouncer; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.NotificationPanelViewController; +import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.window.OverlayViewController; +import com.android.systemui.window.OverlayViewGlobalStateController; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Automotive implementation of the {@link KeyguardViewController}. It controls the Keyguard View + * that is mounted to the SystemUIOverlayWindow. + */ +@Singleton +public class CarKeyguardViewController extends OverlayViewController implements + KeyguardViewController { + private static final String TAG = "CarKeyguardViewController"; + private static final boolean DEBUG = true; + + private final Context mContext; + private final Handler mHandler; + private final CarServiceProvider mCarServiceProvider; + private final KeyguardStateController mKeyguardStateController; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final LockPatternUtils mLockPatternUtils; + private final FalsingManager mFalsingManager; + private final KeyguardBypassController mKeyguardBypassController; + private final DismissCallbackRegistry mDismissCallbackRegistry; + private final ViewMediatorCallback mViewMediatorCallback; + private final CarNavigationBarController mCarNavigationBarController; + // Needed to instantiate mBouncer. + private final KeyguardBouncer.BouncerExpansionCallback + mExpansionCallback = new KeyguardBouncer.BouncerExpansionCallback() { + @Override + public void onFullyShown() { + } + + @Override + public void onStartingToHide() { + } + + @Override + public void onStartingToShow() { + } + + @Override + public void onFullyHidden() { + } + }; + private final CarUserManager.UserLifecycleListener mUserLifecycleListener = (e) -> { + if (e.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) { + revealKeyguardIfBouncerPrepared(); + } + }; + + private KeyguardBouncer mBouncer; + private OnKeyguardCancelClickedListener mKeyguardCancelClickedListener; + private boolean mShowing; + + @Inject + public CarKeyguardViewController( + Context context, + @Main Handler mainHandler, + CarServiceProvider carServiceProvider, + OverlayViewGlobalStateController overlayViewGlobalStateController, + KeyguardStateController keyguardStateController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + BiometricUnlockController biometricUnlockController, + ViewMediatorCallback viewMediatorCallback, + CarNavigationBarController carNavigationBarController, + /* The params below are only used to reuse KeyguardBouncer */ + LockPatternUtils lockPatternUtils, + DismissCallbackRegistry dismissCallbackRegistry, + FalsingManager falsingManager, + KeyguardBypassController keyguardBypassController) { + + super(R.id.keyguard_stub, overlayViewGlobalStateController); + + mContext = context; + mHandler = mainHandler; + mCarServiceProvider = carServiceProvider; + mKeyguardStateController = keyguardStateController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mLockPatternUtils = lockPatternUtils; + mFalsingManager = falsingManager; + mKeyguardBypassController = keyguardBypassController; + mDismissCallbackRegistry = dismissCallbackRegistry; + mViewMediatorCallback = viewMediatorCallback; + mCarNavigationBarController = carNavigationBarController; + + biometricUnlockController.setKeyguardViewController(this); + registerUserSwitchedListener(); + } + + @Override + public void onFinishInflate() { + mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext, + mViewMediatorCallback, mLockPatternUtils, + getLayout().findViewById(R.id.keyguard_container), mDismissCallbackRegistry, + mExpansionCallback, mKeyguardStateController, mFalsingManager, + mKeyguardBypassController); + } + + @Override + public void notifyKeyguardAuthenticated(boolean strongAuth) { + mBouncer.notifyKeyguardAuthenticated(strongAuth); + } + + @Override + public void showBouncer(boolean scrimmed) { + if (mShowing && !mBouncer.isShowing()) { + mBouncer.show(/* resetSecuritySelection= */ false); + } + } + + @Override + public void show(Bundle options) { + if (mShowing) return; + + mShowing = true; + mKeyguardStateController.notifyKeyguardState(mShowing, /* occluded= */ false); + mCarNavigationBarController.showAllKeyguardButtons(/* isSetUp= */ true); + start(); + reset(/* hideBouncerWhenShowing= */ false); + notifyKeyguardUpdateMonitor(); + } + + @Override + public void hide(long startTime, long fadeoutDuration) { + if (!mShowing) return; + + mViewMediatorCallback.readyForKeyguardDone(); + mShowing = false; + mKeyguardStateController.notifyKeyguardState(mShowing, /* occluded= */ false); + mBouncer.hide(/* destroyView= */ true); + mCarNavigationBarController.hideAllKeyguardButtons(/* isSetUp= */ true); + stop(); + mKeyguardStateController.notifyKeyguardDoneFading(); + mViewMediatorCallback.keyguardGone(); + notifyKeyguardUpdateMonitor(); + } + + @Override + public void reset(boolean hideBouncerWhenShowing) { + if (mShowing) { + if (mBouncer != null) { + if (!mBouncer.isSecure()) { + dismissAndCollapse(); + } + mBouncer.show(/* resetSecuritySelection= */ true); + } + mKeyguardUpdateMonitor.sendKeyguardReset(); + notifyKeyguardUpdateMonitor(); + } + } + + @Override + public void onFinishedGoingToSleep() { + mBouncer.onScreenTurnedOff(); + } + + @Override + public void onCancelClicked() { + mBouncer.hide(/* destroyView= */ true); + mKeyguardCancelClickedListener.onCancelClicked(); + } + + @Override + public boolean isShowing() { + return mShowing; + } + + @Override + public void dismissAndCollapse() { + hide(/* startTime= */ 0, /* fadeoutDuration= */ 0); + } + + @Override + public void startPreHideAnimation(Runnable finishRunnable) { + mBouncer.startPreHideAnimation(finishRunnable); + } + + @Override + public void setNeedsInput(boolean needsInput) { + getLayout().setFocusable(needsInput); + } + + /** + * Add listener for keyguard cancel clicked. + */ + public void registerOnKeyguardCancelClickedListener( + OnKeyguardCancelClickedListener keyguardCancelClickedListener) { + mKeyguardCancelClickedListener = keyguardCancelClickedListener; + } + + /** + * Remove listener for keyguard cancel clicked. + */ + public void unregisterOnKeyguardCancelClickedListener( + OnKeyguardCancelClickedListener keyguardCancelClickedListener) { + mKeyguardCancelClickedListener = null; + } + + @Override + public ViewRootImpl getViewRootImpl() { + return ((View) getLayout().getParent()).getViewRootImpl(); + } + + @Override + public boolean isBouncerShowing() { + return mBouncer.isShowing(); + } + + @Override + public boolean bouncerIsOrWillBeShowing() { + return mBouncer.isShowing() || mBouncer.inTransit(); + } + + @Override + public void keyguardGoingAway() { + // no-op + } + + @Override + public void setKeyguardGoingAwayState(boolean isKeyguardGoingAway) { + // no-op + } + + @Override + public void onStartedGoingToSleep() { + // no-op + } + + @Override + public void onStartedWakingUp() { + // no-op + } + + @Override + public void onScreenTurningOn() { + // no-op + } + + @Override + public void onScreenTurnedOn() { + // no-op + } + + @Override + public void setOccluded(boolean occluded, boolean animate) { + // no-op + } + + @Override + public boolean shouldDisableWindowAnimationsForUnlock() { + return false; + } + + @Override + public boolean isGoingToNotificationShade() { + return false; + } + + @Override + public boolean isUnlockWithWallpaper() { + return false; + } + + @Override + public boolean shouldSubtleWindowAnimationsForUnlock() { + return false; + } + + @Override + public void registerStatusBar(StatusBar statusBar, ViewGroup container, + NotificationPanelViewController notificationPanelViewController, + BiometricUnlockController biometricUnlockController, + DismissCallbackRegistry dismissCallbackRegistry, ViewGroup lockIconContainer, + View notificationContainer, KeyguardBypassController bypassController, + FalsingManager falsingManager) { + // no-op + } + + /** + * Hides Keyguard so that the transitioning Bouncer can be hidden until it is prepared. To be + * called by {@link com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator} + * when a new user is selected. + */ + public void hideKeyguardToPrepareBouncer() { + getLayout().setVisibility(View.INVISIBLE); + } + + private void revealKeyguardIfBouncerPrepared() { + int reattemptDelayMillis = 50; + Runnable revealKeyguard = () -> { + if (!mBouncer.inTransit() || !mBouncer.isSecure()) { + getLayout().setVisibility(View.VISIBLE); + } else { + if (DEBUG) { + Log.d(TAG, "revealKeyguardIfBouncerPrepared: Bouncer is not prepared " + + "yet so reattempting after " + reattemptDelayMillis + "ms."); + } + mHandler.postDelayed(this::revealKeyguardIfBouncerPrepared, reattemptDelayMillis); + } + }; + mHandler.post(revealKeyguard); + } + + private void notifyKeyguardUpdateMonitor() { + mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(mShowing); + if (mBouncer != null) { + mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isBouncerShowing()); + } + } + + private void registerUserSwitchedListener() { + mCarServiceProvider.addListener(car -> { + CarUserManager userManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE); + userManager.addListener(Runnable::run, mUserLifecycleListener); + }); + } + + /** + * Defines a callback for keyguard cancel button clicked listeners. + */ + public interface OnKeyguardCancelClickedListener { + /** + * Called when keyguard cancel button is clicked. + */ + void onCancelClicked(); + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewMediator.java new file mode 100644 index 000000000000..db0f5d82e210 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewMediator.java @@ -0,0 +1,54 @@ +/* + * 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.car.keyguard; + +import com.android.systemui.car.userswitcher.FullScreenUserSwitcherViewController; +import com.android.systemui.window.OverlayViewMediator; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Manages events originating from the Keyguard service that cause Keyguard or other OverlayWindow + * Components to appear or disappear. + */ +@Singleton +public class CarKeyguardViewMediator implements OverlayViewMediator { + + private final CarKeyguardViewController mCarKeyguardViewController; + private final FullScreenUserSwitcherViewController mFullScreenUserSwitcherViewController; + + @Inject + public CarKeyguardViewMediator( + CarKeyguardViewController carKeyguardViewController, + FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController + ) { + mCarKeyguardViewController = carKeyguardViewController; + mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController; + } + + @Override + public void registerListeners() { + mCarKeyguardViewController.registerOnKeyguardCancelClickedListener( + mFullScreenUserSwitcherViewController::start); + } + + @Override + public void setupOverlayContentViewControllers() { + // no-op + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java index 1901a2db879d..d8a894cfa8ba 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java @@ -16,9 +16,6 @@ package com.android.systemui.car.notification; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; import android.app.ActivityManager; import android.car.Car; import android.car.drivingstate.CarUxRestrictionsManager; @@ -33,7 +30,6 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; @@ -54,7 +50,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.window.OverlayViewController; +import com.android.systemui.window.OverlayPanelViewController; import com.android.systemui.window.OverlayViewGlobalStateController; import javax.inject.Inject; @@ -62,39 +58,22 @@ import javax.inject.Singleton; /** View controller for the notification panel. */ @Singleton -public class NotificationPanelViewController extends OverlayViewController { - - // used to calculate how fast to open or close the window - private static final float DEFAULT_FLING_VELOCITY = 0; - // max time a fling animation takes - private static final float FLING_ANIMATION_MAX_TIME = 0.5f; - // acceleration rate for the fling animation - private static final float FLING_SPEED_UP_FACTOR = 0.6f; - - private static final int SWIPE_DOWN_MIN_DISTANCE = 25; - private static final int SWIPE_MAX_OFF_PATH = 75; - private static final int SWIPE_THRESHOLD_VELOCITY = 200; +public class NotificationPanelViewController extends OverlayPanelViewController { + private static final boolean DEBUG = true; private static final String TAG = "NotificationPanelViewController"; private final Context mContext; private final Resources mResources; private final CarServiceProvider mCarServiceProvider; - private final CarDeviceProvisionedController mCarDeviceProvisionedController; private final IStatusBarService mBarService; private final CommandQueue mCommandQueue; private final NotificationDataManager mNotificationDataManager; private final CarUxRestrictionManagerWrapper mCarUxRestrictionManagerWrapper; private final CarNotificationListener mCarNotificationListener; private final NotificationClickHandlerFactory mNotificationClickHandlerFactory; - private final FlingAnimationUtils mFlingAnimationUtils; private final StatusBarStateController mStatusBarStateController; - private final int mSettleClosePercentage; - - private float mOpeningVelocity = DEFAULT_FLING_VELOCITY; - private float mClosingVelocity = DEFAULT_FLING_VELOCITY; - private float mInitialBackgroundAlpha; private float mBackgroundAlphaDiff; @@ -108,13 +87,7 @@ public class NotificationPanelViewController extends OverlayViewController { private float mFirstTouchDownOnGlassPane; private boolean mNotificationListAtBottomAtTimeOfTouch; private boolean mIsSwipingVerticallyToClose; - private int mPercentageFromBottom; - private boolean mIsNotificationAnimating; private boolean mIsNotificationCardSwiping; - private boolean mPanelExpanded = false; - - private View.OnTouchListener mTopNavBarNotificationTouchListener; - private View.OnTouchListener mNavBarNotificationTouchListener; private OnUnseenCountUpdateListener mUnseenCountUpdateListener; @@ -123,6 +96,7 @@ public class NotificationPanelViewController extends OverlayViewController { Context context, @Main Resources resources, OverlayViewGlobalStateController overlayViewGlobalStateController, + FlingAnimationUtils.Builder flingAnimationUtilsBuilder, /* Other things */ CarServiceProvider carServiceProvider, @@ -135,26 +109,21 @@ public class NotificationPanelViewController extends OverlayViewController { CarUxRestrictionManagerWrapper carUxRestrictionManagerWrapper, CarNotificationListener carNotificationListener, NotificationClickHandlerFactory notificationClickHandlerFactory, - FlingAnimationUtils.Builder flingAnimationUtilsBuilder, /* Things that need to be replaced */ StatusBarStateController statusBarStateController ) { - super(R.id.notification_panel_stub, overlayViewGlobalStateController); + super(context, resources, R.id.notification_panel_stub, overlayViewGlobalStateController, + flingAnimationUtilsBuilder, carDeviceProvisionedController); mContext = context; mResources = resources; mCarServiceProvider = carServiceProvider; - mCarDeviceProvisionedController = carDeviceProvisionedController; mBarService = barService; mCommandQueue = commandQueue; mNotificationDataManager = notificationDataManager; mCarUxRestrictionManagerWrapper = carUxRestrictionManagerWrapper; mCarNotificationListener = carNotificationListener; mNotificationClickHandlerFactory = notificationClickHandlerFactory; - mFlingAnimationUtils = flingAnimationUtilsBuilder - .setMaxLengthSeconds(FLING_ANIMATION_MAX_TIME) - .setSpeedUpFactor(FLING_SPEED_UP_FACTOR) - .build(); mStatusBarStateController = statusBarStateController; // Notification background setup. @@ -175,60 +144,6 @@ public class NotificationPanelViewController extends OverlayViewController { + " percentage"); } mBackgroundAlphaDiff = finalBackgroundAlpha - mInitialBackgroundAlpha; - - // Notification Panel param setup - mSettleClosePercentage = mResources.getInteger( - R.integer.notification_settle_close_percentage); - - // Attached to the top navigation bar (i.e. status bar) to detect pull down of the - // notification shade. - GestureDetector openGestureDetector = new GestureDetector(mContext, - new OpenNotificationGestureListener() { - @Override - protected void openNotification() { - animateExpandNotificationsPanel(); - } - }); - - // Attached to the NavBars to close the notification shade - GestureDetector navBarCloseNotificationGestureDetector = new GestureDetector(mContext, - new NavBarCloseNotificationGestureListener() { - @Override - protected void close() { - if (mPanelExpanded) { - animateCollapsePanels(); - } - } - }); - - mTopNavBarNotificationTouchListener = (v, event) -> { - if (!isInflated()) { - getOverlayViewGlobalStateController().inflateView(this); - } - if (!mCarDeviceProvisionedController.isCurrentUserFullySetup()) { - return true; - } - - boolean consumed = openGestureDetector.onTouchEvent(event); - if (consumed) { - return true; - } - maybeCompleteAnimation(event); - return true; - }; - - mNavBarNotificationTouchListener = - (v, event) -> { - if (!isInflated()) { - return true; - } - boolean consumed = navBarCloseNotificationGestureDetector.onTouchEvent(event); - if (consumed) { - return true; - } - maybeCompleteAnimation(event); - return true; - }; } @Override @@ -252,14 +167,13 @@ public class NotificationPanelViewController extends OverlayViewController { private void onNotificationViewInflated() { // Find views. mNotificationView = getLayout().findViewById(R.id.notification_view); - View glassPane = mNotificationView.findViewById(R.id.glass_pane); - mHandleBar = mNotificationView.findViewById(R.id.handle_bar); - mNotificationList = mNotificationView.findViewById(R.id.notifications); + setupHandleBar(); + setupNotificationPanel(); mNotificationClickHandlerFactory.registerClickListener((launchResult, alertEntry) -> { if (launchResult == ActivityManager.START_TASK_TO_FRONT || launchResult == ActivityManager.START_SUCCESS) { - animateCollapsePanels(); + animateCollapsePanel(); } }); @@ -269,39 +183,52 @@ public class NotificationPanelViewController extends OverlayViewController { mNotificationDataManager.getUnseenNotificationCount()); } }); + mNotificationClickHandlerFactory.setNotificationDataManager(mNotificationDataManager); mNotificationView.setClickHandlerFactory(mNotificationClickHandlerFactory); mNotificationView.setNotificationDataManager(mNotificationDataManager); - mNotificationList.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - if (!mNotificationList.canScrollVertically(1)) { - mNotificationListAtBottom = true; - return; - } - mNotificationListAtBottom = false; - mIsSwipingVerticallyToClose = false; - mNotificationListAtBottomAtTimeOfTouch = false; - } + mCarServiceProvider.addListener(car -> { + CarUxRestrictionsManager carUxRestrictionsManager = + (CarUxRestrictionsManager) + car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE); + mCarUxRestrictionManagerWrapper.setCarUxRestrictionsManager( + carUxRestrictionsManager); + + mNotificationViewController = new NotificationViewController( + mNotificationView, + PreprocessingManager.getInstance(mContext), + mCarNotificationListener, + mCarUxRestrictionManagerWrapper, + mNotificationDataManager); + mNotificationViewController.enable(); + }); + } + + private void setupHandleBar() { + mHandleBar = mNotificationView.findViewById(R.id.handle_bar); + GestureDetector handleBarCloseNotificationGestureDetector = new GestureDetector(mContext, + new HandleBarCloseGestureListener()); + mHandleBar.setOnTouchListener((v, event) -> { + handleBarCloseNotificationGestureDetector.onTouchEvent(event); + maybeCompleteAnimation(event); + return true; }); + } - // Attached to the notification ui to detect close request of the notification shade. + private void setupNotificationPanel() { + View glassPane = mNotificationView.findViewById(R.id.glass_pane); + mNotificationList = mNotificationView.findViewById(R.id.notifications); GestureDetector closeGestureDetector = new GestureDetector(mContext, - new CloseNotificationGestureListener() { + new CloseGestureListener() { @Override protected void close() { - if (mPanelExpanded) { - animateCollapsePanels(); + if (isPanelExpanded()) { + animateCollapsePanel(); } } }); - // Attached to the Handle bar to close the notification shade - GestureDetector handleBarCloseNotificationGestureDetector = new GestureDetector(mContext, - new HandleBarCloseNotificationGestureListener()); - // The glass pane is used to view touch events before passed to the notification list. // This allows us to initialize gesture listeners and detect when to close the notifications glassPane.setOnTouchListener((v, event) -> { @@ -320,6 +247,21 @@ public class NotificationPanelViewController extends OverlayViewController { return false; }); + mNotificationList.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + // Check if we can scroll vertically downwards. + if (!mNotificationList.canScrollVertically(/* direction= */ 1)) { + mNotificationListAtBottom = true; + return; + } + mNotificationListAtBottom = false; + mIsSwipingVerticallyToClose = false; + mNotificationListAtBottomAtTimeOfTouch = false; + } + }); + mNotificationList.setOnTouchListener((v, event) -> { mIsNotificationCardSwiping = Math.abs(mFirstTouchDownOnGlassPane - event.getRawX()) > SWIPE_MAX_OFF_PATH; @@ -341,19 +283,19 @@ public class NotificationPanelViewController extends OverlayViewController { boolean handled = closeGestureDetector.onTouchEvent(event); boolean isTracking = mIsTracking; - Rect rect = mNotificationView.getClipBounds(); + Rect rect = getLayout().getClipBounds(); float clippedHeight = 0; if (rect != null) { clippedHeight = rect.bottom; } if (!handled && event.getActionMasked() == MotionEvent.ACTION_UP && mIsSwipingVerticallyToClose) { - if (mSettleClosePercentage < mPercentageFromBottom && isTracking) { - animateNotificationPanel(DEFAULT_FLING_VELOCITY, false); - } else if (clippedHeight != mNotificationView.getHeight() && isTracking) { + if (getSettleClosePercentage() < getPercentageFromBottom() && isTracking) { + animatePanel(DEFAULT_FLING_VELOCITY, false); + } else if (clippedHeight != getLayout().getHeight() && isTracking) { // this can be caused when user is at the end of the list and trying to // fling to top of the list by scrolling down. - animateNotificationPanel(DEFAULT_FLING_VELOCITY, true); + animatePanel(DEFAULT_FLING_VELOCITY, true); } } @@ -365,28 +307,6 @@ public class NotificationPanelViewController extends OverlayViewController { } return handled || isTracking; }); - - mCarServiceProvider.addListener(car -> { - CarUxRestrictionsManager carUxRestrictionsManager = - (CarUxRestrictionsManager) - car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE); - mCarUxRestrictionManagerWrapper.setCarUxRestrictionsManager( - carUxRestrictionsManager); - - mNotificationViewController = new NotificationViewController( - mNotificationView, - PreprocessingManager.getInstance(mContext), - mCarNotificationListener, - mCarUxRestrictionManagerWrapper, - mNotificationDataManager); - mNotificationViewController.enable(); - }); - - mHandleBar.setOnTouchListener((v, event) -> { - handleBarCloseNotificationGestureDetector.onTouchEvent(event); - maybeCompleteAnimation(event); - return true; - }); } /** Called when the car power state is changed to ON. */ @@ -397,139 +317,40 @@ public class NotificationPanelViewController extends OverlayViewController { mNotificationDataManager.clearAll(); } - View.OnTouchListener getTopNavBarNotificationTouchListener() { - return mTopNavBarNotificationTouchListener; - } - - View.OnTouchListener getNavBarNotificationTouchListener() { - return mNavBarNotificationTouchListener; - } - - private void maybeCompleteAnimation(MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_UP - && mNotificationView.getVisibility() == View.VISIBLE) { - if (mSettleClosePercentage < mPercentageFromBottom) { - animateNotificationPanel(DEFAULT_FLING_VELOCITY, false); - } else { - animateNotificationPanel(DEFAULT_FLING_VELOCITY, true); - } - } + @Override + protected boolean shouldAnimateCollapsePanel() { + return true; } - /** - * Animates the notification shade from one position to other. This is used to either open or - * close the notification shade completely with a velocity. If the animation is to close the - * notification shade this method also makes the view invisible after animation ends. - */ - private void animateNotificationPanel(float velocity, boolean isClosing) { - float to = 0; - if (!isClosing) { - to = mNotificationView.getHeight(); - } - - Rect rect = mNotificationView.getClipBounds(); - if (rect != null && rect.bottom != to) { - float from = rect.bottom; - animate(from, to, velocity, isClosing); - return; - } - - // We will only be here if the shade is being opened programmatically or via button when - // height of the layout was not calculated. - ViewTreeObserver notificationTreeObserver = mNotificationView.getViewTreeObserver(); - notificationTreeObserver.addOnGlobalLayoutListener( - new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - ViewTreeObserver obs = mNotificationView.getViewTreeObserver(); - obs.removeOnGlobalLayoutListener(this); - float to = mNotificationView.getHeight(); - animate(/* from= */ 0, to, velocity, isClosing); - } - }); + @Override + protected void onAnimateCollapsePanel() { + // No op. } - private void animateCollapsePanels() { - if (!mPanelExpanded || mNotificationView.getVisibility() == View.INVISIBLE) { - return; - } - getOverlayViewGlobalStateController().setWindowFocusable(false); - animateNotificationPanel(mClosingVelocity, true); + @Override + protected boolean shouldAnimateExpandPanel() { + return mCommandQueue.panelsEnabled(); } - private void animateExpandNotificationsPanel() { - if (!mCommandQueue.panelsEnabled() - || !mCarDeviceProvisionedController.isCurrentUserFullySetup()) { - return; - } - // scroll to top + @Override + protected void onAnimateExpandPanel() { mNotificationList.scrollToPosition(0); - setPanelVisible(true); - mNotificationView.setVisibility(View.VISIBLE); - animateNotificationPanel(mOpeningVelocity, false); - - setPanelExpanded(true); } - private void animate(float from, float to, float velocity, boolean isClosing) { - if (mIsNotificationAnimating) { - return; - } - mIsNotificationAnimating = true; - mIsTracking = true; - ValueAnimator animator = ValueAnimator.ofFloat(from, to); - animator.addUpdateListener( - animation -> { - float animatedValue = (Float) animation.getAnimatedValue(); - setNotificationViewClipBounds((int) animatedValue); - }); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - mIsNotificationAnimating = false; - mIsTracking = false; - mOpeningVelocity = DEFAULT_FLING_VELOCITY; - mClosingVelocity = DEFAULT_FLING_VELOCITY; - if (isClosing) { - setPanelVisible(false); - mNotificationView.setVisibility(View.INVISIBLE); - mNotificationView.setClipBounds(null); - mNotificationViewController.onVisibilityChanged(false); - // let the status bar know that the panel is closed - setPanelExpanded(false); - } else { - mNotificationViewController.onVisibilityChanged(true); - // let the status bar know that the panel is open - mNotificationView.setVisibleNotificationsAsSeen(); - setPanelExpanded(true); - } - } - }); - mFlingAnimationUtils.apply(animator, from, to, Math.abs(velocity)); - animator.start(); + @Override + protected void onCollapseAnimationEnd() { + mNotificationViewController.onVisibilityChanged(false); } - /** - * Set the panel view to be visible. - */ - public void setPanelVisible(boolean visible) { - if (visible && !getOverlayViewGlobalStateController().isWindowVisible()) { - getOverlayViewGlobalStateController().setWindowVisible(true); - } - if (!visible && getOverlayViewGlobalStateController().isWindowVisible()) { - getOverlayViewGlobalStateController().setWindowVisible(false); - } - getLayout().setVisibility(visible ? View.VISIBLE : View.INVISIBLE); - getOverlayViewGlobalStateController().setWindowFocusable(visible); + @Override + protected void onExpandAnimationEnd() { + mNotificationViewController.onVisibilityChanged(true); + mNotificationView.setVisibleNotificationsAsSeen(); } - /** - * Set the panel state to expanded. This will expand or collapse the overlay window if - * necessary. - */ - public void setPanelExpanded(boolean expand) { - mPanelExpanded = expand; + @Override + protected void onPanelExpanded(boolean expand) { + super.onPanelExpanded(expand); if (expand && mStatusBarStateController.getState() != StatusBarState.KEYGUARD) { if (DEBUG) { @@ -550,19 +371,19 @@ public class NotificationPanelViewController extends OverlayViewController { } } - private void setNotificationViewClipBounds(int height) { - if (height > mNotificationView.getHeight()) { - height = mNotificationView.getHeight(); - } - Rect clipBounds = new Rect(); - clipBounds.set(0, 0, mNotificationView.getWidth(), height); - // Sets the clip region on the notification list view. - mNotificationView.setClipBounds(clipBounds); + @Override + protected void onOpenScrollStart() { + mNotificationList.scrollToPosition(0); + } + + @Override + protected void onScroll(int height) { if (mHandleBar != null) { ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mHandleBar.getLayoutParams(); mHandleBar.setTranslationY(height - mHandleBar.getHeight() - lp.bottomMargin); } + if (mNotificationView.getHeight() > 0) { Drawable background = mNotificationView.getBackground().mutate(); background.setAlpha((int) (getBackgroundAlpha(height) * 255)); @@ -570,6 +391,13 @@ public class NotificationPanelViewController extends OverlayViewController { } } + @Override + protected boolean shouldAllowClosingScroll() { + // Unless the notification list is at the bottom, the panel shouldn't be allowed to + // collapse on scroll. + return mNotificationListAtBottomAtTimeOfTouch; + } + /** * Calculates the alpha value for the background based on how much of the notification * shade is visible to the user. When the notification shade is completely open then @@ -580,30 +408,6 @@ public class NotificationPanelViewController extends OverlayViewController { + ((float) height / mNotificationView.getHeight() * mBackgroundAlphaDiff); } - private void calculatePercentageFromBottom(float height) { - if (mNotificationView.getHeight() > 0) { - mPercentageFromBottom = (int) Math.abs( - height / mNotificationView.getHeight() * 100); - } - } - - /** Toggles the visibility of the notification panel. */ - public void toggle() { - if (!isInflated()) { - getOverlayViewGlobalStateController().inflateView(this); - } - if (mPanelExpanded) { - animateCollapsePanels(); - } else { - animateExpandNotificationsPanel(); - } - } - - /** Returns {@code true} if the notification panel is expanded. */ - public boolean isPanelExpanded() { - return mPanelExpanded; - } - /** Sets the unseen count listener. */ public void setOnUnseenCountUpdateListener(OnUnseenCountUpdateListener listener) { mUnseenCountUpdateListener = listener; @@ -619,154 +423,9 @@ public class NotificationPanelViewController extends OverlayViewController { } /** - * Only responsible for open hooks. Since once the panel opens it covers all elements - * there is no need to merge with close. - */ - private abstract class OpenNotificationGestureListener extends - GestureDetector.SimpleOnGestureListener { - - @Override - public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, - float distanceY) { - - if (mNotificationView.getVisibility() == View.INVISIBLE) { - // when the on-scroll is called for the first time to open. - mNotificationList.scrollToPosition(0); - } - setPanelVisible(true); - mNotificationView.setVisibility(View.VISIBLE); - - // clips the view for the notification shade when the user scrolls to open. - setNotificationViewClipBounds((int) event2.getRawY()); - - // Initially the scroll starts with height being zero. This checks protects from divide - // by zero error. - calculatePercentageFromBottom(event2.getRawY()); - - mIsTracking = true; - return true; - } - - - @Override - public boolean onFling(MotionEvent event1, MotionEvent event2, - float velocityX, float velocityY) { - if (velocityY > SWIPE_THRESHOLD_VELOCITY) { - mOpeningVelocity = velocityY; - openNotification(); - return true; - } - animateNotificationPanel(DEFAULT_FLING_VELOCITY, true); - - return false; - } - - protected abstract void openNotification(); - } - - /** - * To be installed on the open panel notification panel - */ - private abstract class CloseNotificationGestureListener extends - GestureDetector.SimpleOnGestureListener { - - @Override - public boolean onSingleTapUp(MotionEvent motionEvent) { - if (mPanelExpanded) { - animateNotificationPanel(DEFAULT_FLING_VELOCITY, true); - } - return true; - } - - @Override - public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, - float distanceY) { - // should not clip while scroll to the bottom of the list. - if (!mNotificationListAtBottomAtTimeOfTouch) { - return false; - } - float actualNotificationHeight = - mNotificationView.getHeight() - (event1.getRawY() - event2.getRawY()); - if (actualNotificationHeight > mNotificationView.getHeight()) { - actualNotificationHeight = mNotificationView.getHeight(); - } - if (mNotificationView.getHeight() > 0) { - mPercentageFromBottom = (int) Math.abs( - actualNotificationHeight / mNotificationView.getHeight() * 100); - boolean isUp = distanceY > 0; - - // This check is to figure out if onScroll was called while swiping the card at - // bottom of the list. At that time we should not allow notification shade to - // close. We are also checking for the upwards swipe gesture here because it is - // possible if a user is closing the notification shade and while swiping starts - // to open again but does not fling. At that time we should allow the - // notification shade to close fully or else it would stuck in between. - if (Math.abs(mNotificationView.getHeight() - actualNotificationHeight) - > SWIPE_DOWN_MIN_DISTANCE && isUp) { - setNotificationViewClipBounds((int) actualNotificationHeight); - mIsTracking = true; - } else if (!isUp) { - setNotificationViewClipBounds((int) actualNotificationHeight); - } - } - // if we return true the items in RV won't be scrollable. - return false; - } - - - @Override - public boolean onFling(MotionEvent event1, MotionEvent event2, - float velocityX, float velocityY) { - // should not fling if the touch does not start when view is at the bottom of the list. - if (!mNotificationListAtBottomAtTimeOfTouch) { - return false; - } - if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH - || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) { - // swipe was not vertical or was not fast enough - return false; - } - boolean isUp = velocityY < 0; - if (isUp) { - close(); - return true; - } else { - // we should close the shade - animateNotificationPanel(velocityY, false); - } - return false; - } - - protected abstract void close(); - } - - /** - * To be installed on the nav bars. - */ - private abstract class NavBarCloseNotificationGestureListener extends - CloseNotificationGestureListener { - @Override - public boolean onSingleTapUp(MotionEvent e) { - mClosingVelocity = DEFAULT_FLING_VELOCITY; - if (mPanelExpanded) { - close(); - } - return super.onSingleTapUp(e); - } - - @Override - public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, - float distanceY) { - calculatePercentageFromBottom(event2.getRawY()); - setNotificationViewClipBounds((int) event2.getRawY()); - return true; - } - } - - /** * To be installed on the handle bar. */ - private class HandleBarCloseNotificationGestureListener extends + private class HandleBarCloseGestureListener extends GestureDetector.SimpleOnGestureListener { @Override @@ -777,9 +436,8 @@ public class NotificationPanelViewController extends OverlayViewController { // the handle bar we should calculate the height using the diff of event1 and event2. // This will help the notification shade to clip smoothly as the event2 value changes // as event1 value will be fixed. - int clipHeight = - mNotificationView.getHeight() - (int) (event1.getRawY() - event2.getRawY()); - setNotificationViewClipBounds(clipHeight); + int clipHeight = getLayout().getHeight() - (int) (event1.getRawY() - event2.getRawY()); + setViewClipBounds(clipHeight); return true; } } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java index 110c2ee8854b..9d71797794b8 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java @@ -59,13 +59,13 @@ public class NotificationPanelViewMediator implements OverlayViewMediator, @Override public void registerListeners() { mCarNavigationBarController.registerTopBarTouchListener( - mNotificationPanelViewController.getTopNavBarNotificationTouchListener()); + mNotificationPanelViewController.getDragOpenTouchListener()); mCarNavigationBarController.registerBottomBarTouchListener( - mNotificationPanelViewController.getNavBarNotificationTouchListener()); + mNotificationPanelViewController.getDragCloseTouchListener()); mCarNavigationBarController.registerLeftBarTouchListener( - mNotificationPanelViewController.getNavBarNotificationTouchListener()); + mNotificationPanelViewController.getDragCloseTouchListener()); mCarNavigationBarController.registerRightBarTouchListener( - mNotificationPanelViewController.getNavBarNotificationTouchListener()); + mNotificationPanelViewController.getDragCloseTouchListener()); mCarNavigationBarController.registerNotificationController( new CarNavigationBarController.NotificationsShadeController() { diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarTrustAgentUnlockDialogHelper.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarTrustAgentUnlockDialogHelper.java deleted file mode 100644 index 597716569e9b..000000000000 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarTrustAgentUnlockDialogHelper.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.car.userswitcher; - -import android.app.admin.DevicePolicyManager; -import android.bluetooth.BluetoothAdapter; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Resources; -import android.graphics.PixelFormat; -import android.os.Handler; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; - -import com.android.internal.widget.LockPatternUtils; -import com.android.systemui.R; -import com.android.systemui.dagger.qualifiers.Main; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * A helper class displays an unlock dialog and receives broadcast about detecting trusted device - * & unlocking state to show the appropriate message on the dialog. - */ -@Singleton -class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{ - private static final String TAG = CarTrustAgentUnlockDialogHelper.class.getSimpleName(); - - private final Context mContext; - private final Resources mResources; - private final WindowManager mWindowManager; - private final UserManager mUserManager; - private final WindowManager.LayoutParams mParams; - /** - * Not using Dialog because context passed from {@link FullscreenUserSwitcherViewMediator} - * is not an activity. - */ - private final View mUnlockDialogLayout; - private final TextView mUnlockingText; - private final Button mButton; - private final IntentFilter mFilter; - private int mUid; - private boolean mIsDialogShowing; - private OnHideListener mOnHideListener; - - @Inject - CarTrustAgentUnlockDialogHelper(Context context, @Main Resources resources, - UserManager userManager, WindowManager windowManager) { - mContext = context; - mResources = resources; - mUserManager = userManager; - mWindowManager = windowManager; - mParams = createLayoutParams(); - mFilter = getIntentFilter(); - - mParams.packageName = mContext.getPackageName(); - mParams.setTitle(mContext.getString(R.string.unlock_dialog_title)); - - mUnlockDialogLayout = LayoutInflater.from(mContext).inflate( - R.layout.trust_agent_unlock_dialog, null); - mUnlockDialogLayout.setLayoutParams(mParams); - - View dialogParent = mUnlockDialogLayout.findViewById(R.id.unlock_dialog_parent); - dialogParent.setOnTouchListener((v, event)-> { - hideUnlockDialog(/* dismissUserSwitcher= */ false); - return true; - }); - View unlockDialog = mUnlockDialogLayout.findViewById(R.id.unlock_dialog); - unlockDialog.setOnTouchListener((v, event) -> { - // If the person taps inside the unlock dialog, the touch event will be intercepted here - // and the dialog will not exit - return true; - }); - mUnlockingText = mUnlockDialogLayout.findViewById(R.id.unlocking_text); - mButton = mUnlockDialogLayout.findViewById(R.id.enter_pin_button); - mButton.setOnClickListener(v -> { - hideUnlockDialog(/* dismissUserSwitcher= */true); - // TODO(b/138250105) Stop unlock advertising - }); - - BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - if (bluetoothAdapter != null - && bluetoothAdapter.getLeState() == BluetoothAdapter.STATE_BLE_ON) { - mUnlockingText.setText(R.string.unlock_dialog_message_start); - } - } - - /** - * This filter is listening on: - * {@link BluetoothAdapter#ACTION_BLE_STATE_CHANGED} for starting unlock advertising; - * {@link Intent#ACTION_USER_UNLOCKED} for IHU unlocked - */ - private IntentFilter getIntentFilter() { - IntentFilter filter = new IntentFilter(); - filter.addAction(BluetoothAdapter.ACTION_BLE_STATE_CHANGED); - filter.addAction(Intent.ACTION_USER_UNLOCKED); - return filter; - } - - /** - * Show dialog for the given user - */ - void showUnlockDialog(int uid, OnHideListener listener) { - showUnlockDialogAfterDelay(uid, 0, listener); - } - - /** - * Show dialog for the given user after the certain time of delay has elapsed - * - * @param uid the user to unlock - * @param listener listener that listens to dialog hide - */ - void showUnlockDialogAfterDelay(int uid, OnHideListener listener) { - long delayMillis = mResources.getInteger(R.integer.unlock_dialog_delay_ms); - showUnlockDialogAfterDelay(uid, delayMillis, listener); - } - - /** - * Show dialog for the given user after the supplied delay has elapsed - */ - private void showUnlockDialogAfterDelay(int uid, long delayMillis, OnHideListener listener) { - setUid(uid); - mOnHideListener = listener; - if (!mIsDialogShowing) { - logd("Receiver registered"); - mContext.registerReceiverAsUser(this, UserHandle.ALL, mFilter, - /* broadcastPermission= */ null, - /* scheduler= */ null); - new Handler().postDelayed(() -> { - if (!mUserManager.isUserUnlocked(uid)) { - logd("Showed unlock dialog for user: " + uid + " after " + delayMillis - + " delay."); - mWindowManager.addView(mUnlockDialogLayout, mParams); - } - }, delayMillis); - } - mIsDialogShowing = true; - } - - private void setUid(int uid) { - mUid = uid; - TextView userName = mUnlockDialogLayout.findViewById(R.id.user_name); - userName.setText(mUserManager.getUserInfo(mUid).name); - ImageView avatar = mUnlockDialogLayout.findViewById(R.id.avatar); - avatar.setImageBitmap(mUserManager.getUserIcon(mUid)); - setButtonText(); - } - - private void hideUnlockDialog(boolean dismissUserSwitcher) { - if (!mIsDialogShowing) { - return; - } - mWindowManager.removeView(mUnlockDialogLayout); - logd("Receiver unregistered"); - mContext.unregisterReceiver(this); - if (mOnHideListener != null) { - mOnHideListener.onHide(dismissUserSwitcher); - } - mIsDialogShowing = false; - } - - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action == null) { - return; - } - switch (action) { - case BluetoothAdapter.ACTION_BLE_STATE_CHANGED: - logd("Received ACTION_BLE_STATE_CHANGED"); - int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); - if (state == BluetoothAdapter.STATE_BLE_ON) { - logd("Received BLE_ON"); - mUnlockingText.setText(R.string.unlock_dialog_message_start); - } - break; - case Intent.ACTION_USER_UNLOCKED: - int uid = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); - if (uid == mUid) { - logd("IHU unlocked"); - hideUnlockDialog(/* notifyOnHideListener= */false); - } else { - Log.e(TAG, "Received ACTION_USER_UNLOCKED for unexpected uid: " + uid); - } - break; - default: - Log.e(TAG, "Encountered unexpected action when attempting to set " - + "unlock state message: " + action); - } - } - - // Set button text based on screen lock type - private void setButtonText() { - LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); - int passwordQuality = lockPatternUtils.getActivePasswordQuality(mUid); - switch (passwordQuality) { - // PIN - case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: - case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: - mButton.setText(R.string.unlock_dialog_button_text_pin); - break; - // Pattern - case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: - mButton.setText(R.string.unlock_dialog_button_text_pattern); - break; - // Password - case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: - case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: - case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: - mButton.setText(R.string.unlock_dialog_button_text_password); - break; - default: - Log.e(TAG, "Encountered unexpected screen lock type when attempting to set " - + "button text:" + passwordQuality); - } - } - - private WindowManager.LayoutParams createLayoutParams() { - final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( - WindowManager.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, - WindowManager.LayoutParams.FLAG_FULLSCREEN - | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS - | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, - PixelFormat.TRANSLUCENT - ); - attrs.setFitInsetsTypes(0 /* types */); - return attrs; - } - - private void logd(String message) { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, message); - } - } - - /** - * Listener used to notify when the dialog is hidden - */ - interface OnHideListener { - void onHide(boolean dismissUserSwitcher); - } -} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java index 627729768e88..149531f75029 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java @@ -16,29 +16,9 @@ package com.android.systemui.car.userswitcher; -import android.car.Car; -import android.car.trust.CarTrustAgentEnrollmentManager; -import android.car.userlib.CarUserManagerHelper; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.UserInfo; -import android.content.res.Resources; -import android.os.Handler; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.Log; - -import com.android.internal.widget.LockPatternUtils; -import com.android.systemui.R; -import com.android.systemui.car.CarServiceProvider; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.car.keyguard.CarKeyguardViewController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.car.CarStatusBar; -import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager; import com.android.systemui.window.OverlayViewMediator; import javax.inject.Inject; @@ -51,98 +31,24 @@ import javax.inject.Singleton; public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator { private static final String TAG = FullscreenUserSwitcherViewMediator.class.getSimpleName(); - private final Context mContext; - private final UserManager mUserManager; - private final CarServiceProvider mCarServiceProvider; - private final CarTrustAgentUnlockDialogHelper mUnlockDialogHelper; - private final CarStatusBarKeyguardViewManager mCarStatusBarKeyguardViewManager; - private final Handler mMainHandler; private final StatusBarStateController mStatusBarStateController; private final FullScreenUserSwitcherViewController mFullScreenUserSwitcherViewController; - private final ScreenLifecycle mScreenLifecycle; - private final CarStatusBar mCarStatusBar; - private final boolean mIsUserSwitcherEnabled; - private final CarUserManagerHelper mCarUserManagerHelper; - - private CarTrustAgentEnrollmentManager mEnrollmentManager; - private UserGridRecyclerView.UserRecord mSelectedUser; - private final CarTrustAgentUnlockDialogHelper.OnHideListener mOnHideListener = - dismissUserSwitcher -> { - if (dismissUserSwitcher) { - dismissUserSwitcher(); - } else { - // Re-draw the parent view, otherwise the unlock dialog will not be removed - // from the screen immediately. - invalidateFullscreenUserSwitcherView(); - } - }; - private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "user 0 is unlocked, SharedPreference is accessible."); - } - showDialogForInitialUser(); - mContext.unregisterReceiver(mUserUnlockReceiver); - } - }; + private final CarKeyguardViewController mCarKeyguardViewController; @Inject public FullscreenUserSwitcherViewMediator( - Context context, - @Main Resources resources, - @Main Handler mainHandler, - UserManager userManager, - CarServiceProvider carServiceProvider, - CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper, - CarStatusBarKeyguardViewManager carStatusBarKeyguardViewManager, - CarStatusBar carStatusBar, StatusBarStateController statusBarStateController, - FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController, - ScreenLifecycle screenLifecycle) { - mContext = context; - - mIsUserSwitcherEnabled = resources.getBoolean(R.bool.config_enableFullscreenUserSwitcher); - - mMainHandler = mainHandler; - mUserManager = userManager; + CarKeyguardViewController carKeyguardViewController, + FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController) { - mCarServiceProvider = carServiceProvider; - mCarServiceProvider.addListener( - car -> mEnrollmentManager = (CarTrustAgentEnrollmentManager) car.getCarManager( - Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE)); - - mUnlockDialogHelper = carTrustAgentUnlockDialogHelper; - mCarStatusBarKeyguardViewManager = carStatusBarKeyguardViewManager; - mCarStatusBar = carStatusBar; mStatusBarStateController = statusBarStateController; mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController; - mScreenLifecycle = screenLifecycle; - - mCarUserManagerHelper = new CarUserManagerHelper(mContext); + mCarKeyguardViewController = carKeyguardViewController; } @Override public void registerListeners() { - registerUserSwitcherShowListeners(); registerUserSwitcherHideListeners(); - registerHideKeyguardListeners(); - - if (mUserManager.isUserUnlocked(UserHandle.USER_SYSTEM)) { - // User0 is unlocked, switched to the initial user - showDialogForInitialUser(); - } else { - // listen to USER_UNLOCKED - mContext.registerReceiverAsUser(mUserUnlockReceiver, - UserHandle.getUserHandleForUid(UserHandle.USER_SYSTEM), - new IntentFilter(Intent.ACTION_USER_UNLOCKED), - /* broadcastPermission= */ null, - /* scheduler= */ null); - } - } - - private void registerUserSwitcherShowListeners() { - mCarStatusBarKeyguardViewManager.addOnKeyguardCancelClickedListener(this::show); } private void registerUserSwitcherHideListeners() { @@ -157,130 +63,22 @@ public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator { }); } - private void registerHideKeyguardListeners() { - mStatusBarStateController.addCallback(new StatusBarStateController.StateListener() { - @Override - public void onStateChanged(int newState) { - if (newState != StatusBarState.FULLSCREEN_USER_SWITCHER) { - return; - } - dismissKeyguardWhenUserSwitcherNotDisplayed(newState); - } - }); - - mScreenLifecycle.addObserver(new ScreenLifecycle.Observer() { - @Override - public void onScreenTurnedOn() { - dismissKeyguardWhenUserSwitcherNotDisplayed(mStatusBarStateController.getState()); - } - }); - - mContext.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (!intent.getAction().equals(Intent.ACTION_USER_SWITCHED)) { - return; - } - - // Try to dismiss the keyguard after every user switch. - dismissKeyguardWhenUserSwitcherNotDisplayed(mStatusBarStateController.getState()); - } - }, new IntentFilter(Intent.ACTION_USER_SWITCHED)); - } - @Override public void setupOverlayContentViewControllers() { mFullScreenUserSwitcherViewController.setUserGridSelectionListener(this::onUserSelected); } /** - * Every time user clicks on an item in the switcher, if the clicked user has no trusted - * device, we hide the switcher, either gradually or immediately. - * If the user has trusted device, we show an unlock dialog to notify user the unlock - * state. - * When the unlock dialog is dismissed by user, we hide the unlock dialog and the switcher. - * We dismiss the entire keyguard when we hide the switcher if user clicked on the - * foreground user (user we're already logged in as). + * Every time user clicks on an item in the switcher, we hide the switcher. */ private void onUserSelected(UserGridRecyclerView.UserRecord record) { - mSelectedUser = record; - if (record.mInfo != null) { - if (hasScreenLock(record.mInfo.id) && hasTrustedDevice(record.mInfo.id)) { - mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, mOnHideListener); - return; - } - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "no trusted device enrolled for uid: " + record.mInfo.id); - } + if (record.mType != UserGridRecyclerView.UserRecord.FOREGROUND_USER) { + mCarKeyguardViewController.hideKeyguardToPrepareBouncer(); } - dismissUserSwitcher(); - } - - // We automatically dismiss keyguard unless user switcher is being shown above the keyguard. - private void dismissKeyguardWhenUserSwitcherNotDisplayed(int state) { - if (!mIsUserSwitcherEnabled) { - return; // Not using the full screen user switcher. - } - - if (state == StatusBarState.FULLSCREEN_USER_SWITCHER - && !mFullScreenUserSwitcherViewController.isVisible()) { - // Current execution path continues to set state after this, thus we deffer the - // dismissal to the next execution cycle. - - // Dismiss the keyguard if switcher is not visible. - // TODO(b/150402329): Remove once keyguard is implemented using Overlay Window - // abstractions. - mMainHandler.post(mCarStatusBar::dismissKeyguard); - } - } - private boolean hasScreenLock(int uid) { - LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); - return lockPatternUtils.getCredentialTypeForUser(uid) - != LockPatternUtils.CREDENTIAL_TYPE_NONE; - } - - private boolean hasTrustedDevice(int uid) { - if (mEnrollmentManager == null) { // car service not ready, so it cannot be available. - return false; - } - return !mEnrollmentManager.getEnrolledDeviceInfoForUser(uid).isEmpty(); - } - - private void dismissUserSwitcher() { - if (mSelectedUser == null) { - Log.e(TAG, "Request to dismiss user switcher, but no user selected"); - return; - } - if (mSelectedUser.mType == UserGridRecyclerView.UserRecord.FOREGROUND_USER) { - hide(); - mCarStatusBar.dismissKeyguard(); - return; - } hide(); } - private void showDialogForInitialUser() { - int initialUser = mCarUserManagerHelper.getInitialUser(); - UserInfo initialUserInfo = mUserManager.getUserInfo(initialUser); - mSelectedUser = new UserGridRecyclerView.UserRecord(initialUserInfo, - UserGridRecyclerView.UserRecord.FOREGROUND_USER); - - // If the initial user has screen lock and trusted device, display the unlock dialog on the - // keyguard. - if (hasScreenLock(initialUser) && hasTrustedDevice(initialUser)) { - mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser, - mOnHideListener); - } else { - // If no trusted device, dismiss the keyguard. - dismissUserSwitcher(); - } - } - - private void invalidateFullscreenUserSwitcherView() { - mFullScreenUserSwitcherViewController.invalidate(); - } - private void hide() { mFullScreenUserSwitcherViewController.stop(); } diff --git a/packages/CarSystemUI/src/com/android/systemui/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/window/OverlayPanelViewController.java new file mode 100644 index 000000000000..58022f12e58c --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/window/OverlayPanelViewController.java @@ -0,0 +1,563 @@ +/* + * 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.window; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Rect; +import android.util.Log; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewTreeObserver; + +import androidx.annotation.CallSuper; + +import com.android.systemui.R; +import com.android.systemui.car.CarDeviceProvisionedController; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.statusbar.FlingAnimationUtils; + +/** + * The {@link OverlayPanelViewController} provides additional dragging animation capabilities to + * {@link OverlayViewController}. + */ +public abstract class OverlayPanelViewController extends OverlayViewController { + + private static final boolean DEBUG = true; + private static final String TAG = "OverlayPanelViewController"; + + // used to calculate how fast to open or close the window + protected static final float DEFAULT_FLING_VELOCITY = 0; + // max time a fling animation takes + protected static final float FLING_ANIMATION_MAX_TIME = 0.5f; + // acceleration rate for the fling animation + protected static final float FLING_SPEED_UP_FACTOR = 0.6f; + + protected static final int SWIPE_DOWN_MIN_DISTANCE = 25; + protected static final int SWIPE_MAX_OFF_PATH = 75; + protected static final int SWIPE_THRESHOLD_VELOCITY = 200; + + private final FlingAnimationUtils mFlingAnimationUtils; + private final CarDeviceProvisionedController mCarDeviceProvisionedController; + private final View.OnTouchListener mDragOpenTouchListener; + private final View.OnTouchListener mDragCloseTouchListener; + + private final int mSettleClosePercentage; + private int mPercentageFromBottom; + + private boolean mPanelVisible; + private boolean mPanelExpanded; + + private float mOpeningVelocity = DEFAULT_FLING_VELOCITY; + private float mClosingVelocity = DEFAULT_FLING_VELOCITY; + + private boolean mIsAnimating; + private boolean mIsTracking; + + public OverlayPanelViewController( + Context context, + @Main Resources resources, + int stubId, + OverlayViewGlobalStateController overlayViewGlobalStateController, + FlingAnimationUtils.Builder flingAnimationUtilsBuilder, + CarDeviceProvisionedController carDeviceProvisionedController + ) { + super(stubId, overlayViewGlobalStateController); + + mFlingAnimationUtils = flingAnimationUtilsBuilder + .setMaxLengthSeconds(FLING_ANIMATION_MAX_TIME) + .setSpeedUpFactor(FLING_SPEED_UP_FACTOR) + .build(); + mCarDeviceProvisionedController = carDeviceProvisionedController; + + mSettleClosePercentage = resources.getInteger( + R.integer.notification_settle_close_percentage); + + // Attached to the top navigation bar (i.e. status bar) to detect pull down of the + // notification shade. + GestureDetector openGestureDetector = new GestureDetector(context, + new OpenGestureListener() { + @Override + protected void open() { + animateExpandPanel(); + } + }); + + // Attached to the NavBars to close the notification shade + GestureDetector navBarCloseNotificationGestureDetector = new GestureDetector(context, + new SystemBarCloseGestureListener() { + @Override + protected void close() { + if (isPanelExpanded()) { + animateCollapsePanel(); + } + } + }); + + mDragOpenTouchListener = (v, event) -> { + if (!mCarDeviceProvisionedController.isCurrentUserFullySetup()) { + return true; + } + if (!isInflated()) { + getOverlayViewGlobalStateController().inflateView(this); + } + + boolean consumed = openGestureDetector.onTouchEvent(event); + if (consumed) { + return true; + } + maybeCompleteAnimation(event); + return true; + }; + + mDragCloseTouchListener = (v, event) -> { + if (!isInflated()) { + return true; + } + boolean consumed = navBarCloseNotificationGestureDetector.onTouchEvent(event); + if (consumed) { + return true; + } + maybeCompleteAnimation(event); + return true; + }; + } + + /** Toggles the visibility of the panel. */ + public void toggle() { + if (!isInflated()) { + getOverlayViewGlobalStateController().inflateView(this); + } + if (isPanelExpanded()) { + animateCollapsePanel(); + } else { + animateExpandPanel(); + } + } + + /* ***************************************************************************************** * + * Panel Animation + * ***************************************************************************************** */ + + /** Animates the closing of the panel. */ + protected void animateCollapsePanel() { + if (!shouldAnimateCollapsePanel()) { + return; + } + + if (!isPanelExpanded() || !isPanelVisible()) { + return; + } + + onAnimateCollapsePanel(); + getOverlayViewGlobalStateController().setWindowFocusable(false); + animatePanel(mClosingVelocity, /* isClosing= */ true); + } + + /** Determines whether {@link #animateCollapsePanel()} should collapse the panel. */ + protected abstract boolean shouldAnimateCollapsePanel(); + + /** Called when the panel is beginning to collapse. */ + protected abstract void onAnimateCollapsePanel(); + + /** Animates the expansion of the panel. */ + protected void animateExpandPanel() { + if (!shouldAnimateExpandPanel()) { + return; + } + + if (!mCarDeviceProvisionedController.isCurrentUserFullySetup()) { + return; + } + + onAnimateExpandPanel(); + setPanelVisible(true); + animatePanel(mOpeningVelocity, /* isClosing= */ false); + + setPanelExpanded(true); + } + + /** Determines whether {@link #animateExpandPanel()}} should expand the panel. */ + protected abstract boolean shouldAnimateExpandPanel(); + + /** Called when the panel is beginning to expand. */ + protected abstract void onAnimateExpandPanel(); + + /** + * Depending on certain conditions, determines whether to fully expand or collapse the panel. + */ + protected void maybeCompleteAnimation(MotionEvent event) { + if (event.getActionMasked() == MotionEvent.ACTION_UP + && isPanelVisible()) { + if (mSettleClosePercentage < mPercentageFromBottom) { + animatePanel(DEFAULT_FLING_VELOCITY, false); + } else { + animatePanel(DEFAULT_FLING_VELOCITY, true); + } + } + } + + /** + * Animates the panel from one position to other. This is used to either open or + * close the panel completely with a velocity. If the animation is to close the + * panel this method also makes the view invisible after animation ends. + */ + protected void animatePanel(float velocity, boolean isClosing) { + float to = 0; + if (!isClosing) { + to = getLayout().getHeight(); + } + + Rect rect = getLayout().getClipBounds(); + if (rect != null && rect.bottom != to) { + float from = rect.bottom; + animate(from, to, velocity, isClosing); + return; + } + + // We will only be here if the shade is being opened programmatically or via button when + // height of the layout was not calculated. + ViewTreeObserver notificationTreeObserver = getLayout().getViewTreeObserver(); + notificationTreeObserver.addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + ViewTreeObserver obs = getLayout().getViewTreeObserver(); + obs.removeOnGlobalLayoutListener(this); + float to = getLayout().getHeight(); + animate(/* from= */ 0, to, velocity, isClosing); + } + }); + } + + private void animate(float from, float to, float velocity, boolean isClosing) { + if (mIsAnimating) { + return; + } + mIsAnimating = true; + mIsTracking = true; + ValueAnimator animator = ValueAnimator.ofFloat(from, to); + animator.addUpdateListener( + animation -> { + float animatedValue = (Float) animation.getAnimatedValue(); + setViewClipBounds((int) animatedValue); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mIsAnimating = false; + mIsTracking = false; + mOpeningVelocity = DEFAULT_FLING_VELOCITY; + mClosingVelocity = DEFAULT_FLING_VELOCITY; + if (isClosing) { + setPanelVisible(false); + getLayout().setClipBounds(null); + onCollapseAnimationEnd(); + setPanelExpanded(false); + } else { + onExpandAnimationEnd(); + setPanelExpanded(true); + } + } + }); + getFlingAnimationUtils().apply(animator, from, to, Math.abs(velocity)); + animator.start(); + } + + /** + * Called in {@link Animator.AnimatorListener#onAnimationEnd(Animator)} when the panel is + * closing. + */ + protected abstract void onCollapseAnimationEnd(); + + /** + * Called in {@link Animator.AnimatorListener#onAnimationEnd(Animator)} when the panel is + * opening. + */ + protected abstract void onExpandAnimationEnd(); + + /* ***************************************************************************************** * + * Panel Visibility + * ***************************************************************************************** */ + + /** Set the panel view to be visible. */ + protected final void setPanelVisible(boolean visible) { + mPanelVisible = visible; + onPanelVisible(visible); + } + + /** Returns {@code true} if panel is visible. */ + public final boolean isPanelVisible() { + return mPanelVisible; + } + + /** Business logic run when panel visibility is set. */ + @CallSuper + protected void onPanelVisible(boolean visible) { + if (DEBUG) { + Log.e(TAG, "onPanelVisible: " + visible); + } + + if (visible && !getOverlayViewGlobalStateController().isWindowVisible()) { + getOverlayViewGlobalStateController().setWindowVisible(true); + } + if (!visible && getOverlayViewGlobalStateController().isWindowVisible()) { + getOverlayViewGlobalStateController().setWindowVisible(false); + } + getLayout().setVisibility(visible ? View.VISIBLE : View.INVISIBLE); + getOverlayViewGlobalStateController().setWindowFocusable(visible); + } + + /* ***************************************************************************************** * + * Panel Expansion + * ***************************************************************************************** */ + + /** + * Set the panel state to expanded. This will expand or collapse the overlay window if + * necessary. + */ + protected final void setPanelExpanded(boolean expand) { + mPanelExpanded = expand; + onPanelExpanded(expand); + } + + /** Returns {@code true} if panel is expanded. */ + public final boolean isPanelExpanded() { + return mPanelExpanded; + } + + @CallSuper + protected void onPanelExpanded(boolean expand) { + if (DEBUG) { + Log.e(TAG, "onPanelExpanded: " + expand); + } + } + + /* ***************************************************************************************** * + * Misc + * ***************************************************************************************** */ + + protected void calculatePercentageFromBottom(float height) { + if (getLayout().getHeight() > 0) { + mPercentageFromBottom = (int) Math.abs( + height / getLayout().getHeight() * 100); + } + } + + protected void setViewClipBounds(int height) { + if (height > getLayout().getHeight()) { + height = getLayout().getHeight(); + } + Rect clipBounds = new Rect(); + clipBounds.set(0, 0, getLayout().getWidth(), height); + getLayout().setClipBounds(clipBounds); + onScroll(height); + } + + /** Called while scrolling. */ + protected abstract void onScroll(int height); + + /* ***************************************************************************************** * + * Getters + * ***************************************************************************************** */ + + /** Returns the open touch listener. */ + public final View.OnTouchListener getDragOpenTouchListener() { + return mDragOpenTouchListener; + } + + /** Returns the close touch listener. */ + public final View.OnTouchListener getDragCloseTouchListener() { + return mDragCloseTouchListener; + } + + /** Gets the fling animation utils used for animating this panel. */ + protected final FlingAnimationUtils getFlingAnimationUtils() { + return mFlingAnimationUtils; + } + + /** Returns {@code true} if the panel is currently tracking. */ + protected final boolean isTracking() { + return mIsTracking; + } + + /** Returns {@code true} if the panel is currently animating. */ + protected final boolean isAnimating() { + return mIsAnimating; + } + + /** Returns the percentage of the panel that is open from the bottom. */ + protected final int getPercentageFromBottom() { + return mPercentageFromBottom; + } + + /** Returns the percentage at which we've determined whether to open or close the panel. */ + protected final int getSettleClosePercentage() { + return mSettleClosePercentage; + } + + /* ***************************************************************************************** * + * Gesture Listeners + * ***************************************************************************************** */ + + /** Called when the user is beginning to scroll down the panel. */ + protected abstract void onOpenScrollStart(); + + /** + * Only responsible for open hooks. Since once the panel opens it covers all elements + * there is no need to merge with close. + */ + protected abstract class OpenGestureListener extends + GestureDetector.SimpleOnGestureListener { + + @Override + public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, + float distanceY) { + + if (!isPanelVisible()) { + onOpenScrollStart(); + } + setPanelVisible(true); + + // clips the view for the notification shade when the user scrolls to open. + setViewClipBounds((int) event2.getRawY()); + + // Initially the scroll starts with height being zero. This checks protects from divide + // by zero error. + calculatePercentageFromBottom(event2.getRawY()); + + mIsTracking = true; + return true; + } + + + @Override + public boolean onFling(MotionEvent event1, MotionEvent event2, + float velocityX, float velocityY) { + if (velocityY > SWIPE_THRESHOLD_VELOCITY) { + mOpeningVelocity = velocityY; + open(); + return true; + } + animatePanel(DEFAULT_FLING_VELOCITY, true); + + return false; + } + + protected abstract void open(); + } + + /** Determines whether the scroll event should allow closing of the panel. */ + protected abstract boolean shouldAllowClosingScroll(); + + protected abstract class CloseGestureListener extends + GestureDetector.SimpleOnGestureListener { + + @Override + public boolean onSingleTapUp(MotionEvent motionEvent) { + if (isPanelExpanded()) { + animatePanel(DEFAULT_FLING_VELOCITY, true); + } + return true; + } + + @Override + public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, + float distanceY) { + // should not clip while scroll to the bottom of the list. + if (!shouldAllowClosingScroll()) { + return false; + } + float actualNotificationHeight = + getLayout().getHeight() - (event1.getRawY() - event2.getRawY()); + if (actualNotificationHeight > getLayout().getHeight()) { + actualNotificationHeight = getLayout().getHeight(); + } + if (getLayout().getHeight() > 0) { + mPercentageFromBottom = (int) Math.abs( + actualNotificationHeight / getLayout().getHeight() * 100); + boolean isUp = distanceY > 0; + + // This check is to figure out if onScroll was called while swiping the card at + // bottom of the list. At that time we should not allow notification shade to + // close. We are also checking for the upwards swipe gesture here because it is + // possible if a user is closing the notification shade and while swiping starts + // to open again but does not fling. At that time we should allow the + // notification shade to close fully or else it would stuck in between. + if (Math.abs(getLayout().getHeight() - actualNotificationHeight) + > SWIPE_DOWN_MIN_DISTANCE && isUp) { + setViewClipBounds((int) actualNotificationHeight); + mIsTracking = true; + } else if (!isUp) { + setViewClipBounds((int) actualNotificationHeight); + } + } + // if we return true the items in RV won't be scrollable. + return false; + } + + + @Override + public boolean onFling(MotionEvent event1, MotionEvent event2, + float velocityX, float velocityY) { + // should not fling if the touch does not start when view is at the bottom of the list. + if (!shouldAllowClosingScroll()) { + return false; + } + if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH + || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) { + // swipe was not vertical or was not fast enough + return false; + } + boolean isUp = velocityY < 0; + if (isUp) { + close(); + return true; + } else { + // we should close the shade + animatePanel(velocityY, false); + } + return false; + } + + protected abstract void close(); + } + + protected abstract class SystemBarCloseGestureListener extends CloseGestureListener { + @Override + public boolean onSingleTapUp(MotionEvent e) { + mClosingVelocity = DEFAULT_FLING_VELOCITY; + if (isPanelExpanded()) { + close(); + } + return super.onSingleTapUp(e); + } + + @Override + public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, + float distanceY) { + calculatePercentageFromBottom(event2.getRawY()); + setViewClipBounds((int) event2.getRawY()); + return true; + } + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java b/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java index dd29f8dac387..6b4f3e37bc18 100644 --- a/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java @@ -16,6 +16,7 @@ package com.android.systemui.window; +import com.android.systemui.car.keyguard.CarKeyguardViewMediator; import com.android.systemui.car.notification.NotificationPanelViewMediator; import com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator; @@ -29,12 +30,6 @@ import dagger.multibindings.IntoMap; */ @Module public abstract class OverlayWindowModule { - /** Injects FullscreenUserSwitcherViewsMediator. */ - @Binds - @IntoMap - @ClassKey(FullscreenUserSwitcherViewMediator.class) - public abstract OverlayViewMediator bindFullscreenUserSwitcherViewsMediator( - FullscreenUserSwitcherViewMediator overlayViewsMediator); /** Injects NotificationPanelViewMediator. */ @Binds @@ -42,4 +37,18 @@ public abstract class OverlayWindowModule { @ClassKey(NotificationPanelViewMediator.class) public abstract OverlayViewMediator bindNotificationPanelViewMediator( NotificationPanelViewMediator notificationPanelViewMediator); + + /** Inject into CarKeyguardViewMediator. */ + @Binds + @IntoMap + @ClassKey(CarKeyguardViewMediator.class) + public abstract OverlayViewMediator bindCarKeyguardViewMediator( + CarKeyguardViewMediator carKeyguardViewMediator); + + /** Injects FullscreenUserSwitcherViewsMediator. */ + @Binds + @IntoMap + @ClassKey(FullscreenUserSwitcherViewMediator.class) + public abstract OverlayViewMediator bindFullscreenUserSwitcherViewsMediator( + FullscreenUserSwitcherViewMediator overlayViewsMediator); } diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarTest.java index f2748b89c95c..76557fda6926 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarTest.java @@ -20,13 +20,14 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.os.Handler; -import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableResources; import android.view.LayoutInflater; import android.view.WindowManager; +import androidx.test.filters.SmallTest; + import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarDeviceProvisionedController; diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayPanelViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayPanelViewControllerTest.java new file mode 100644 index 000000000000..04f2d06ca71c --- /dev/null +++ b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayPanelViewControllerTest.java @@ -0,0 +1,431 @@ +/* + * 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.window; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.res.Resources; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarDeviceProvisionedController; +import com.android.systemui.statusbar.FlingAnimationUtils; +import com.android.systemui.tests.R; + +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; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class OverlayPanelViewControllerTest extends SysuiTestCase { + private TestOverlayPanelViewController mOverlayPanelViewController; + private ViewGroup mBaseLayout; + + @Mock + private OverlayViewGlobalStateController mOverlayViewGlobalStateController; + @Mock + private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder; + @Mock + private FlingAnimationUtils mFlingAnimationUtils; + @Mock + private CarDeviceProvisionedController mCarDeviceProvisionedController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate( + R.layout.overlay_view_controller_test, /* root= */ null); + + when(mFlingAnimationUtilsBuilder.setMaxLengthSeconds(anyFloat())).thenReturn( + mFlingAnimationUtilsBuilder); + when(mFlingAnimationUtilsBuilder.setSpeedUpFactor(anyFloat())).thenReturn( + mFlingAnimationUtilsBuilder); + when(mFlingAnimationUtilsBuilder.build()).thenReturn(mFlingAnimationUtils); + mOverlayPanelViewController = new TestOverlayPanelViewController( + getContext(), + getContext().getOrCreateTestableResources().getResources(), + R.id.overlay_view_controller_stub, + mOverlayViewGlobalStateController, + mFlingAnimationUtilsBuilder, + mCarDeviceProvisionedController); + } + + @Test + public void toggle_notInflated_inflates() { + assertThat(mOverlayPanelViewController.isInflated()).isFalse(); + + mOverlayPanelViewController.toggle(); + + verify(mOverlayViewGlobalStateController).inflateView(mOverlayPanelViewController); + } + + @Test + public void toggle_inflated_doesNotInflate() { + mOverlayPanelViewController.inflate(mBaseLayout); + assertThat(mOverlayPanelViewController.isInflated()).isTrue(); + + mOverlayPanelViewController.toggle(); + + verify(mOverlayViewGlobalStateController, never()).inflateView(mOverlayPanelViewController); + } + + @Test + public void toggle_notExpanded_panelExpands() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setPanelExpanded(false); + + mOverlayPanelViewController.toggle(); + + assertThat(mOverlayPanelViewController.mAnimateExpandPanelCalled).isTrue(); + } + + @Test + public void toggle_expanded_panelCollapses() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setPanelExpanded(true); + + mOverlayPanelViewController.toggle(); + + assertThat(mOverlayPanelViewController.mAnimateCollapsePanelCalled).isTrue(); + } + + @Test + public void animateCollapsePanel_shouldNotAnimateCollapsePanel_doesNotCollapse() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setShouldAnimateCollapsePanel(false); + + mOverlayPanelViewController.animateCollapsePanel(); + + assertThat(mOverlayPanelViewController.mAnimateCollapsePanelCalled).isTrue(); + assertThat(mOverlayPanelViewController.mOnAnimateCollapsePanelCalled).isFalse(); + } + + @Test + public void animateCollapsePanel_isNotExpanded_doesNotCollapse() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setShouldAnimateCollapsePanel(true); + mOverlayPanelViewController.setPanelExpanded(false); + + mOverlayPanelViewController.animateCollapsePanel(); + + assertThat(mOverlayPanelViewController.mAnimateCollapsePanelCalled).isTrue(); + assertThat(mOverlayPanelViewController.mOnAnimateCollapsePanelCalled).isFalse(); + } + + @Test + public void animateCollapsePanel_isNotVisible_doesNotCollapse() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setShouldAnimateCollapsePanel(true); + mOverlayPanelViewController.setPanelExpanded(true); + mOverlayPanelViewController.setPanelVisible(false); + + mOverlayPanelViewController.animateCollapsePanel(); + + assertThat(mOverlayPanelViewController.mAnimateCollapsePanelCalled).isTrue(); + assertThat(mOverlayPanelViewController.mOnAnimateCollapsePanelCalled).isFalse(); + } + + @Test + public void animateCollapsePanel_collapses() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setShouldAnimateCollapsePanel(true); + mOverlayPanelViewController.setPanelExpanded(true); + mOverlayPanelViewController.setPanelVisible(true); + + mOverlayPanelViewController.animateCollapsePanel(); + + assertThat(mOverlayPanelViewController.mOnAnimateCollapsePanelCalled).isTrue(); + } + + @Test + public void animateCollapsePanel_removesWindowFocus() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setShouldAnimateCollapsePanel(true); + mOverlayPanelViewController.setPanelExpanded(true); + mOverlayPanelViewController.setPanelVisible(true); + + mOverlayPanelViewController.animateCollapsePanel(); + + verify(mOverlayViewGlobalStateController).setWindowFocusable(false); + } + + @Test + public void animateExpandPanel_shouldNotAnimateExpandPanel_doesNotExpand() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setShouldAnimateExpandPanel(false); + + mOverlayPanelViewController.animateExpandPanel(); + + assertThat(mOverlayPanelViewController.mAnimateExpandPanelCalled).isTrue(); + assertThat(mOverlayPanelViewController.mOnAnimateExpandPanelCalled).isFalse(); + } + + @Test + public void animateExpandPanel_userNotSetup_doesNotExpand() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setShouldAnimateExpandPanel(true); + when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(false); + + mOverlayPanelViewController.animateExpandPanel(); + + assertThat(mOverlayPanelViewController.mAnimateExpandPanelCalled).isTrue(); + assertThat(mOverlayPanelViewController.mOnAnimateExpandPanelCalled).isFalse(); + } + + @Test + public void animateExpandPanel_expands() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setShouldAnimateExpandPanel(true); + when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true); + + mOverlayPanelViewController.animateExpandPanel(); + + assertThat(mOverlayPanelViewController.mOnAnimateExpandPanelCalled).isTrue(); + } + + @Test + public void animateExpandPanel_setsPanelVisible() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setShouldAnimateExpandPanel(true); + when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true); + + mOverlayPanelViewController.animateExpandPanel(); + + assertThat(mOverlayPanelViewController.isPanelVisible()).isTrue(); + } + + @Test + public void animateExpandPanel_setsPanelExpanded() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setShouldAnimateExpandPanel(true); + when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true); + + mOverlayPanelViewController.animateExpandPanel(); + + assertThat(mOverlayPanelViewController.isPanelExpanded()).isTrue(); + } + + @Test + public void setPanelVisible_setTrue_windowNotVisible_setsWindowVisible() { + mOverlayPanelViewController.inflate(mBaseLayout); + when(mOverlayViewGlobalStateController.isWindowVisible()).thenReturn(false); + + mOverlayPanelViewController.setPanelVisible(true); + + verify(mOverlayViewGlobalStateController).setWindowVisible(true); + } + + @Test + public void setPanelVisible_setTrue_windowVisible_doesNotSetWindowVisible() { + mOverlayPanelViewController.inflate(mBaseLayout); + when(mOverlayViewGlobalStateController.isWindowVisible()).thenReturn(true); + + mOverlayPanelViewController.setPanelVisible(true); + + verify(mOverlayViewGlobalStateController, never()).setWindowVisible(true); + } + + @Test + public void setPanelVisible_setTrue_setLayoutVisible() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.getLayout().setVisibility(View.INVISIBLE); + + mOverlayPanelViewController.setPanelVisible(true); + + assertThat(mOverlayPanelViewController.getLayout().getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void setPanelVisible_setTrue_setWindowFocusable() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.setPanelVisible(true); + + verify(mOverlayViewGlobalStateController).setWindowFocusable(true); + } + + @Test + public void setPanelVisible_setFalse_windowVisible_setsWindowNotVisible() { + mOverlayPanelViewController.inflate(mBaseLayout); + when(mOverlayViewGlobalStateController.isWindowVisible()).thenReturn(true); + + mOverlayPanelViewController.setPanelVisible(false); + + verify(mOverlayViewGlobalStateController).setWindowVisible(false); + } + + @Test + public void setPanelVisible_setFalse_windowNotVisible_doesNotSetWindowNotVisible() { + mOverlayPanelViewController.inflate(mBaseLayout); + when(mOverlayViewGlobalStateController.isWindowVisible()).thenReturn(false); + + mOverlayPanelViewController.setPanelVisible(false); + + verify(mOverlayViewGlobalStateController, never()).setWindowVisible(false); + } + + @Test + public void setPanelVisible_setFalse_setLayoutInvisible() { + mOverlayPanelViewController.inflate(mBaseLayout); + mOverlayPanelViewController.getLayout().setVisibility(View.VISIBLE); + + mOverlayPanelViewController.setPanelVisible(false); + + assertThat(mOverlayPanelViewController.getLayout().getVisibility()).isEqualTo( + View.INVISIBLE); + } + + @Test + public void setPanelVisible_setFalse_setWindowNotFocusable() { + mOverlayPanelViewController.inflate(mBaseLayout); + + mOverlayPanelViewController.setPanelVisible(false); + + verify(mOverlayViewGlobalStateController).setWindowFocusable(false); + } + + @Test + public void dragOpenTouchListener_isNotInflated_inflatesView() { + when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true); + assertThat(mOverlayPanelViewController.isInflated()).isFalse(); + + mOverlayPanelViewController.getDragOpenTouchListener().onTouch(/* v= */ null, + MotionEvent.obtain(/* downTime= */ 200, /* eventTime= */ 300, + MotionEvent.ACTION_MOVE, /* x= */ 0, /* y= */ 0, /* metaState= */ 0)); + + verify(mOverlayViewGlobalStateController).inflateView(mOverlayPanelViewController); + } + + private static class TestOverlayPanelViewController extends OverlayPanelViewController { + + private boolean mShouldAnimateCollapsePanel; + private boolean mShouldAnimateExpandPanel; + private boolean mShouldAllowClosingScroll; + + boolean mOnAnimateCollapsePanelCalled; + boolean mAnimateCollapsePanelCalled; + boolean mOnAnimateExpandPanelCalled; + boolean mAnimateExpandPanelCalled; + boolean mOnCollapseAnimationEndCalled; + boolean mOnExpandAnimationEndCalled; + boolean mOnOpenScrollStartEnd; + List<Integer> mOnScrollHeights; + + TestOverlayPanelViewController( + Context context, + Resources resources, + int stubId, + OverlayViewGlobalStateController overlayViewGlobalStateController, + FlingAnimationUtils.Builder flingAnimationUtilsBuilder, + CarDeviceProvisionedController carDeviceProvisionedController) { + super(context, resources, stubId, overlayViewGlobalStateController, + flingAnimationUtilsBuilder, + carDeviceProvisionedController); + + mOnScrollHeights = new ArrayList<>(); + } + + public void setShouldAnimateCollapsePanel(boolean shouldAnimate) { + mShouldAnimateCollapsePanel = shouldAnimate; + } + + @Override + protected boolean shouldAnimateCollapsePanel() { + return mShouldAnimateCollapsePanel; + } + + @Override + protected void animateCollapsePanel() { + super.animateCollapsePanel(); + mAnimateCollapsePanelCalled = true; + } + + @Override + protected void onAnimateCollapsePanel() { + mOnAnimateCollapsePanelCalled = true; + } + + public void setShouldAnimateExpandPanel(boolean shouldAnimate) { + mShouldAnimateExpandPanel = shouldAnimate; + } + + @Override + protected boolean shouldAnimateExpandPanel() { + return mShouldAnimateExpandPanel; + } + + @Override + protected void animateExpandPanel() { + super.animateExpandPanel(); + mAnimateExpandPanelCalled = true; + } + + @Override + protected void onAnimateExpandPanel() { + mOnAnimateExpandPanelCalled = true; + } + + @Override + protected void onCollapseAnimationEnd() { + mOnCollapseAnimationEndCalled = true; + } + + @Override + protected void onExpandAnimationEnd() { + mOnExpandAnimationEndCalled = true; + } + + @Override + protected void onScroll(int height) { + mOnScrollHeights.add(height); + } + + @Override + protected void onOpenScrollStart() { + mOnOpenScrollStartEnd = true; + } + + public void setShouldAllowClosingScroll(boolean shouldAllow) { + mShouldAllowClosingScroll = shouldAllow; + } + + @Override + protected boolean shouldAllowClosingScroll() { + return mShouldAllowClosingScroll; + } + } +} diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewControllerTest.java index 3be962627f62..331326168ba4 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/window/OverlayViewControllerTest.java @@ -43,7 +43,7 @@ import org.mockito.MockitoAnnotations; @TestableLooper.RunWithLooper @SmallTest public class OverlayViewControllerTest extends SysuiTestCase { - private MockOverlayViewController mOverlayViewController; + private TestOverlayViewController mOverlayViewController; private ViewGroup mBaseLayout; @Mock @@ -56,7 +56,7 @@ public class OverlayViewControllerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(/* testClass= */ this); - mOverlayViewController = new MockOverlayViewController(R.id.overlay_view_controller_stub, + mOverlayViewController = new TestOverlayViewController(R.id.overlay_view_controller_stub, mOverlayViewGlobalStateController); mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate( @@ -130,12 +130,12 @@ public class OverlayViewControllerTest extends SysuiTestCase { assertThat(mOverlayViewController.mHideInternalCalled).isFalse(); } - private static class MockOverlayViewController extends OverlayViewController { + private static class TestOverlayViewController extends OverlayViewController { boolean mOnFinishInflateCalled = false; boolean mShowInternalCalled = false; boolean mHideInternalCalled = false; - MockOverlayViewController(int stubId, + TestOverlayViewController(int stubId, OverlayViewGlobalStateController overlayViewGlobalStateController) { super(stubId, overlayViewGlobalStateController); } diff --git a/packages/CarrierDefaultApp/res/values-hu/strings.xml b/packages/CarrierDefaultApp/res/values-hu/strings.xml index 4ae6ea67bb06..a492e47242af 100644 --- a/packages/CarrierDefaultApp/res/values-hu/strings.xml +++ b/packages/CarrierDefaultApp/res/values-hu/strings.xml @@ -8,7 +8,7 @@ <string name="portal_notification_detail" msgid="2295729385924660881">"Koppintson a(z) %s webhely meglátogatásához"</string> <string name="no_data_notification_detail" msgid="3112125343857014825">"Vegye fel a kapcsolatot szolgáltatójával (%s)"</string> <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Nincs mobiladat-kapcsolat"</string> - <string name="no_mobile_data_connection" msgid="544980465184147010">"Adjon hozzá előfizetést vagy barangolási csomagot a következőn keresztül: %s"</string> + <string name="no_mobile_data_connection" msgid="544980465184147010">"Adjon hozzá előfizetést vagy roamingcsomagot a következőn keresztül: %s"</string> <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Mobiladat-állapot"</string> <string name="action_bar_label" msgid="4290345990334377177">"Bejelentkezés a mobilhálózatra"</string> <string name="ssl_error_warning" msgid="3127935140338254180">"Biztonsági problémák vannak azzal a hálózattal, amelyhez csatlakozni szeretne."</string> diff --git a/packages/CarrierDefaultApp/res/values-ky/strings.xml b/packages/CarrierDefaultApp/res/values-ky/strings.xml index 199476f47be0..bf4c8c323827 100644 --- a/packages/CarrierDefaultApp/res/values-ky/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ky/strings.xml @@ -8,7 +8,7 @@ <string name="portal_notification_detail" msgid="2295729385924660881">"%s сайтына баш багуу үчүн басыңыз"</string> <string name="no_data_notification_detail" msgid="3112125343857014825">"%s Интернет провайдери менен байланышыңыз"</string> <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Мобилдик Интернет жок"</string> - <string name="no_mobile_data_connection" msgid="544980465184147010">"%s аркылуу дайындарды же роуминг планын кошуу"</string> + <string name="no_mobile_data_connection" msgid="544980465184147010">"%s аркылуу дайын-даректерди же роуминг планын кошуу"</string> <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Мобилдик Интернеттин абалы"</string> <string name="action_bar_label" msgid="4290345990334377177">"Мобилдик тармакка кирүү"</string> <string name="ssl_error_warning" msgid="3127935140338254180">"Кошулайын деген тармагыңызда коопсуздук көйгөйлөрү бар."</string> diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml index 2637c3c0b562..4f2719f8e0f8 100644 --- a/packages/PrintSpooler/res/values-hi/strings.xml +++ b/packages/PrintSpooler/res/values-hi/strings.xml @@ -104,7 +104,7 @@ </string-array> <string name="print_write_error_message" msgid="5787642615179572543">"फ़ाइल पर नहीं लिखा जा सका"</string> <string name="print_error_default_message" msgid="8602678405502922346">"क्षमा करें, उससे बात नहीं बनी. फिर से प्रयास करें."</string> - <string name="print_error_retry" msgid="1426421728784259538">"फिर से प्रयास करें"</string> + <string name="print_error_retry" msgid="1426421728784259538">"फिर से कोशिश करें"</string> <string name="print_error_printer_unavailable" msgid="8985614415253203381">"यह प्रिंटर इस समय उपलब्ध नहीं है."</string> <string name="print_cannot_load_page" msgid="6179560924492912009">"झलक नहीं दिखाई जा सकती"</string> <string name="print_preparing_preview" msgid="3939930735671364712">"झलक तैयार हो रही है..."</string> diff --git a/packages/PrintSpooler/res/values-ne/strings.xml b/packages/PrintSpooler/res/values-ne/strings.xml index da49afbc3528..154364de4b53 100644 --- a/packages/PrintSpooler/res/values-ne/strings.xml +++ b/packages/PrintSpooler/res/values-ne/strings.xml @@ -33,7 +33,7 @@ <string name="pages_range_example" msgid="8558694453556945172">"उदाहरण १-५,८,११-१३"</string> <string name="print_preview" msgid="8010217796057763343">"प्रिन्ट पूर्वावलोकन"</string> <string name="install_for_print_preview" msgid="6366303997385509332">"पूर्वावलोकनको लागि PDF भ्यूअर स्थापना गर्नुहोस्"</string> - <string name="printing_app_crashed" msgid="854477616686566398">"मुद्रण अनुप्रयोग क्र्यास भयो"</string> + <string name="printing_app_crashed" msgid="854477616686566398">"प्रिन्टिङ अनुप्रयोग क्र्यास भयो"</string> <string name="generating_print_job" msgid="3119608742651698916">"प्रिन्ट कार्य निर्माण गरिँदै"</string> <string name="save_as_pdf" msgid="5718454119847596853">"PDF को रूपमा सुरक्षित गर्नुहोस्"</string> <string name="all_printers" msgid="5018829726861876202">"सबै प्रिन्टरहरू..."</string> @@ -64,9 +64,9 @@ <string name="notification_channel_progress" msgid="872788690775721436">"चलिरहेका छपाइका कार्यहरू"</string> <string name="notification_channel_failure" msgid="9042250774797916414">"कार्यहरूलाई छाप्न सकिएन"</string> <string name="could_not_create_file" msgid="3425025039427448443">"फाइल सिर्जना गर्न सकिएन"</string> - <string name="print_services_disabled_toast" msgid="9089060734685174685">"केही मुद्रण सम्बन्धी सेवाहरूलाई असक्षम गरिएको छ"</string> + <string name="print_services_disabled_toast" msgid="9089060734685174685">"केही प्रिन्टिङ सम्बन्धी सेवाहरूलाई असक्षम गरिएको छ"</string> <string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिन्टरहरू खोज्दै"</string> - <string name="print_no_print_services" msgid="8561247706423327966">"कुनै पनि मुद्रण सेवाहरू सक्रिय छैनन्"</string> + <string name="print_no_print_services" msgid="8561247706423327966">"कुनै पनि प्रिन्टिङ सेवाहरू सक्रिय छैनन्"</string> <string name="print_no_printers" msgid="4869403323900054866">"कुनै प्रिन्टरहरू भेटाइएन"</string> <string name="cannot_add_printer" msgid="7840348733668023106">"प्रिन्टरहरू थप्न सक्दैन"</string> <string name="select_to_add_printers" msgid="3800709038689830974">"प्रिन्टर थप्नका लागि चयन गर्नुहोस्"</string> diff --git a/packages/PrintSpooler/tests/outofprocess/Android.bp b/packages/PrintSpooler/tests/outofprocess/Android.bp index c6dc26370ebc..0e028b04aaaf 100644 --- a/packages/PrintSpooler/tests/outofprocess/Android.bp +++ b/packages/PrintSpooler/tests/outofprocess/Android.bp @@ -27,4 +27,5 @@ android_test { sdk_version: "test_current", test_suites: ["device-tests"], + required: ["com.android.cts.helpers.aosp"], } diff --git a/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml b/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml index b649e82d10bc..922d73511815 100644 --- a/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml +++ b/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml @@ -18,6 +18,8 @@ <option name="test-file-name" value="PrintSpoolerOutOfProcessTests.apk" /> </target_preparer> + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DeviceInteractionHelperInstaller" /> + <option name="test-suite-tag" value="apct" /> <option name="test-tag" value="PrintSpoolerOutOfProcessTests" /> <option name="config-descriptor:metadata" key="component" value="print" /> diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java index 61c2f54a2bf9..132545b2d5d2 100644 --- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java @@ -36,6 +36,7 @@ import android.print.test.services.FirstPrintService; import android.print.test.services.PrinterDiscoverySessionCallbacks; import android.print.test.services.StubbablePrinterDiscoverySession; import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; import android.support.test.uiautomator.UiSelector; @@ -78,6 +79,10 @@ public class WorkflowTest extends BasePrintTest { void accept(T t) throws InterruptedException; } + public static UiDevice getUiDevice() { + return UiDevice.getInstance(getInstrumentation()); + } + /** * Execute {@code waiter} until {@code condition} is met. * diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml index 6b1f2590f8e2..1d23c31f493d 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml @@ -17,6 +17,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="enabled_by_admin" msgid="6630472777476410137">"ବ୍ୟବସ୍ଥାପକଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string> + <string name="enabled_by_admin" msgid="6630472777476410137">"ଆଡମିନଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string> <string name="disabled_by_admin" msgid="4023569940620832713">"ବ୍ୟବସ୍ଥାପକଙ୍କ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-be/strings.xml b/packages/SettingsLib/SearchWidget/res/values-be/strings.xml index 4fc722faba52..c72f8199f12e 100644 --- a/packages/SettingsLib/SearchWidget/res/values-be/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-be/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"Налады пошуку"</string> + <string name="search_menu" msgid="1914043873178389845">"Пошук налад"</string> </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-pa/strings.xml b/packages/SettingsLib/SearchWidget/res/values-pa/strings.xml index 8c7dd6fe3ec6..09a285b7452f 100644 --- a/packages/SettingsLib/SearchWidget/res/values-pa/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-pa/strings.xml @@ -17,5 +17,5 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="search_menu" msgid="1914043873178389845">"ਖੋਜ ਸੈਟਿੰਗਾਂ"</string> + <string name="search_menu" msgid="1914043873178389845">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਖੋਜੋ"</string> </resources> diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index a5bac278e383..90526dbea0ea 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Draadlose ontfouting"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Skakel draadlose ontfouting aan om beskikbare toestelle te sien en te gebruik"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Gebruik QR-kode om toestel saam te bind"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Gebruik QR-kodeskandeerder om nuwe toestelle saam te bind"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Gebruik QR-kodeskandeerder om nuwe toestelle saam te bind"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Gebruik saambindkode om toestel saam te bind"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Gebruik \'n sessyferkode om nuwe toestelle saam te bind"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Saamgebinde toestelle"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Kon nie die toestel saambind nie. Óf die QR-kode is verkeerd, óf die toestel is nie aan dieselfde netwerk gekoppel nie."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adres en -poort"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skandeer QR-kode"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Bind toestel oor Wi-Fi saam deur \'n QR-kode te skandeer"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Bind toestel oor Wi-Fi saam deur \'n QR-kode te skandeer"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Koppel asseblief aan \'n Wi-Fi-netwerk"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Kortpad na foutverslag"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Draadlose skermsertifisering"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktiveer Wi-Fi-woordryke aanmelding"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Regulering van Wi-Fi-opsporing"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi‑verbeterde MAC-verewekansiging"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiele data is altyd aktief"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardewareversnelling vir verbinding"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Wys Bluetooth-toestelle sonder name"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Wys opsies vir draadlose skermsertifisering"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Verhoog Wi-Fi-aantekeningvlak, wys per SSID RSSI in Wi‑Fi-kieser"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verlaag batteryverbruik en verbeter netwerk se werkverrigting"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Hierdie skakelaar beïnvloed MAC-verewekansiginggedrag net vir klantmodus.\nWanneer hierdie modus geaktiveer is, kan enige netwerke waarvoor MAC-verewekansiging geaktiveer is, se MAC-adresse tydens die assosiasie weer verewigkansig word, na gelang van wanneer die klant laas van die netwerk ontkoppel het. Herverewekansiging vind nie plaas as die toestel binne 4 uur of korter herkoppel nie."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Beperk"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Onbeperk"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Loggerbuffer se groottes"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Wys Program Reageer Nie-dialoog vir agtergrondprogramme"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Wys kennisgewingkanaalwaarskuwings"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Wys waarskuwing op skerm wanneer \'n program \'n kennisgewing sonder \'n geldige kanaal plaas"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Dwing kortpaaie vir gesprekkennisgewings af"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kennisgewings moet deur \'n langleef-delingkortpad gerugsteun word om in gesprekafdeling te kan verskyn"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Dwing toelating op eksterne berging"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Maak dat enige program na eksterne berging geskryf kan word, ongeag manifeswaardes"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Dwing aktiwiteite om verstelbaar te wees"</string> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index 126efcc9bbd4..d25ef9bb4149 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"ገመድ-አልባ debugging"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"የሚገኙ መሣሪያዎችን ለመመልከትና ለመጠቀም ገመድ-አልባ debuggingን ያብሩ"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"የQR ኮድን በመጠቀም መሣሪያን ያጣምሩ"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"የQR ኮድ መቃኛን በመጠቀም አዲስ መሣሪያዎችን ያጣምሩ"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"የQR ኮድ መቃኛን በመጠቀም አዲስ መሣሪያዎችን ያጣምሩ"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"የማጣመሪያ ኮድን በመጠቀም መሣሪያን ያጣምሩ"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"የስድስት አኃዝ ኮድ በመጠቀም አዲስ መሣሪያዎችን ያጣምሩ"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"የተጣመሩ መሣሪያዎች"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"መሣሪያውን ማጣመር አልተሳካም። ወይም QR ኮዱ ትክክል አልነበረም፣ ወይም መሣሪያው ከተመሳሳዩ አውታረ መረብ ጋር አልተገናኘም።"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"የአይፒ አድራሻ እና ወደብ"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR ኮድን ይቃኙ"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"የQR ኮድ በመጠቀም መሣሪያን በመቃኘት በWi-Fi ላይ ያጣምሩ"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"የQR ኮድ በመጠቀም መሣሪያን በመቃኘት በWi-Fi ላይ ያጣምሩ"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"እባክዎ ከWi-Fi አውታረ መረብ ጋር ያገናኙ"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb፣ ማረም፣ ግንባታ"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"የሳንካ ሪፖርት አቋራጭ"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"የWi‑Fi ተጨማሪ ቃላት ምዝግብ ማስታወሻ መያዝ"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"የተንቀሳቃሽ ስልክ ውሂብ ሁልጊዜ ገቢር ነው"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"የሃርድዌር ማቀላጠፊያን በማስተሳሰር ላይ"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"የብሉቱዝ መሣሪያዎችን ያለ ስሞች አሳይ"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ አማራጮችን አሳይ"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"የWi‑Fi ምዝግብ ማስታወሻ አያያዝ ደረጃ ጨምር፣ በWi‑Fi መምረጫ ውስጥ በአንድ SSID RSSI አሳይ"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"የባትሪ መላሸቅን ይቀንሳል እንዲሁም የአውታረ መረብ አፈጻጸም ብቃትን ያሻሽላል"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"የሚለካ"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"ያልተለካ"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"የምዝግብ ማስታወሻ ያዥ መጠኖች"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"ለጀርባ መተግበሪያዎች የመተግበሪያ ምላሽ አይሰጥም መገናኛን አሳይ"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"የማሳወቂያ ሰርጥ ማስጠንቀቂያዎችን አሳይ"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"አንድ መተግበሪያ የሚሰራ ሰርጥ ሳይኖረው ማሳወቂያ ሲለጥፍ በማያ ገጽ-ላይ ማስጠንቀቂያን ያሳያል"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ለውይይት ማሳወቂያዎች አቋራጮች ተፈጻሚ ያድርጉ"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"በውይይት ክፍል ውስጥ እንዲታይ በረዥም ጊዜ የሚቆይ የማጋራት አቋርጭ እንዲደገፉ ማሳወቂያዎችን ይጠይቁ"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"በውጫዊ ላይ ሃይል ይፈቀዳል"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"የዝርዝር ሰነዶች እሴቶች ግምት ውስጥ ሳያስገባ ማንኛውም መተግበሪያ ወደ ውጫዊ ማከማቻው ለመጻፍ ብቁ ያደርጋል"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"እንቅስቃሴዎች ዳግመኛ እንዲመጣጠኑ አስገድድ"</string> diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml index d65d821e71ab..bb976183776d 100644 --- a/packages/SettingsLib/res/values-ar/arrays.xml +++ b/packages/SettingsLib/res/values-ar/arrays.xml @@ -141,13 +141,13 @@ <item msgid="1241278021345116816">"تحسين جودة الصوت (٩٩٠ كيلوبت في الثانية / ٩٠٩ كيلوبت في الثانية)"</item> <item msgid="3523665555859696539">"جودة متوازنة للصوت والاتصال (660 كيلوبت في الثانية/606 كيلوبت في الثانية)"</item> <item msgid="886408010459747589">"تحسين جودة الاتصال (٣٣٠ كيلوبت في الثانية / ٣٠٣ كيلوبت في الثانية)"</item> - <item msgid="3808414041654351577">"أفضل جهد (معدل سرعة المعلومات التكيُّفي)"</item> + <item msgid="3808414041654351577">"أفضل جهد (معدل نقل البيانات التكيُّفي)"</item> </string-array> <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries"> <item msgid="804499336721569838">"تحسين جودة الصوت"</item> <item msgid="7451422070435297462">"جودة متوازنة للصوت والاتصال"</item> <item msgid="6173114545795428901">"تحسين جودة الاتصال"</item> - <item msgid="4349908264188040530">"أفضل جهد (معدل سرعة المعلومات التكيُّفي)"</item> + <item msgid="4349908264188040530">"أفضل جهد (معدل نقل البيانات التكيُّفي)"</item> </string-array> <string-array name="bluetooth_audio_active_device_summaries"> <item msgid="8019740759207729126"></item> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index 88d4c0304396..a7c66bd7733b 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"تصحيح أخطاء USB"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"وضع تصحيح الأخطاء عند توصيل USB"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"إلغاء عمليات تفويض تصحيح أخطاء USB"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"تصحيح الأخطاء عبر شبكة Wi-Fi"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"تصحيح الأخطاء اللاسلكي"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"وضع تصحيح الأخطاء عندما يتم الاتصال بشبكة Wi‑Fi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"خطأ"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"تصحيح الأخطاء عبر شبكة Wi-Fi"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"لعرض الأجهزة المتاحة واستخدامها، فعِّل ميزة تصحيح الأخطاء لاسلكيًا."</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"تصحيح الأخطاء اللاسلكي"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"لعرض الأجهزة المتاحة واستخدامها، فعِّل ميزة \"تصحيح الأخطاء اللاسلكي\"."</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"إقران الجهاز باستخدام رمز الاستجابة السريعة"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"إقران الأجهزة الجديدة باستخدام الماسح الضوئي لرموز الاستجابة السريعة"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"إقران الأجهزة الجديدة باستخدام الماسح الضوئي لرموز الاستجابة السريعة"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"إقران الجهاز باستخدام رمز الإقران"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"إقران الأجهزة الجديدة باستخدام رمز مكوّن من 6 أعداد"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"الأجهزة المقترنة"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"تعذّر إقران الجهاز. إما أن رمز الاستجابة السريعة غير صحيح أو أن الجهاز غير متصل بالشبكة نفسها."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"عنوان IP والمنفذ"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"المسح الضوئي لرمز الاستجابة السريعة"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"إقران الجهاز من خلال شبكة Wi‑Fi عن طريق المسح الضوئي لرمز استجابة سريعة"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"إقران الجهاز من خلال شبكة Wi‑Fi عن طريق المسح الضوئي لرمز استجابة سريعة"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"يُرجى الاتصال بشبكة Wi-Fi."</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb، تصحيح الأخطاء، مطور برامج"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"اختصار تقرير الأخطاء"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"شهادة عرض شاشة لاسلكي"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"تفعيل تسجيل Wi‑Fi Verbose"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"تقييد البحث عن شبكات Wi-Fi"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"بيانات الجوّال نشطة دائمًا"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"تسريع الأجهزة للتوصيل"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"عرض أجهزة البلوتوث بدون أسماء"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"عرض خيارات شهادة عرض شاشة لاسلكي"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"زيادة مستوى تسجيل Wi-Fi، وعرض لكل SSID RSSI في منتقي Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"لتقليل استنفاد البطارية وتحسين أداء الشبكة."</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"تفرض تكلفة استخدام"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"بدون قياس"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"أحجام ذاكرة التخزين المؤقت للتسجيل"</string> @@ -300,8 +304,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"استخدام إعداد تسريع الأجهزة للتوصيل إن كان متاحًا"</string> <string name="adb_warning_title" msgid="7708653449506485728">"هل تريد السماح بتصحيح أخطاء USB؟"</string> <string name="adb_warning_message" msgid="8145270656419669221">"تم تصميم تصحيح أخطاء USB لأغراض التطوير فقط. يمكن استخدامه لنسخ البيانات بين الكمبيوتر والجهاز، وتثبيت التطبيقات على جهازك بدون تنبيه، وقراءة بيانات السجل."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"هل تريد السماح بتصحيح الأخطاء عبر شبكة Wi-Fi؟"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"تم تصميم ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\" لأغراض التطوير فقط. يمكن استخدامها لنسخ البيانات بين الكمبيوتر والجهاز وتثبيت التطبيقات على جهازك بدون إرسال إشعار وقراءة بيانات السجلّ."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"هل تريد السماح بتفعيل ميزة \"تصحيح الأخطاء اللاسلكي\"؟"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"تم تصميم ميزة \"تصحيح الأخطاء اللاسلكي\" لأغراض التطوير فقط. ويمكن استخدامها لنسخ البيانات بين الكمبيوتر والجهاز ، وتثبيت التطبيقات على جهازك بدون إرسال إشعار، وقراءة بيانات السجلّ."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"هل تريد إلغاء إمكانية الدخول إلى تصحيح أخطاء USB من جميع أجهزة الكمبيوتر التي تم التصريح لها سابقًا؟"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"هل تريد السماح لإعدادات التطوير؟"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"هذه الإعدادات مخصصة لاستخدام التطوير فقط. قد يتسبب هذا في حدوث أعطال أو خلل في أداء الجهاز والتطبيقات المثبتة عليه."</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"عرض مربع الحوار \"التطبيق لا يستجيب\" مع تطبيقات الخلفية"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"عرض تحذيرات قناة الإشعار"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"عرض تحذير على الشاشة عندما ينشر تطبيق إشعارًا بدون قناة صالحة"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"فرض اختصارات لإشعارات المحادثات"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"يجب دعم الإشعارات باختصار مشاركة قديم لتظهر في قسم المحادثات."</string> <string name="force_allow_on_external" msgid="9187902444231637880">"السماح بإدراج التطبيقات في وحدة تخزين خارجية"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"تأهيل أي تطبيق بحيث تتم كتابته على وحدة تخزين خارجية، بغض النظر عن قيم البيان"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"فرض إمكانية تغيير حجم الأنشطة"</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index 73a5e7c031d7..9d96384beba0 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -206,13 +206,14 @@ <string name="enable_adb" msgid="8072776357237289039">"ইউএছবি ডিবাগিং"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"ইউএছবি সংযোগ হৈ থকাৰ অৱস্থাত ডিবাগ ম\'ড"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"ইউএছবি ডিবাগিং অনুমতিসমূহ প্ৰত্যাহাৰ কৰক"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"ৱায়াৰলেছ ডিবাগিং"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"ৱায়াৰলেচ ডি\'বাগিং"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"ৱাই-ফাই সংযোজিত হৈ থকা সময়ত ডিবাগ ম’ড"</string> <string name="adb_wireless_error" msgid="721958772149779856">"আসোঁৱাহ"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"ৱায়াৰলেছ ডিবাগিং"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"উপলব্ধ ডিভাইচসমূহ চাবলৈ আৰু ব্যৱহাৰ কৰিবলৈ, ৱায়াৰলেছ ডিবাগিং অন কৰক"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"ৱায়াৰলেচ ডি\'বাগিং"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"উপলব্ধ ডিভাইচসমূহ চাবলৈ আৰু ব্যৱহাৰ কৰিবলৈ, ৱায়াৰলেচ ডি\'বাগিং অন কৰক"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"কিউআৰ ক’ডৰ জৰিয়তে ডিভাইচ পেয়াৰ কৰক"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"কিউআৰ ক’ড স্কেনাৰ ব্যৱহাৰ কৰি নতুন ডিভাইচসমূহ পেয়াৰ কৰক"</string> + <!-- no translation found for adb_pair_method_qrcode_summary (7130694277228970888) --> + <skip /> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"পেয়াৰ কৰা ক’ডৰ জৰিয়তে ডিভাইচ পেয়াৰ কৰক"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ছটা অংকৰ ক’ড ব্যৱহাৰ কৰি নতুন ডিভাইচসমূহ পেয়াৰ কৰক"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"পেয়াৰ কৰি থোৱা ডিভাইচসমূহ"</string> @@ -231,7 +232,8 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"ডিভাইচটো পেয়াৰ কৰিব পৰা নগ’ল। কিউআৰ ক’ডটো ভুল অথবা ডিভাইচটো একেটা নেটৱৰ্কৰ সৈতে সংযোগ কৰা হোৱা নাই।"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"আইপি ঠিকনা & প’ৰ্ট"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"কিউআৰ ক’ড স্কেন কৰক"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"এটা কিউআৰ ক’ড স্কেন কৰি ৱাই-ফাইৰে ডিভাইচ পেয়াৰ কৰক"</string> + <!-- no translation found for adb_wireless_qrcode_pairing_description (6014121407143607851) --> + <skip /> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"অনুগ্ৰহ কৰি এটা ৱাই-ফাই নেটৱর্কলৈ সংযোগ কৰক"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ডিবাগ, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"বাগ ৰিপৰ্টৰ শ্ৱৰ্টকাট"</string> @@ -251,6 +253,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণীকৰণ"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"ৱাই-ফাই ভাৰ্ব\'ছ লগিং সক্ষম কৰক"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"ৱাই-ফাই স্কেনৰ নিয়ন্ত্ৰণ"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"ম’বাইল ডেটা সদা-সক্ৰিয়"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"টেডাৰিং হাৰ্ডৱেৰ ত্বৰণ"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামবিহীন ব্লুটুথ ডিভাইচসমূহ দেখুৱাওক"</string> @@ -283,6 +287,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"বেতাঁৰ ডিছপ্লে’ প্ৰমাণপত্ৰৰ বাবে বিকল্পসমূহ দেখুৱাওক"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ৱাই-ফাই লগিঙৰ মাত্ৰা বঢ়াওক, Wi‑Fi পিকাৰত প্ৰতি SSID RSSI দেখুৱাওক"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"বেটাৰীৰ খৰচ কমায় আৰু নেটৱৰ্কৰ কাৰ্যক্ষমতা বৃদ্ধি কৰে"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"নিৰিখ-নিৰ্দিষ্ট"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"নিৰিখ অনিৰ্দিষ্ট"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"লগাৰৰ বাফাৰৰ আকাৰ"</string> @@ -300,8 +306,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"যদিহে উপলব্ধ হয় তেন্তে টেডাৰিং হাৰ্ডৱেৰ ত্বৰণ ব্যৱহাৰ কৰক"</string> <string name="adb_warning_title" msgid="7708653449506485728">"ইউএছবি ডিবাগিঙৰ অনুমতি দিয়েনে?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"ইউএছবি ডিবাগ কৰা কাৰ্য কেৱল বিকাশৰ উদ্দেশ্যৰেহে কৰা হৈছে৷ আপোনাৰ কম্পিউটাৰ আৰু আপোনাৰ ডিভাইচৰ মাজত ডেটা প্ৰতিলিপি কৰিবলৈ এইটো ব্যৱহাৰ কৰক, কোনো জাননী নিদিয়াকৈয়ে আপোনাৰ ডিভাইচত এপ্সমূহ ইনষ্টল কৰক আৰু লগ ডেটা পঢ়ক৷"</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"ৱায়াৰলেছ ডিবাগিঙৰ অনুমতি দিবনে?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"ৱায়াৰলেছ ডিবাগিং কেৱল বিকাশৰ উদ্দেশ্যেৰে কৰা হয়। আপোনাৰ কম্পিউটাৰ আৰু আপোনাৰ ডিভাইচৰ মাজত ডেটা প্ৰতিলিপি কৰিবলৈ, কোনো জাননী নিদিয়াকৈয়ে আপোনাৰ ডিভাইচত এপ্সমূহ ইনষ্টল কৰিবলৈ আৰু লগ ডেটা পঢ়িবলৈ এইটো ব্যৱহাৰ কৰক।"</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"ৱায়াৰলেচ ডি\'বাগিংৰ অনুমতি দিবনে?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"ৱায়াৰলেচ ডি\'বাগিং কেৱল বিকাশৰ উদ্দেশ্যেৰে কৰা হয়। আপোনাৰ কম্পিউটাৰ আৰু আপোনাৰ ডিভাইচৰ মাজত ডেটা প্ৰতিলিপি কৰিবলৈ, কোনো জাননী নিদিয়াকৈয়ে আপোনাৰ ডিভাইচত এপ্সমূহ ইনষ্টল কৰিবলৈ আৰু লগ ডেটা পঢ়িবলৈ এইটো ব্যৱহাৰ কৰক।"</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"আপুনি আগতে ইউএছবি ডিবাগিঙৰ বাবে প্ৰৱেশৰ অনুমতি দিয়া সকলো কম্পিউটাৰৰ পৰা সেই অনুমতি প্ৰত্যাহাৰ কৰেনে?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"বিকাশৰ কামৰ বাবে থকা ছেটিংবিলাকক অনুমতি দিবনে?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"এই ছেটিংসমূহ বিকাশৰ কামত ব্যৱহাৰ কৰিবলৈ তৈয়াৰ কৰা হৈছে। সেইবিলাকে আপোনাৰ ডিভাইচ আৰু তাত থকা এপ্লিকেশ্বনসমূহক অকামিলা কৰি পেলাব পাৰে আৰু সেইবিলাকৰ কাৰণে এপ্লিকেশ্বনসমূহে অদ্ভুত আচৰণ কৰিব পাৰে।"</string> @@ -371,6 +377,10 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"নেপথ্য এপসমূহৰ বাবে এপে সঁহাৰি দিয়া নাই ডায়ল\'গ প্ৰদৰ্শন কৰক"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"জাননী চ্চেনেলৰ সকীয়নিসমূহ দেখুৱাওক"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"কোনো এপে বৈধ চ্চেনেল নোহোৱাকৈ কোনো জাননী প\'ষ্ট কৰিলে স্ক্ৰীণত সকীয়নি প্ৰদৰ্শন হয়"</string> + <!-- no translation found for enforce_shortcuts_for_conversations (7040735163945040763) --> + <skip /> + <!-- no translation found for enforce_shortcuts_for_conversations_summary (1860168037282467862) --> + <skip /> <string name="force_allow_on_external" msgid="9187902444231637880">"বাহ্যিক সঞ্চয়াগাৰত এপক বলেৰে অনুমতি দিয়ক"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"মেনিফেষ্টৰ মান যিয়েই নহওক, বাহ্যিক সঞ্চয়াগাৰত লিখিবলৈ যিকোনো এপক উপযুক্ত কৰি তোলে"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"বলেৰে কাৰ্যকলাপসমূহৰ আকাৰ সলনি কৰিব পৰা কৰক"</string> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index 4cb4017fcc06..4ec5156023a5 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"USB debaq prosesi"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"USB qoşulu olan zaman debaq rejimi"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB debaq avtorizasiyasını ləğv edin"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Simsiz sazlama"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"WiFi sazlaması"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi qoşulduqda sazlama rejimi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Xəta"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Simsiz sazlama"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Əlçatan cihazları görmək və onlardan istifadə etmək üçün simsiz sazlamanı yandırın"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"WiFi sazlaması"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Əlçatan cihazları görmək və onlardan istifadə etmək üçün WiFi sazlamasını yandırın"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR kodu ilə cihazı cütləşdirin"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR kod Skanerindən istifadə etməklə yeni cihazları cütləşdirin"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR kod skanerindən istifadə etməklə yeni cihazları birləşdirin"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Cütləşdirmə kodu ilə cihazı cütləşdirin"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Altı rəqəmli koddan istifadə etməklə yeni cihazları cütləşdirin"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Cütləşdirilmiş cihazlar"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Cihazı cütləşdirmək alınmadı. Ya QR kodu yanlış idi, ya da cihaz eyni şəbəkəyə qoşulmayıb."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ünvanı və Port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR kodu skanlayın"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR Kodu skanlamaqla cihazı Wi‑Fi vasitəsilə cütləşdirin"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR kodu skanlamaqla cihazı Wi‑Fi vasitəsilə birləşdirin"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Wi-Fi şəbəkəsinə qoşulun"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Baq raportu qısa yolu"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Simsiz displey sertifikatlaşması"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi Çoxsözlü Girişə icazə verin"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi skanlamasının tənzimlənməsi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi ilə qabaqcıl MAC randomizasiyası"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobil data həmişə aktiv"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Birləşmə üçün avadanlıq akselerasiyası"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth cihazlarını adsız göstərin"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Simsiz displey sertifikatlaşması üçün seçimləri göstərir"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi giriş səviyyəsini qaldırın, Wi‑Fi seçəndə hər SSID RSSI üzrə göstərin"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Batareya istifadəsini azaldır & şəbəkə performansını yaxşılaşdırır"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Bu keçid yalnız müştəri rejimi üçün MAC randomizasiyasına təsir edir.\nBu rejim aktivləşdirildikdə müştərinin şəbəkədən sonuncu dəfə ayrıldığı vaxtdan asılı olaraq, əlaqələndirmə zamanı MAC randomizasiyası aktivləşdirilmiş istənilən şəbəkənin MAC ünvanı təkrar randomizasiya olunacaq. Cihaz 4 saat və ya daha qısa zaman sonra təkrar qoşularsa, təkrar randomizasiya baş vermir."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Ödənişli"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Limitsiz"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Logger bufer ölçüləri"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Əlçatan oldarsa, birləşmə üçün avadanlıq akselerasiyasından istifadə edin"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB debaq funksiyasına icazə verilsin?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB sazlanması yalnız inkişaf məqsədlidir. Kompüteriniz və cihazınız arasında datanı kopyalamaq üçün ondan istifadə edin, bildiriş olmadan tətbiqləri cihazınıza quraşdırın və qeydiyyat datasını oxuyun."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Simsiz sazlamaya icazə verilsin?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Simsiz sazlama yalnız inkişaf məqsədlidir. Ondan kompüteriniz və cihazınız arasında datanı kopyalamaq, cihazınızda bildiriş olmadan tətbiqləri quraşdırmaq və qeydiyyat datasını oxumaq üçün istifadə edin."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"WiFi sazlamasına icazə verilsin?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"WiFi sazlaması yalnız inkişaf məqsədlidir. Ondan kompüteriniz və cihazınız arasında datanı kopyalamaq, cihazınızda bildiriş olmadan tətbiqləri quraşdırmaq və qeydiyyat datasını oxumaq üçün istifadə edin."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Əvvəl icazə verdiyiniz kompüterlərdən USB debaq əməliyyatına giriş ləğv olunsun?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"İnkişaf ayarlarına icazə verilsin mi?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Bu parametrlər yalnız inkişafetdirici istifadə üçün nəzərdə tutulub. Onlar cihaz və tətbiqlərinizin sınması və ya pis işləməsinə səbəb ola bilər."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Arxa fon tətbiqləri üçün Tətbiq Cavab Vermir dialoqunu göstərin"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Xəbərdarlıqları göstərin"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Bildiriş paylaşıldıqda xəbərdarlıq göstərir"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Söhbət bildirişləri üçün qısayolları tətbiq edin"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Söhbət bölməsində görünmək üçün bildirişlərin uzunmüddətli paylaşım qısayolu ilə dəstəklənməsini tələb edin"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Tətbiqlərə xaricdən məcburi icazə"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Seçilmiş hər hansı tətbiqi bəyannamə dəyərlərindən aslı olmayaraq xarici yaddaşa yazılabilən edir."</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Ölçü dəyişdirmək üçün məcburi fəaliyyətlər"</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 839b85aca0aa..a93b42297c2e 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Bežično otklanjanje grešaka"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Da biste videli i koristili dostupne uređaje, uključite bežično otklanjanje grešaka"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Uparite uređaj pomoću QR koda"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Uparite nove uređaje pomoću čitača QR koda"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Uparite nove uređaje pomoću čitača QR koda"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Uparite uređaj pomoću koda za uparivanje"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Uparite nove uređaje pomoću šestocifrenog koda"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Upareni uređaji"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Uparivanje uređaja nije uspelo. QR kôd je pogrešan ili uređaj nije povezan sa istom mrežom."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP adresa i port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skeniraj QR kôd"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Uparite uređaj pomoću Wi‑Fi mreže ili tako što ćete skenirati QR kôd"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Uparite uređaj pomoću Wi‑Fi mreže tako što ćete skenirati QR kôd"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Povežite se na Wi-Fi mrežu"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, otklanjanje grešaka, programer"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Prečica za izveštaj o greškama"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Sertifikacija bežičnog ekrana"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogući detaljniju evidenciju za Wi‑Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Usporavanje Wi-Fi skeniranja"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Nasumično MAC razvrstavanje po Wi‑Fi‑ju"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilni podaci su uvek aktivni"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardversko ubrzanje privezivanja"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikaz opcija za sertifikaciju bežičnog ekrana"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećava nivo evidentiranja za Wi‑Fi. Prikaz po SSID RSSI-u u biraču Wi‑Fi mreže"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava učinak mreže"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ovaj prekidač utiče na ponašanje nasumičnog razvrstavanja MAC adresa samo za režim klijenta.\nKada se ovaj režim aktivira, za mreže na kojima je omogućeno nasumično razvrstavanje MAC adresa može da dođe do ponovnog nasumičnog razvrstavanja MAC adresa tokom povezivanja, u zavisnosti od toga kada se klijent pre toga isključio sa mreže. Do ponovnog nasumičnog razvrstavanja ne dolazi ako se uređaj ponovo poveže za 4 sata ili manje."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Sa ograničenjem"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez ograničenja"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Veličine bafera podataka u programu za evidentiranje"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Prikaži dijalog Aplikacija ne reaguje za aplikacije u pozadini"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Prikazuj upozorenja zbog kanala za obaveštenja"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Prikazuje upozorenje na ekranu kada aplikacija postavi obaveštenje bez važećeg kanala"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Primenjuj prečice za obaveštenja o konverzacijama"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Zahteva da obaveštenja imaju i dugoročnu prečicu za deljenje kako bi se pojavljivala u odeljku za konverzacije"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Prinudno dozvoli aplikacije u spoljnoj"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Omogućava upisivanje svih aplikacija u spoljnu memoriju, bez obzira na vrednosti manifesta"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Prinudno omogući promenu veličine aktivnosti"</string> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index cc0d28645856..19c532a91242 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -112,7 +112,7 @@ <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Выкарыстоўваць для перадачы файлаў"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Выкарыстоўваць для ўводу"</string> <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Выкарыстоўваць для слыхавых апаратаў"</string> - <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Падлучыць"</string> + <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Спалучыць"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"СПАЛУЧЫЦЬ"</string> <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Скасаваць"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Спалучэнне дае доступ да вашых кантактаў і гісторыі выклікаў пры падключэнні."</string> @@ -206,19 +206,19 @@ <string name="enable_adb" msgid="8072776357237289039">"Адладка USB"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Рэжым адладкі, калі USB падключаны"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Адклікаць дазвол USB-адладкі"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Бесправадная адладка"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Адладка па Wi-Fi"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Рэжым адладкі з падключанай сеткай Wi‑Fi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Памылка"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Бесправадная адладка"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Каб праглядаць і выкарыстоўваць даступныя прылады, уключыце бесправадную адладку"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Адладка па Wi-Fi"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Каб праглядаць і выкарыстоўваць даступныя прылады, уключыце адладку па Wi-Fi"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Спалучыць прыладу з дапамогай QR-кода"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Спалучаць новыя прылады з дапамогай сканера QR-кода"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Спалучаць новыя прылады з дапамогай сканера QR-кода"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Спалучыць прыладу з дапамогай кода спалучэння"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Спалучаць новыя прылады з дапамогай шасцізначнага кода"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Спалучаныя прылады"</string> <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Цяпер падключана"</string> <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Падрабязныя звесткі пра прыладу"</string> - <string name="adb_device_forget" msgid="193072400783068417">"Ігнараваць"</string> + <string name="adb_device_forget" msgid="193072400783068417">"Забыць"</string> <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Лічбавы адбітак прылады: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string> <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Не ўдалося падключыцца"</string> <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Пераканайцеся, што прылада \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\" падключана да правільнай сеткі"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Не ўдалося спалучыць прыладу. QR-код няправільны, ці прылада падключана не да той самай сеткі."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-адрас і порт"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Сканіраваць QR-код"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Спалучыць прыладу праз Wi‑Fi шляхам сканіравання QR-кода"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Спалучэнне прылады праз Wi‑Fi шляхам сканіравання QR-кода"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Падключыцеся да сеткі Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, адладка, распрацоўшчык"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Ярлык для справаздачы пра памылкі"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Сертыфікацыя бесправаднога экрана"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Уключыць падрабязны журнал Wi‑Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Рэгуляванне пошуку сетак Wi‑Fi"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Мабільная перадача даных заўсёды актыўная"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Апаратнае паскарэнне ў рэжыме мадэма"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Паказваць прылады Bluetooth без назваў"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Паказаць опцыі сертыфікацыі бесправаднога экрана"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Пры выбары сеткі Wi-Fi указваць у журнале RSSI для кожнага SSID"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Зніжае расход зараду акумулятара і павышае прадукцыйнасць мабільных сетак"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"Сетка з улікам трафіка"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Сетка без уліку трафіка"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Памеры буфера журнала"</string> @@ -300,8 +304,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Выкарыстоўваць апаратнае паскарэнне ў рэжыме мадэма пры наяўнасці"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Дазволіць адладку USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"Адладка USB прызначана толькі для мэтаў распрацоўкі. Яна можа выкарыстоўвацца, каб капіяваць дадзеныя паміж кампутарам і прыладай, усталёўваць прыкладанні на прыладзе без папярэдняга апавяшчэння і чытаць дадзеныя дзённiка."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Дазволіць бесправадную адладку?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Бесправадная адладка прызначана толькі для мэт распрацоўкі. Яна можа выкарыстоўвацца, каб капіраваць даныя паміж камп\'ютарам і прыладай, усталёўваць праграмы на прыладзе без апавяшчэння і чытаць даныя журнала."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Дазволіць адладку па Wi-Fi?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Адладка па Wi-Fi прызначана толькі для мэт распрацоўкі. Яна можа выкарыстоўвацца, каб капіраваць даныя паміж камп\'ютарам і прыладай, усталёўваць праграмы на прыладзе без апавяшчэння і чытаць даныя журнала."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Адклікаць доступ да адладкі USB з усіх камп\'ютараў, на якiх вы уваходзiлi ў сiстэму?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Дазволiць налады распрацоўшчыка?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Гэтыя налады прызначаны толькi для распрацоўшыкаў. Яны могуць выклікаць збоi прылад i ўсталяваных на iх прыкладанняў, а таксама перашкаджаць iх працы."</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Паведамляць аб тым, што праграма не адказвае"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Паказваць папярэджанні канала апавяшчэннаў"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Паказвае папярэджанне на экране, калі праграма публікуе апавяшчэнне без сапраўднага канала"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Выкарыстоўваць ярлыкі для апавяшчэнняў з размоў"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Каб апавяшчэнні паяўляліся ў раздзеле размоў, абавязкова дубліраваць іх з дапамогай ярлыкоў з працяглым паказам"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Прымусова дазволіць праграмы на вонкавым сховішчы"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Робіць любую праграму даступнай для запісу на вонкавае сховішча, незалежна ад значэнняў маніфеста"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Зрабіць вокны дзеянняў даступнымі для змены памеру"</string> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index ef0951c623bf..0e5ae097d47f 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -210,9 +210,9 @@ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Режим за отстраняване на грешки при връзка с Wi-Fi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Грешка"</string> <string name="adb_wireless_settings" msgid="2295017847215680229">"Безжично отстраняване на грешки"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"За да виждате и използвате наличните устройства, включете функцията за отстраняване на грешки през безжична мрежа"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"За да виждате и използвате наличните устройства, включете функцията за безжично отстраняване на грешки"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Сдвояване на устройството чрез QR код"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Сдвояване на новите устройства чрез скенер за QR кодове"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Сдвояване на новите устройства чрез скенер за QR кодове"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Сдвояване на устройството чрез код за сдвояване"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Сдвояване на новите устройства чрез шестцифрен код"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Сдвоени устройства"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Сдвояването на устройството не бе успешно. QR кодът е неправилен или устройството не е свързано със същата мрежа."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP адрес и порт"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Сканиране на QR код"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Сдвояване на устройството през Wi‑Fi чрез сканиране на QR код"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Сдвояване на устройството през Wi‑Fi чрез сканиране на QR код"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Моля, свържете се с Wi-Fi мрежа"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, отстраняване на грешки, програмиране"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Пряк път за сигнал за програмна грешка"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Безжичен дисплей"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"„Многословно“ регистр. на Wi‑Fi: Актив."</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Ограничаване на сканирането за Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Подобр. рандом. на MAC адреса чрез Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Винаги активни мобилни данни"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Хардуерно ускорение за тетъринга"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показване на устройствата с Bluetooth без имена"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показване на опциите за сертифициране на безжичния дисплей"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"По-подробно регистр. на Wi‑Fi – данни за RSSI на SSID в инстр. за избор на Wi‑Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Намалява изразходването на батерията и подобрява ефективността на мрежата"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Този превключвател оказва влияние върху поведението при рандомизиране на MAC адреси само в режим на клиентска програма.\nКогато този режим е активиран, MAC адресът на всяка мрежа, за която функцията за рандомизиране е включена, може да бъде повторно рандомизиран по време на свързването в зависимост от това, кога последно клиентската програма е прекратила връзката си с мрежата. Не възниква повторно рандомизиране, ако устройството отново установи връзка до 4 часа."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"С отчитане"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Без отчитане"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Размери на регистрац. буфери"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Да се използва хардуерно ускорение на тетъринга, ако е налице"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Разрешаване на отстраняването на грешки през USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"Отстраняването на грешки през USB е предназначено само за програмни цели. Използвайте го за копиране на данни между компютъра и устройството си, за инсталиране на приложения на устройството си без известяване и за четене на регистрационни данни."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Да се разреши ли отстраняването на грешки през безжична мрежа?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Отстраняването на грешки през безжична мрежа е предназначено само за програмни цели. Използвайте го за копиране на данни между компютъра и устройството си, за инсталиране на приложения на устройството си без известяване и за четене на регистрационни данни."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Да се разреши ли безжичното отстраняване на грешки?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Безжичното отстраняване на грешки е предназначено само за програмни цели. Използвайте го за копиране на данни между компютъра и устройството си, за инсталиране на приложения на устройството си без известяване и за четене на регистрационни данни."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Да се отмени ли достъпът до отстраняването на грешки през USB от всички по-рано упълномощени от вас компютри?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Да се разрешат ли настройките за програмиране?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Тези настройки са предназначени само за програмиране. Те могат да доведат до прекъсване на работата или неправилно функциониране на устройството ви и приложенията в него."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Показване на диалоговия прозорец за грешки от типа ANR за приложенията на заден план"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Предупрежд. за канала за известия"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Показва се предупреждение, когато приложение публикува известие без валиден канал"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Налагане на преки пътища за извест. за разговори"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"За известията да се създава рез. копие чрез постоянен пряк път за споделяне, за да се показват в секцията с разговори"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Външно хран.: принуд. разрешаване на приложенията"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Всички приложения ще отговарят на условията да бъдат записвани във външното хранилище независимо от стойностите в манифеста"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Възможност за преоразмеряване на активностите"</string> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index 1cd8eeae5ead..a377ff36442d 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -212,7 +212,8 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"ওয়্যারলেস ডিবাগিং"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"কোন কোন ডিভাইস উপলভ্য আছে তা দেখে নিয়ে ব্যবহার করার জন্য, ওয়্যারলেস ডিবাগিং চালু করুন"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR কোড ব্যবহার করে ডিভাইস যোগ করুন"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR কোড স্ক্যানার ব্যবহার করে নতুন ডিভাইস যোগ করুন"</string> + <!-- no translation found for adb_pair_method_qrcode_summary (7130694277228970888) --> + <skip /> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"যোগ করার কোড ব্যবহার করে ডিভাইস যোগ করুন"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ছয় সংখ্যার কোড ব্যবহার করে নতুন ডিভাইস যোগ করুন"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"যোগ করা ডিভাইস"</string> @@ -231,7 +232,8 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"ডিভাইস যোগ করা যায়নি। এটি দুটি কারণে হয়ে থাকে - QR কোডটি সঠিক নয় বা ডিভাইসটি একই নেটওয়ার্কে কানেক্ট করা নেই।"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP অ্যাড্রেস ও পোর্ট"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR কোড স্ক্যান করুন"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR কোড স্ক্যান করে ওয়াই-ফাই ব্যবহার করে ডিভাইস যোগ করুন"</string> + <!-- no translation found for adb_wireless_qrcode_pairing_description (6014121407143607851) --> + <skip /> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"একটি ওয়াই-ফাই নেটওয়ার্কের সাথে কানেক্ট করুন"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ত্রুটি প্রতিবেদনের শর্টকাট"</string> @@ -251,6 +253,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"ওয়্যারলেস ডিসপ্লে সার্টিফিকেশন"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"ওয়াই-ফাই ভারবোস লগিং চালু করুন"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"ওয়াই-ফাই স্ক্যান থ্রোটলিং"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"মোবাইল ডেটা সব সময় সক্রিয় থাক"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"টিথারিং হার্ডওয়্যার অ্যাক্সিলারেশন"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামহীন ব্লুটুথ ডিভাইসগুলি দেখুন"</string> @@ -273,7 +277,7 @@ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"ব্লুটুথ অডিও LDAC কোডেক: প্লেব্যাক গুণমান"</string> <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"ব্লুটুথ অডিও LDAC কোডেক ট্রিগার করুন\nএটি বেছে নেওয়া আছে: প্লেব্যাকের কোয়ালিটি"</string> <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"স্ট্রিমিং: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string> - <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"ব্যক্তিগত ডিএনএস"</string> + <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"প্রাইভেট ডিএনএস"</string> <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"ব্যক্তিগত ডিএনএস মোড বেছে নিন"</string> <string name="private_dns_mode_off" msgid="7065962499349997041">"বন্ধ আছে"</string> <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"অটোমেটিক"</string> @@ -283,6 +287,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ওয়্যারলেস প্রদর্শন সার্টিফিকেশন জন্য বিকল্পগুলি দেখান"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ওয়াই-ফাই লগিং স্তর বাড়ান, ওয়াই-ফাই চয়নকারীতে SSID RSSI অনুযায়ী দেখান"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ব্যাটারির খরচ কমায় এবং নেটওয়ার্কের পারফর্ম্যান্স উন্নত করে"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"মিটার্ড"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"পরিমাপ করা নয়"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"লগার বাফারের আকারগুলি"</string> @@ -301,7 +307,7 @@ <string name="adb_warning_title" msgid="7708653449506485728">"USB ডিবাগিং মঞ্জুর করবেন?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB ডিবাগিং কেবলমাত্র বিকাশ করার উদ্দেশ্যে। আপনার কম্পিউটার এবং আপনার ডিভাইসের মধ্যে ডেটা অনুলিপি করতে এটি ব্যবহার করুন, বিজ্ঞপ্তি ছাড়া আপনার ডিভাইসে অ্যাপ্লিকেশানগুলি ইনস্টল করুন এবং ডেটা লগ পড়ুন।"</string> <string name="adbwifi_warning_title" msgid="727104571653031865">"ওয়্যারলেস ডিবাগিং-এর অনুমতি দেবেন?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"ওয়্যারলেস ডিবাগিং কেবলমাত্র বিকাশ করার উদ্দেশ্যে। আপনার কম্পিউটার এবং আপনার ডিভাইসের মধ্যে ডেটা কপি করতে এটি ব্যবহার করুন, বিজ্ঞপ্তি ছাড়া আপনার ডিভাইসে অ্যাপ ইনস্টল করুন এবং ডেটা লগ পড়ুন।"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"ওয়্যারলেস ডিবাগিং কেবলমাত্র ডেভেলপ করার উদ্দেশ্যে। আপনার কম্পিউটার এবং আপনার ডিভাইসের মধ্যে ডেটা কপি করতে এটি ব্যবহার করুন, বিজ্ঞপ্তি ছাড়া আপনার ডিভাইসে অ্যাপ ইনস্টল করুন এবং ডেটা লগ পড়ুন।"</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"আপনি আগে যে সব কম্পিউটার USB ডিবাগিং এর অ্যাক্সেসের অনুমতি দিয়েছিলেন তা প্রত্যাহার করবেন?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"উন্নতি সেটিংসের অনুমতি দেবেন?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"এইসব সেটিংস কেবলমাত্র উন্নত করার উদ্দেশ্য। সেগুলি কারণে আপনার ডিভাইস ভেঙ্গে এবং অ্যাপ্লিকেশানগুলি ভালো ভাবে কাজ করা নাও কারতে পারে।"</string> @@ -371,6 +377,10 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"ব্যাকগ্রাউন্ডের অ্যাপগুলির জন্য \'অ্যাপ থেকে সাড়া পাওয়া যাচ্ছে না\' মেসেজ দেখান"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"বিজ্ঞপ্তির সতর্কতা দেখুন"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"অ্যাপ সঠিক চ্যানেল ছাড়া বিজ্ঞপ্তি দেখালে সতর্ক করে"</string> + <!-- no translation found for enforce_shortcuts_for_conversations (7040735163945040763) --> + <skip /> + <!-- no translation found for enforce_shortcuts_for_conversations_summary (1860168037282467862) --> + <skip /> <string name="force_allow_on_external" msgid="9187902444231637880">"বহিরাগততে বলপূর্বক মঞ্জুরি"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"ম্যানিফেস্ট মানগুলি নির্বিশেষে যেকোনো অ্যাপ্লিকেশানকে বাহ্যিক সঞ্চয়স্থানে লেখার উপযুক্ত বানায়"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"আকার পরিবর্তনযোগ্য করার জন্য ক্রিয়াকলাপগুলিকে জোর করুন"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index c72411cc10e6..cdd312c036f3 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -210,9 +210,9 @@ <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Način rada otklanjanja grešaka kada je WiFi mreža povezana"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Greška"</string> <string name="adb_wireless_settings" msgid="2295017847215680229">"Bežično otklanjanje grešaka"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Da vidite i koristite dostupne uređaje, uključite otklanjanje grešaka putem bežične veze"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Da vidite i koristite dostupne uređaje, uključite bežično otklanjanje grešaka"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Uparite uređaj pomoću QR koda"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Uparite nove uređaje pomoću skenera QR koda"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Uparite nove uređaje pomoću skenera QR koda"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Uparite uređaj pomoću koda za uparivanje"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Uparite nove uređaje pomoću šestocifrenog koda"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Upareni uređaji"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Uparivanje uređaja nije uspjelo. QR kȏd nije tačan ili uređaj nije povezan na istu mrežu."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP adresa i priključak"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skenirajte QR kôd"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Uparite uređaj putem WiFi-ja skeniranjem QR koda"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Uparite uređaj putem WiFi-ja skeniranjem QR koda"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Povežite se na WiFi mrežu"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, otklanjanje grešaka, programer"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Prečica za izvještaj o greškama"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certifikacija bežičnog prikaza"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogući detaljni zapisnik za WiFi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Reguliranje skeniranja WiFi mreže"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Nasum. odabir MAC-a poboljšan WiFi-jem"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Prijenos podataka na mobilnoj mreži je uvijek aktivan"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardversko ubrzavanje za povezivanje putem mobitela"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikaz opcija za certifikaciju bežičnog prikaza"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećani nivo zapisnika za WiFi. Prikaz po SSID RSSI-ju u Biraču WiFi-ja"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava performanse mreže"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ovo aktiviranje/deaktiviranje utiče na ponašanje nasumičnog odabira MAC adrese isključivo za način rada klijenta.\nKada je taj način aktiviran, na svakoj mreži na kojoj je omogućen nasumični odabir MAC adrese može doći do ponovnog nasumičnog odabira MAC adrese za vrijeme povezivanja, u zavisnosti od toga kada je posljednji put prekinuta povezanost klijenta s mrežom. Do ponovnog nasumičnog odabira ne dolazi ako se uređaj ponovo poveže u roku od 4 sata ili ranije."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"S naplatom"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Mreža bez naplate"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Veličine međumemorije zapisnika"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Prikaz dijaloga \"Aplikacija ne reagira\" za aplikacije pokrenute u pozadini"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Prikaži upozorenja kanala obavještenja"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Prikaz upozorenja na ekranu kada aplikacija pošalje obavještenje bez važećeg kanala"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Primijeni prečice za obavještenja o razgovorima"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Traži da obavještenja imaju dugotrajnu prečicu za dijeljenje radi prikaza u odjeljku za razgovore"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Nametni aplikacije na vanjskoj pohrani"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Omogućava upisivanje svih aplikacija u vanjsku pohranu, bez obzira na prikazane vrijednosti"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Nametni aktivnostima mijenjanje veličina"</string> @@ -476,7 +480,7 @@ <string name="retail_demo_reset_next" msgid="3688129033843885362">"Naprijed"</string> <string name="retail_demo_reset_title" msgid="1866911701095959800">"Potrebna je lozinka"</string> <string name="active_input_method_subtypes" msgid="4232680535471633046">"Aktivne metode unosa"</string> - <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"Koristite jezik sistema"</string> + <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"Koristi jezik sistema"</string> <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"Otvaranje postavki za <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> nije uspjelo"</string> <string name="ime_security_warning" msgid="6547562217880551450">"Ovaj način unosa može prikupiti sav tekst koji upišete, uključujući lične podatke kao što su lozinke i brojevi kreditnih kartica. Način omogućava aplikacija <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Da li želite koristiti ovaj način unosa?"</string> <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"Napomena: Nakon ponovnog pokretanja, ova aplikacija se neće moći pokrenuti dok ne otključate telefon"</string> @@ -541,7 +545,7 @@ <string name="user_new_user_name" msgid="60979820612818840">"Novi korisnik"</string> <string name="user_new_profile_name" msgid="2405500423304678841">"Novi profil"</string> <string name="user_info_settings_title" msgid="6351390762733279907">"Podaci o korisniku"</string> - <string name="profile_info_settings_title" msgid="105699672534365099">"Podaci o profilu"</string> + <string name="profile_info_settings_title" msgid="105699672534365099">"Informacije o profilu"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Prije nego vam se omogući kreiranje ograničenog profila, morate postaviti zaključavanje ekrana da biste zaštitili svoje aplikacije i lične podatke."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Postaviti zaključavanje"</string> <string name="user_switch_to_user" msgid="6975428297154968543">"Prebaci na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 765d44259ce4..b60e6aa538d4 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -195,7 +195,7 @@ </string-array> <string name="choose_profile" msgid="343803890897657450">"Tria un perfil"</string> <string name="category_personal" msgid="6236798763159385225">"Personal"</string> - <string name="category_work" msgid="4014193632325996115">"Feina"</string> + <string name="category_work" msgid="4014193632325996115">"Treball"</string> <string name="development_settings_title" msgid="140296922921597393">"Opcions per a desenvolupadors"</string> <string name="development_settings_enable" msgid="4285094651288242183">"Activa les opcions per a desenvolupadors"</string> <string name="development_settings_summary" msgid="8718917813868735095">"Defineix les opcions per al desenvolupament d\'aplicacions"</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Depuració sense fil"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Per veure i utilitzar els dispositius disponibles, activa la depuració sense fil"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Vincula el dispositiu amb un codi QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Vincula dispositius nous utilitzant l\'escàner de codis QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Vincula dispositius nous utilitzant l\'escàner de codis QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Vincula el dispositiu amb un codi de vinculació"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Vincula dispositius nous utilitzant un codi de sis dígits"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositius vinculats"</string> @@ -226,12 +226,12 @@ <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Codi de vinculació Wi‑Fi"</string> <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"No s\'ha pogut vincular"</string> <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Assegura\'t que el dispositiu estigui connectat a la mateixa xarxa."</string> - <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Vincula el dispositiu per Wi‑Fi escanejant un codi QR"</string> + <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Escaneja un codi QR per vincular el dispositiu per Wi‑Fi"</string> <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"S\'està vinculant el dispositiu…"</string> <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"No s\'ha pogut vincular el dispositiu. O bé el codi QR és incorrecte, o bé el dispositiu no està connectat a la mateixa xarxa."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adreça IP i port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Escaneja un codi QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Vincula el dispositiu per Wi‑Fi escanejant un codi QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Escaneja un codi QR per vincular el dispositiu per Wi‑Fi"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Connecta\'t a una xarxa Wi‑Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, depurar, desenvolupador"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Drecera per a informe d\'errors"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certificació de pantalla sense fil"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Activa el registre Wi‑Fi detallat"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitació de la cerca de xarxes Wi‑Fi"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Dades mòbils sempre actives"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Acceleració per maquinari per a compartició de xarxa"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra els dispositius Bluetooth sense el nom"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra les opcions per a la certificació de pantalla sense fil"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Augmenta nivell de registre Wi‑Fi, mostra\'l per SSID RSSI al selector de Wi‑Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Redueix el consum de bateria i millora el rendiment de la xarxa"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"D\'ús mesurat"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"D\'ús no mesurat"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Mides de la mem. intermèdia del registrador"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Mostra el quadre de diàleg L\'aplicació no respon per a aplicacions en segon pla"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostra avisos del canal de notificacions"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Mostra un avís en pantalla quan una aplicació publica una notificació sense un canal vàlid"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Aplica dreceres per a notificacions de converses"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Requereix que les notificacions tinguin una drecera fixa per aparèixer la secció de converses"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Força permetre aplicacions de manera externa"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Permet que qualsevol aplicació es pugui escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Força l\'ajust de la mida de les activitats"</string> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index ed2db3a730e7..efc5680004bf 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Bezdrátové ladění"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Chcete-li zobrazit a použít dostupná zařízení, zapněte bezdrátové ladění"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Párovat zařízení pomocí QR kódu"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Párovat nová zařízení pomocí skenování QR kódu"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Párovat nová zařízení pomocí skeneru QR kódů"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Párovat zařízení pomocí párovacího kódu"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Párovat nová zařízení pomocí šestimístného kódu"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Spárovaná zařízení"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Spárování zařízení se nezdařilo. Buď byl QR kód chybný, nebo zařízení není připojeno ke stejné síti."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP adresa a port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Naskenování QR kódu"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Párovat zařízení přes Wi-Fi naskenováním QR kódu"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Párovat zařízení přes Wi-Fi naskenováním QR kódu"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Připojte se k síti Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ladění, vývoj"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Zástupce hlášení chyb"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certifikace bezdrát. displeje"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Podrobné protokolování Wi‑Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Přibrždění vyhledávání Wi‑Fi"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilní data jsou vždy aktivní"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwarová akcelerace tetheringu"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovat zařízení Bluetooth bez názvů"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Zobrazit možnosti certifikace bezdrátového displeje"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zvýšit úroveň protokolování Wi‑Fi zobrazenou v SSID a RSSI při výběru sítě Wi‑Fi."</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Snižuje vyčerpávání baterie a vylepšuje výkon sítě"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"Měřená"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Neměřená"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Vyrovnávací paměť protokol. nástroje"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Zobrazovat dialog „Aplikace neodpovídá“ pro aplikace na pozadí"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Zobrazovat upozornění ohledně kanálu oznámení"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Když aplikace odešle oznámení bez platného kanálu, na obrazovce se zobrazí upozornění"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"U oznámení konverzací vyžadovat zkratky"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"V sekci konverzace zobrazovat pouze oznámení podložená dlouhodobými sdílecími zkratkami"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Vynutit povolení aplikací na externím úložišti"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Každou aplikaci bude možné zapsat do externího úložiště, bez ohledu na hodnoty manifestu"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Vynutit možnost změny velikosti aktivit"</string> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index f682b15deb98..4fee673b8292 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"USB-fejlretning"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Fejlretningstilstand, når USB er tilsluttet"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Tilbagekald tilladelser for USB-fejlretning"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Trådløs fejlfinding"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Trådløs fejlretning"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Fejlfindingstilstand, når der er Wi-Fi-forbindelse"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Fejl"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Trådløs fejlfinding"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Trådløs fejlretning"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Du kan se og bruge tilgængelige enheder ved at aktivere trådløs fejlretning"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Dan par med en enhed ved hjælp af en QR-kode"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Dan par med nye enheder ved hjælp af QR-kodescanneren"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Dan par med nye enheder ved hjælp af QR-kodescanneren"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Dan par med en enhed ved hjælp af en parringskode"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Dan par med nye enheder ved hjælp af den sekscifrede kode"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Parrede enheder"</string> @@ -231,11 +231,11 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Enheden blev ikke parret. Det skyldes enten, at QR-koden var forkert, eller at enheden ikke er forbundet til det samme netværk."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adresse og port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scan QR-kode"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Dan par med en enhed via Wi-Fi ved at scanne en QR-kode"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Dan par med en enhed via Wi-Fi ved at scanne en QR-kode"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Opret forbindelse til et Wi-Fi-netværk"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, fejlfinding, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Genvej til fejlrapportering"</string> - <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Vis en knap til oprettelse af fejlrapporter i afbrydermenuen"</string> + <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Vis en knap til oprettelse af fejlrapporter i menuen for afbryderknappen"</string> <string name="keep_screen_on" msgid="1187161672348797558">"Lås ikke"</string> <string name="keep_screen_on_summary" msgid="1510731514101925829">"Skærmen går ikke i dvale under opladning"</string> <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Aktivér Bluetooth HCI spionlog"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certificering af trådløs skærm"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktivér detaljeret Wi-Fi-logføring"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Begrænsning af Wi-Fi-scanning"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi‑forbedret MAC-randomisering"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobildata er altid aktiveret"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwareacceleration ved netdeling"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheder uden navne"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vis valgmuligheder for certificering af trådløs skærm"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Øg mængden af Wi‑Fi-logføring. Vis opdelt efter SSID RSSI i Wi‑Fi-vælgeren"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reducerer batteriforbruget og forbedrer netværkets effektivitet"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Denne skift påvirker kun MAC-randomisering for klienttilstand.\nNår denne tilstand er aktiveret, kan netværk, der har Mac-randomisering aktiveret, få deres MAC-adresser randomiseret igen, når der oprettes forbindelse, afhængigt af hvornår klienten sidst afbrød forbindelse til netværket. Randomisering sker ikke igen, hvis enheden forbinder igen inden for højst 4 timer."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Forbrugsafregnet"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Ikke forbrugsafregnet"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Størrelser for Logger-buffer"</string> @@ -300,7 +302,7 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Brug hardwareacceleration ved netdeling, hvis det er muligt"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Vil du tillade USB-fejlretning?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB-fejlretning er kun beregnet til udvikling og kan bruges til at kopiere data mellem din computer og enheden, installere apps på enheden uden notifikation og læse logdata."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Vil du tillade trådløs fejlfinding?"</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Vil du tillade trådløs fejlretning?"</string> <string name="adbwifi_warning_message" msgid="8005936574322702388">"Trådløs fejlretning er kun beregnet til udvikling og kan bruges til at kopiere data mellem din computer og enheden, installere apps på enheden uden notifikation og læse logdata."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Vil du ophæve adgangen til USB-fejlretning for alle computere, du tidligere har godkendt?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Vil du tillade udviklingsindstillinger?"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Vis dialogboksen \"Appen svarer ikke\" for baggrundsapps"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Vis advarsler om notifikationskanal"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Viser en advarsel, når en app sender en notifikation uden en gyldig kanal"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Kræv genveje til samtalenotifikationer"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kræv, at notifikationer bakkes op af en langvarig delingsgenvej, hvis de skal vises i samtalesektionen"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Gennemtving tilladelse til eksternt lager"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Gennemtving, at aktiviteter kan tilpasses"</string> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 7918022e5a37..37ae78618bb8 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"USB-Debugging"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Debugmodus bei Anschluss über USB"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB-Debugging-Autorisierungen aufheben"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Kabelloses Debugging"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Debugging über WLAN"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Debugging-Modus, wenn eine WLAN-Verbindung besteht"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Fehler"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Kabelloses Debugging"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Aktiviere das kabellose Debugging, um verfügbare Geräte zu sehen und zu verwenden"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Debugging über WLAN"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Aktiviere \"Debugging über WLAN\", um verfügbare Geräte zu sehen und zu verwenden"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Gerät über einen QR-Code koppeln"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Neue Geräte über QR-Codescanner koppeln"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Neue Geräte über QR-Codescanner koppeln"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Gerät über einen Kopplungscode koppeln"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Neue Geräte mit sechsstelligem Code koppeln"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Gekoppelte Geräte"</string> @@ -231,11 +231,11 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Das Gerät konnte nicht gekoppelt werden. Der QR-Code war nicht korrekt oder das Gerät ist nicht mit demselben Netzwerk verbunden."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-Adresse & Port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR-Code scannen"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Scanne einen QR-Code, um ein Gerät über WLAN zu koppeln"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Scanne einen QR-Code, um ein Gerät über WLAN zu koppeln"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Bitte stell eine WLAN-Verbindung her"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"ADB, Debug, Dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Verknüpfung zu Fehlerbericht"</string> - <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Im Menü \"Ein/Aus\" wird eine Option zum Erstellen eines Fehlerberichts angezeigt"</string> + <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Im Ein-/Aus-Menü wird eine Option zum Erstellen eines Fehlerberichts angezeigt"</string> <string name="keep_screen_on" msgid="1187161672348797558">"Aktiv lassen"</string> <string name="keep_screen_on_summary" msgid="1510731514101925829">"Display wird beim Laden nie in den Ruhezustand versetzt"</string> <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Bluetooth HCI-Snoop-Protokoll aktivieren"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Zertifizierung für kabellose Übertragung"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Ausführliche WLAN-Protokollierung aktivieren"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Drosselung der WLAN-Suche"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"WLAN-erweiterte MAC-Adressrandomisierung"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile Datennutzung immer aktiviert"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwarebeschleunigung für Tethering"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-Geräte ohne Namen anzeigen"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"WLAN-Protokollierungsebene erhöhen, pro SSID RSSI in WiFi Picker anzeigen"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verringert den Akkuverbrauch und verbessert die Netzwerkleistung"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Hiermit wird das Verhalten der MAC-Adressrandomisierung ausschließlich für den Clientmodus umgeschaltet.\nWenn dieser Modus aktiviert ist, werden bei allen Netzwerken, bei denen die MAC-Randomisierung aktiviert ist, die MAC-Adressen während der Verknüpfung abhängig davon, wann der Client zuletzt vom Netzwerk getrennt wurde, wieder randomisiert. Die erneute Randomisierung findet nicht statt, wenn die Verbindung des Geräts innerhalb von maximal 4 Stunden wieder hergestellt wird."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Kostenpflichtig"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Kostenlos"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Logger-Puffergrößen"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Falls verfügbar, Hardwarebeschleunigung für Tethering verwenden"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB-Debugging zulassen?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB-Debugging ist nur für Entwicklungszwecke vorgesehen. Damit kannst du Daten zwischen deinem Computer und deinem Gerät kopieren, Apps auf deinem Gerät ohne Benachrichtigung installieren und Protokolldaten lesen."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Kabelloses Debugging zulassen?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Das kabellose Debugging ist nur für Entwicklungszwecke vorgesehen. Damit kannst du Daten zwischen deinem Computer und deinem Gerät kopieren, Apps auf deinem Gerät ohne Benachrichtigung installieren und Protokolldaten lesen."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"\"Debugging über WLAN\" zulassen?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"\"Debugging über WLAN\" ist nur für Entwicklungszwecke vorgesehen. Damit kannst du Daten zwischen deinem Computer und deinem Gerät kopieren, Apps auf deinem Gerät ohne Benachrichtigung installieren und Protokolldaten lesen."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Zugriff auf USB-Debugging für alle zuvor autorisierten Computer aufheben?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Entwicklungseinstellungen zulassen?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Diese Einstellungen sind ausschließlich für Entwicklungszwecke gedacht. Sie können dein Gerät und die darauf installierten Apps beschädigen oder zu unerwünschtem Verhalten führen."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Bei Abstürzen von Hintergrund-Apps \"App reagiert nicht\"-Dialog anzeigen"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Benachrichtigungskanal- Warnungen anzeigen"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Bei Benachrichtigungen ohne gültigen Kanal wird eine Warnung angezeigt"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Tastenkombination für Benachrichtigungen zur Unterhaltung erzwingen"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Benachrichtigungen müssen durch eine langlebige Tastenkombination zum Teilen unterstützt werden, um im Bereich der Unterhaltung zu erscheinen"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Sperrung des externen Speichers für alle Apps aufheben"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Jede App kann, ungeachtet der Manifestwerte, in den externen Speicher geschrieben werden"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Aktivitätengröße darf immer angepasst werden"</string> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index b4d7c875bf62..dfc9dd13e982 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"Εντοπισμός σφαλμάτων USB"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Λειτουργία εντοπισμού σφαλμάτων όταν το USB είναι συνδεδεμένο"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Ανάκληση εξ/σεων εντ/σμού σφ/των USB"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Εντοπισμός σφαλμ. ασύρ. σύνδεσης"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Ασύρματος εντοπισμός σφαλμάτων"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Λειτουργία εντοπισμού σφαλμάτων όταν το Wi‑Fi είναι συνδεδεμένο"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Σφάλμα"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Εντοπισμός σφαλμ. ασύρ. σύνδεσης"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Για να δείτε και να χρησιμοποιήσετε τις διαθέσιμες συσκευές, ενεργοποιήστε τον εντοπισμό σφαλμάτων ασύρματης σύνδεσης"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Ασύρματος εντοπισμός σφαλμάτων"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Για να δείτε και να χρησιμοποιήσετε τις διαθέσιμες συσκευές, ενεργοποιήστε τον ασύρματο εντοπισμό σφαλμάτων"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Σύζευξη συσκευής με κωδικό QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Σύζευξη νέων συσκευών με τη χρήση σαρωτή κωδικών QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Σύζευξη νέων συσκευών με τη χρήση σαρωτή κωδικών QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Σύζευξη συσκευής με κωδικό σύζευξης"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Σύζευξη νέων συσκευών με τη χρήση εξαψήφιου κωδικού"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Συσκευές σε σύζευξη"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Η σύζευξη της συσκευής απέτυχε. Ο κωδικός QR ήταν λανθασμένος ή η συσκευή δεν είναι συνδεδεμένη στο ίδιο δίκτυο."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Διεύθυνση IP και θύρα"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Σάρωση κωδικού QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Σύζευξη συσκευής μέσω Wi‑Fi με τη σάρωση ενός κωδικού QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Σύζευξη συσκευής μέσω Wi‑Fi με τη σάρωση ενός κωδικού QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Συνδεθείτε σε ένα δίκτυο Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, εντοπισμός σφαλμάτων, προγραμματιστής"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Συντόμευση αναφοράς σφαλμάτων"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Πιστοποίηση ασύρματης οθόνης"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Ενεργοποίηση λεπτομερ. καταγραφής Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Περιορισμός σάρωσης Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Ρύθμ. τυχαίας σειράς MAC με βελτ. Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Πάντα ενεργά δεδομένα κινητής τηλεφωνίας"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Σύνδεση επιτάχυνσης υλικού"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Εμφάνιση συσκευών Bluetooth χωρίς ονόματα"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Εμφάνιση επιλογών για πιστοποίηση ασύρματης οθόνης"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Αύξηση επιπέδου καταγ. Wi-Fi, εμφάνιση ανά SSID RSSI στο εργαλείο επιλογής Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Περιορίζει την κατανάλωση της μπαταρίας και βελτιώνει την απόδοση του δικτύου"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Αυτός ο διακόπτης επηρεάζει τη συμπεριφορά της ρύθμισης τυχαίας σειράς διευθύνσεων MAC μόνο για τη λειτουργία εφαρμογής πελάτη.\nΌταν αυτή η λειτουργία είναι ενεργοποιημένη, σε όλα τα δίκτυα που είναι ενεργή η ρύθμιση τυχαίας σειράς διευθύνσεων MAC ενδέχεται να αλλάξει ξανά η τυχαία σειρά των διευθύνσεων MAC κατά τη συσχέτιση, ανάλογα με το πότε έγινε η τελευταία αποσύνδεση της εφαρμογής πελάτη από το δίκτυο. Αν η συσκευή επανασυνδεθεί μέσα σε 4 ώρες ή λιγότερες, τότε δεν θα αλλάξει η τυχαία σειρά."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Μέτρηση με βάση τη χρήση"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Χωρίς μέτρηση με βάση τη χρήση"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Μέγεθος προσωρινής μνήμης για τη λειτουργία καταγραφής"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Χρήση της σύνδεσης επιτάχυνσης υλικού εάν υπάρχει"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Να επιτρέπεται ο εντοπισμός σφαλμάτων USB;"</string> <string name="adb_warning_message" msgid="8145270656419669221">"Ο εντοπισμός σφαλμάτων USB προορίζεται μόνο για σκοπούς προγραμματισμού. Χρησιμοποιήστε τον για αντιγραφή δεδομένων μεταξύ του υπολογιστή και της συσκευής σας, για την εγκατάσταση εφαρμογών στη συσκευή σας χωρίς προειδοποίηση και για την ανάγνωση δεδομένων καταγραφής."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Να επιτρέπεται ο εντοπισμός σφαλμάτων ασύρματης σύνδεσης;"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Ο εντοπισμός σφαλμάτων ασύρματης σύνδεσης προορίζεται μόνο για σκοπούς προγραμματισμού. Χρησιμοποιήστε τον για αντιγραφή δεδομένων μεταξύ του υπολογιστή και της συσκευής σας, για την εγκατάσταση εφαρμογών στη συσκευή σας χωρίς ειδοποίηση και για την ανάγνωση δεδομένων καταγραφής."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Να επιτρέπεται ο ασύρματος εντοπισμός σφαλμάτων;"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Ο ασύρματος εντοπισμός σφαλμάτων προορίζεται μόνο για σκοπούς προγραμματισμού. Χρησιμοποιήστε τον για αντιγραφή δεδομένων μεταξύ του υπολογιστή και της συσκευής σας, για την εγκατάσταση εφαρμογών στη συσκευή σας χωρίς ειδοποίηση και για την ανάγνωση δεδομένων καταγραφής."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Ανάκληση πρόσβασης στον εντοπισμό σφαλμάτων USB από όλους τους υπολογιστές για τους οποίους είχατε εξουσιοδότηση στο παρελθόν;"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Να επιτρέπεται η χρήση των ρυθμίσεων ανάπτυξης;"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Αυτές οι ρυθμίσεις προορίζονται για χρήση κατά την ανάπτυξη. Μπορούν να προκαλέσουν προβλήματα στη λειτουργία της συσκευής και των εφαρμογών σας."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Εμφάνιση του παραθύρου \"Η εφαρμογή δεν αποκρίνεται\" για εφαρμογές παρασκηνίου"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Εμφάνιση προειδοπ. καναλιού ειδοπ."</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Εμφανίζει προειδοποίηση όταν μια εφαρμογή δημοσιεύει ειδοποίηση χωρίς έγκυρο κανάλι"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Επιβολή συντομεύσεων για ειδοποιήσεις συνομιλίας"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Να απαιτείται η υποστήριξη των ειδοπ. από μια συντόμευση κοινοποίησης μεγάλης διάρκειας για να εμφανίζονται στην ενότητα συνομιλίας"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Να επιτρέπονται υποχρεωτικά εφαρμογές σε εξωτ.συσ."</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Κάνει κάθε εφαρμογή κατάλληλη για εγγραφή σε εξωτερικό αποθηκευτικό χώρο, ανεξάρτητα από τις τιμές του μανιφέστου"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Αναγκαστική δυνατότητα αλλαγής μεγέθους δραστηριοτήτων"</string> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index 4cc274452b61..a932bceb02a5 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Wireless debugging"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"To see and use available devices, turn on wireless debugging"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Pair device with QR code"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Pair new devices using QR code scanner"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Pair new devices using QR code scanner"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Pair device with pairing code"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Pair new devices using six-digit code"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Paired devices"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Failed to pair the device. Either the QR code was incorrect, or the device is not connected to the same network."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP address & port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scan QR code"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Pair device over Wi‑Fi by scanning a QR code"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Pair device over Wi‑Fi by scanning a QR code"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Please connect to a Wi‑Fi network"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Bug report shortcut"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi‑enhanced MAC randomisation"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string> @@ -274,7 +275,7 @@ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"Trigger Bluetooth Audio LDAC\nCodec Selection: Playback Quality"</string> <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string> <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"Private DNS"</string> - <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Select private DNS mode"</string> + <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Select Private DNS Mode"</string> <string name="private_dns_mode_off" msgid="7065962499349997041">"Off"</string> <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Automatic"</string> <string name="private_dns_mode_provider" msgid="3619040641762557028">"Private DNS provider hostname"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"This toggle affects MAC randomisation behaviour for client mode only.\nWhen this mode is activated, any networks that have MAC randomisation enabled may have their MAC addresses re‑randomised during association, depending on when the client last disconnected from the network. Re‑randomisation does not occur if the device reconnects in four hours or less."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Display App Not Responding dialogue for background apps"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Show notification channel warnings"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Displays on-screen warning when an app posts a notification without a valid channel"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Enforce shortcuts for conversation notifications"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Force allow apps on external"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizeable"</string> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index 4cc274452b61..a932bceb02a5 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Wireless debugging"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"To see and use available devices, turn on wireless debugging"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Pair device with QR code"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Pair new devices using QR code scanner"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Pair new devices using QR code scanner"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Pair device with pairing code"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Pair new devices using six-digit code"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Paired devices"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Failed to pair the device. Either the QR code was incorrect, or the device is not connected to the same network."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP address & port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scan QR code"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Pair device over Wi‑Fi by scanning a QR code"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Pair device over Wi‑Fi by scanning a QR code"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Please connect to a Wi‑Fi network"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Bug report shortcut"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi‑enhanced MAC randomisation"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string> @@ -274,7 +275,7 @@ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"Trigger Bluetooth Audio LDAC\nCodec Selection: Playback Quality"</string> <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string> <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"Private DNS"</string> - <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Select private DNS mode"</string> + <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Select Private DNS Mode"</string> <string name="private_dns_mode_off" msgid="7065962499349997041">"Off"</string> <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Automatic"</string> <string name="private_dns_mode_provider" msgid="3619040641762557028">"Private DNS provider hostname"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"This toggle affects MAC randomisation behaviour for client mode only.\nWhen this mode is activated, any networks that have MAC randomisation enabled may have their MAC addresses re‑randomised during association, depending on when the client last disconnected from the network. Re‑randomisation does not occur if the device reconnects in four hours or less."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Display App Not Responding dialogue for background apps"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Show notification channel warnings"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Displays on-screen warning when an app posts a notification without a valid channel"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Enforce shortcuts for conversation notifications"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Force allow apps on external"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizeable"</string> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index 4cc274452b61..a932bceb02a5 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Wireless debugging"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"To see and use available devices, turn on wireless debugging"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Pair device with QR code"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Pair new devices using QR code scanner"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Pair new devices using QR code scanner"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Pair device with pairing code"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Pair new devices using six-digit code"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Paired devices"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Failed to pair the device. Either the QR code was incorrect, or the device is not connected to the same network."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP address & port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scan QR code"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Pair device over Wi‑Fi by scanning a QR code"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Pair device over Wi‑Fi by scanning a QR code"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Please connect to a Wi‑Fi network"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Bug report shortcut"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi‑enhanced MAC randomisation"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string> @@ -274,7 +275,7 @@ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"Trigger Bluetooth Audio LDAC\nCodec Selection: Playback Quality"</string> <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string> <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"Private DNS"</string> - <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Select private DNS mode"</string> + <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Select Private DNS Mode"</string> <string name="private_dns_mode_off" msgid="7065962499349997041">"Off"</string> <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Automatic"</string> <string name="private_dns_mode_provider" msgid="3619040641762557028">"Private DNS provider hostname"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"This toggle affects MAC randomisation behaviour for client mode only.\nWhen this mode is activated, any networks that have MAC randomisation enabled may have their MAC addresses re‑randomised during association, depending on when the client last disconnected from the network. Re‑randomisation does not occur if the device reconnects in four hours or less."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Display App Not Responding dialogue for background apps"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Show notification channel warnings"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Displays on-screen warning when an app posts a notification without a valid channel"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Enforce shortcuts for conversation notifications"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Force allow apps on external"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizeable"</string> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index 4cc274452b61..a932bceb02a5 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Wireless debugging"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"To see and use available devices, turn on wireless debugging"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Pair device with QR code"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Pair new devices using QR code scanner"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Pair new devices using QR code scanner"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Pair device with pairing code"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Pair new devices using six-digit code"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Paired devices"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Failed to pair the device. Either the QR code was incorrect, or the device is not connected to the same network."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP address & port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scan QR code"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Pair device over Wi‑Fi by scanning a QR code"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Pair device over Wi‑Fi by scanning a QR code"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Please connect to a Wi‑Fi network"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Bug report shortcut"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi verbose logging"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi‑enhanced MAC randomisation"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string> @@ -274,7 +275,7 @@ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"Trigger Bluetooth Audio LDAC\nCodec Selection: Playback Quality"</string> <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"Streaming: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string> <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"Private DNS"</string> - <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Select private DNS mode"</string> + <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Select Private DNS Mode"</string> <string name="private_dns_mode_off" msgid="7065962499349997041">"Off"</string> <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Automatic"</string> <string name="private_dns_mode_provider" msgid="3619040641762557028">"Private DNS provider hostname"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain and improves network performance"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"This toggle affects MAC randomisation behaviour for client mode only.\nWhen this mode is activated, any networks that have MAC randomisation enabled may have their MAC addresses re‑randomised during association, depending on when the client last disconnected from the network. Re‑randomisation does not occur if the device reconnects in four hours or less."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Display App Not Responding dialogue for background apps"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Show notification channel warnings"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Displays on-screen warning when an app posts a notification without a valid channel"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Enforce shortcuts for conversation notifications"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Force allow apps on external"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizeable"</string> diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml index e935a74e64cc..6295fe6dd16c 100644 --- a/packages/SettingsLib/res/values-en-rXC/strings.xml +++ b/packages/SettingsLib/res/values-en-rXC/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Wireless debugging"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"To see and use available devices, turn on wireless debugging"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Pair device with QR code"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Pair new devices using QR code Scanner"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Pair new devices using QR code scanner"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Pair device with pairing code"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Pair new devices using six digit code"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Paired devices"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Failed to pair the device. Either the QR code was incorrect, or the device is not connected to the same network."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP address & Port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scan QR code"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Pair device over Wi‑Fi by scanning a QR Code"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Pair device over Wi‑Fi by scanning a QR code"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Please connect to a Wi‑Fi network"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Bug report shortcut"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Wireless display certification"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Enable Wi‑Fi Verbose Logging"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi scan throttling"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi‑enhanced MAC randomization"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobile data always active"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering hardware acceleration"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Show options for wireless display certification"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduces battery drain & improves network performance"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"This toggle affects MAC randomization behavior for client mode only.\nWhen this mode is activated, any networks that have MAC randomization enabled may have their MAC addresses re‑randomized during association, depending on when the client last disconnected from the network. Re‑randomization does not occur if the device reconnects in 4 hours or less."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Metered"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Unmetered"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Logger buffer sizes"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Display App Not Responding dialog for background apps"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Show notification channel warnings"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Displays on-screen warning when an app posts a notification without a valid channel"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Enforce shortcuts for conversation notifications"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Force allow apps on external"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Makes any app eligible to be written to external storage, regardless of manifest values"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Force activities to be resizable"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 6cb975f799ab..b212eb6a484a 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -23,7 +23,7 @@ <string name="wifi_fail_to_scan" msgid="2333336097603822490">"No se pueden buscar las redes."</string> <string name="wifi_security_none" msgid="7392696451280611452">"Ninguna"</string> <string name="wifi_remembered" msgid="3266709779723179188">"Guardada"</string> - <string name="wifi_disconnected" msgid="7054450256284661757">"Desconectada"</string> + <string name="wifi_disconnected" msgid="7054450256284661757">"Desconectado"</string> <string name="wifi_disabled_generic" msgid="2651916945380294607">"Inhabilitada"</string> <string name="wifi_disabled_network_failure" msgid="2660396183242399585">"Error de configuración IP"</string> <string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"No se estableció conexión debido a la mala calidad de la red"</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Depuración inalámbrica"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para ver y usar los dispositivos disponibles, activa la depuración inalámbrica"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Vincular dispositivo mediante código QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Vincular dispositivos nuevos mediante escáner de código QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Vincular dispositivos nuevos mediante escáner de código QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Vincular dispositivo mediante código de sincroniz."</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Vincular dispositivos nuevos mediante código de seis dígitos"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivos vinculados"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Error al vincular el dispositivo. El código QR era incorrecto o el dispositivo no está conectado a la misma red."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Dirección IP y puerto"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Escanear código QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Escanea un código QR para vincular el dispositivo mediante Wi‑Fi"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Escanea un código QR para vincular el dispositivo mediante Wi‑Fi"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conéctate a una red Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Acceso directo para informes de errores"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certificación de pantalla inalámbrica"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Habilitar registro detallado de Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitación de búsqueda de Wi-Fi"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Datos móviles siempre activados"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleración de hardware de conexión mediante dispositivo móvil"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opciones de certificación de pantalla inalámbrica"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar nivel de registro Wi-Fi; mostrar por SSID RSSI en el selector de Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce el consumo de batería y mejora el rendimiento de la red"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"Con uso medido"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Sin tarifa plana"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Tamaños de búfer de Logger"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Mostrar diálogo cuando las apps en segundo plano no responden"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Alertas de notificaciones"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Advertencia en pantalla cuando una app publica una notificación sin canal válido"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Acc. dir. notif. de conv."</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Notif. requieren acc. dir. permanente de uso comp."</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Forzar permisos en almacenamiento externo"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Cualquier app puede escribirse en un almacenamiento externo, sin importar los valores del manifiesto"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Forzar actividades para que cambien de tamaño"</string> @@ -429,7 +435,7 @@ <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Duración aproximada hasta <xliff:g id="TIME">%1$s</xliff:g> según el uso (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g> según el uso"</string> <string name="power_discharge_by" msgid="4113180890060388350">"Duración aproximada hasta: <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only" msgid="92545648425937000">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only" msgid="92545648425937000">"Debería durar aproximadamente hasta: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Hasta <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Es posible que la batería se agote para las <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"Tiempo restante: menos de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml index a403e3e6519e..6e69c713ffd5 100644 --- a/packages/SettingsLib/res/values-es/arrays.xml +++ b/packages/SettingsLib/res/values-es/arrays.xml @@ -26,7 +26,7 @@ <item msgid="6050951078202663628">"Estableciendo conexión..."</item> <item msgid="8356618438494652335">"Autenticando..."</item> <item msgid="2837871868181677206">"Obteniendo dirección IP…"</item> - <item msgid="4613015005934755724">"Conexión establecida"</item> + <item msgid="4613015005934755724">"Conectado"</item> <item msgid="3763530049995655072">"Suspendida"</item> <item msgid="7852381437933824454">"Desconectando..."</item> <item msgid="5046795712175415059">"Desconectado"</item> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index d77772364f77..413e9fd64ec1 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Depuración inalámbrica"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para ver y utilizar los dispositivos disponibles, activa la depuración inalámbrica"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Vincular dispositivo con código QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Vincula nuevos dispositivos con el escáner de códigos QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Vincula nuevos dispositivos con el escáner de códigos QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Vincular dispositivo con código de sincronización"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Vincula nuevos dispositivos con un código de seis dígitos"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivos vinculados"</string> @@ -230,8 +230,8 @@ <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Vinculando dispositivo…"</string> <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"No se ha podido vincular el dispositivo. El código QR no era correcto o el dispositivo no estaba conectado a la misma red."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Dirección IP y puerto"</string> - <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Escanear código QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Vincula un dispositivo a través de Wi‑Fi con un código QR"</string> + <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Escanea el código QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Vincula un dispositivo a través de Wi‑Fi escaneando un código QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conéctate a una red Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, depuración, desarrollo"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Atajo a informe de errores"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certificación de pantalla inalámbrica"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Habilitar registro de Wi-Fi detallado"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitación de búsqueda de redes Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Aleatorización de MAC mejorada por Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Datos móviles siempre activos"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleración por hardware para conexión compartida"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opciones para la certificación de la pantalla inalámbrica"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar el nivel de registro de Wi-Fi y mostrar por SSID RSSI en el selector Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce el consumo de batería y mejora el rendimiento de las redes"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Este interruptor afecta al comportamiento al aleatorizar direcciones MAC solo en el modo del cliente.\nCuando este modo está actualizado, según hace cuánto el cliente se haya desconectado por última vez de la red, es posible que las redes que tengan habilitada esta aleatorización vean que sus direcciones MAC vuelven a aleatorizarse durante la asociación. No se volverán a aleatorizar si el dispositivo se vuelve a conectar en un plazo de cuatro horas."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Medida"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"No medida"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Tamaños del búfer para registrar"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Mostrar el diálogo de que la aplicación no responde para aplicaciones en segundo plano"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Ver advertencias del canal de notificaciones"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Mostrar una advertencia en pantalla cuando una aplicación publica una notificación sin un canal válido"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Implementar atajos en notific. de conversaciones"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Exigir que las notificaciones tengan un atajo para compartir y que así aparezcan en la sección de conversaciones"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Forzar permitir aplicaciones de forma externa"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Hacer que cualquier aplicación se pueda escribir en un dispositivo de almacenamiento externo independientemente de los valores definidos"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Forzar el ajuste de tamaño de las actividades"</string> @@ -427,9 +431,9 @@ <!-- no translation found for power_remaining_duration_only_short (7438846066602840588) --> <skip /> <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g> según el uso (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Duración aproximada hasta: <xliff:g id="TIME">%1$s</xliff:g> (según el uso)"</string> + <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Debería durar hasta las <xliff:g id="TIME">%1$s</xliff:g> basado en tu uso"</string> <string name="power_discharge_by" msgid="4113180890060388350">"Debería durar aproximadamente hasta <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only" msgid="92545648425937000">"Duración aproximada hasta: <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only" msgid="92545648425937000">"Debería durar hasta las <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Hasta: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Es probable que te quedes sin batería sobre esta hora: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"Tiempo restante: menos de <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> @@ -443,8 +447,8 @@ <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"Es posible que el tablet se apague pronto (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"Es posible que el dispositivo se apague pronto (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string> - <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> hasta que termine de cargarse"</string> - <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> hasta que termine de cargarse)"</string> + <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> hasta cargarse completamente"</string> + <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> hasta cargarse completamente)"</string> <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string> <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rápidamente"</string> @@ -505,7 +509,7 @@ <string name="zen_mode_duration_settings_title" msgid="1553451650289651489">"Duración"</string> <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Preguntar siempre"</string> <string name="zen_mode_forever" msgid="3339224497605461291">"Hasta que se desactive"</string> - <string name="time_unit_just_now" msgid="3006134267292728099">"Justo ahora"</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> <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> @@ -532,7 +536,7 @@ <string name="user_add_user_message_long" msgid="1527434966294733380">"Puedes compartir este dispositivo si creas más usuarios. Cada uno tendrá su propio espacio y podrá personalizarlo con aplicaciones, un fondo de pantalla y mucho más. Los usuarios también pueden ajustar opciones del dispositivo, como la conexión Wi‑Fi, que afectan a todos los usuarios.\n\nCuando añadas un usuario, tendrá que configurar su espacio.\n\nCualquier usuario puede actualizar aplicaciones de todos los usuarios. Es posible que no se transfieran los servicios y opciones de accesibilidad al nuevo usuario."</string> <string name="user_add_user_message_short" msgid="3295959985795716166">"Al añadir un usuario nuevo, este debe configurar su espacio.\n\nCualquier usuario puede actualizar las aplicaciones del resto de usuarios."</string> <string name="user_setup_dialog_title" msgid="8037342066381939995">"¿Configurar usuario ahora?"</string> - <string name="user_setup_dialog_message" msgid="269931619868102841">"Asegúrate de que la persona pueda acceder al dispositivo y configurar su espacio."</string> + <string name="user_setup_dialog_message" msgid="269931619868102841">"Asegúrate de que la persona está disponible en este momento para usar el dispositivo y configurar su espacio."</string> <string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"¿Quieres configurar un perfil ahora?"</string> <string name="user_setup_button_setup_now" msgid="1708269547187760639">"Configurar ahora"</string> <string name="user_setup_button_setup_later" msgid="8712980133555493516">"Ahora no"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index 1fa41596a3ac..73320100c2d6 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Juhtmevaba silumine"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Saadaolevate seadmete nägemiseks ja kasutamiseks lülitage sisse juhtmevaba silumine"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Seadme sidumine QR-koodiga"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Uute seadmete sidumine QR-koodi skanneriga"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Uute seadmete sidumine QR-koodi skanneriga"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Seadme sidumine sidumiskoodiga"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Uute seadmete sidumine kuuekohalise koodiga"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Seotud seadmed"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Seadme sidumine ebaõnnestus. QR-kood oli vale või seade ei ole ühendatud samasse võrku."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-aadress ja port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR-koodi skannimine"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Siduge seade WiFi kaudu, skannides QR-koodi"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Siduge seade WiFi kaudu, skannides QR-koodi"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Looge ühendus WiFi-võrguga"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, silumine, arendus"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Veaaruande otsetee"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Juhtmeta ekraaniühenduse sertifitseerimine"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Luba WiFi sõnaline logimine"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"WiFi-skannimise ahendamine"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"WiFi-põhine MAC-i juhuslikustamine"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Hoia mobiilne andmeside alati aktiivne"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Ühenduse jagamise riistvaraline kiirendus"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Kuva ilma nimedeta Bluetoothi seadmed"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Juhtmeta ekraaniühenduse sertifitseerimisvalikute kuvamine"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Suurenda WiFi logimistaset, kuva WiFi valijas SSID RSSI järgi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Aeglustab aku tühjenemist ja parandab võrgu toimivust"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"See lüliti mõjutab MAC-aadressi juhuslikustamise käitumist ainult kliendirežiimis.\nSelle režiimi aktiveerimisel võidakse seostamise ajal MAC-aadressid uuesti juhuslikustada kõigi võrkude jaoks, millel on MAC-aadressi juhuslikustamine lubatud, olenevalt sellest, millal klient viimati ühenduse võrguga katkestas. Uuesti juhuslikustamist ei toimu juhul, kui seade loob uuesti ühenduse kuni 4 tunni jooksul."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Mahupõhine"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Mittemahupõhine"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Logija puhvri suurused"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Kuva taustarakenduste puhul dialoog Rakendus ei reageeri"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Kuva märguandekanali hoiatused"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Esitab ekraanil hoiatuse, kui rakendus postitab kehtiva kanalita märguande"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Otseteede jõustamine vestluste märguannete jaoks"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Nõutakse märguannete toetamist pikaajalise jagamise otseteega, et selle saaks vestluse jaotises kuvada"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Luba rakendused välises salvestusruumis"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Lubab mis tahes rakendusi kirjutada välisesse salvestusruumi manifesti väärtustest olenemata"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Muuda tegevuste suurused muudetavaks"</string> @@ -416,8 +420,8 @@ <string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"Deuteranomaalia (punane-roheline)"</string> <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> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Värviparandus võimaldab kohandada seadmes kuvatavaid värve"</string> + <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Värvikorrigeerimine"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"Värvikorrigeerimine 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> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 2700162afc03..33987aa39b41 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -126,7 +126,7 @@ <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Irudietarako gailua"</string> <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Entzungailua"</string> <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Idazteko gailua"</string> - <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth gailua"</string> + <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth bidezko gailua"</string> <string name="bluetooth_hearingaid_left_pairing_message" msgid="8561855779703533591">"Ezkerreko audifonoa parekatzen…"</string> <string name="bluetooth_hearingaid_right_pairing_message" msgid="2655347721696331048">"Eskuineko audifonoa parekatzen…"</string> <string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"Ezkerrekoa. Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Hari gabeko arazketa"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Erabilgarri dauden gailuak ikusteko eta erabiltzeko, aktibatu hari gabeko arazketa"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Parekatu gailua QR kodearekin"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Parekatu gailu gehiago QR kodea eskaneatuta"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Parekatu gailu gehiago QR kodea eskaneatuta"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Parekatu gailua parekatze-kodearekin"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Parekatu gailu gehiago sei digituko kodearekin"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Parekatutako gailuak"</string> @@ -231,11 +231,11 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Ezin izan da parekatu gailua. QR kodea ez da zuzena edo gailua ez dago sare berera konektatuta."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP helbidea eta ataka"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Eskaneatu QR kodea"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Parekatu gailua wifi-sare baten bidez QR kode bat eskaneatuta"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Parekatu gailua wifi-sare baten bidez QR kode bat eskaneatuta"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Konektatu wifi-sare batera"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, araztu, gailua"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Akatsen txostenerako lasterbidea"</string> - <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Pizteko menuan, erakutsi akatsen txostena sortzeko botoia"</string> + <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Itzaltzeko menuan, erakutsi akatsen txostena sortzeko botoia"</string> <string name="keep_screen_on" msgid="1187161672348797558">"Mantendu aktibo"</string> <string name="keep_screen_on_summary" msgid="1510731514101925829">"Pantaila ez da ezarriko inoiz inaktibo kargatu bitartean"</string> <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Gaitu Bluetooth HCI miatze-erregistroa"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Hari gabe bistaratzeko ziurtagiria"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Gaitu wifi-sareetan saioa hasteko modu xehatua"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wifi-sareen bilaketaren muga"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Datu-konexioa beti aktibo"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Konexioa partekatzeko hardwarearen azelerazioa"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Erakutsi Bluetooth bidezko gailuak izenik gabe"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Erakutsi hari gabe bistaratzeko ziurtagiriaren aukerak"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Erakutsi datu gehiago wifi-sareetan saioa hastean. Erakutsi sarearen identifikatzailea eta seinalearen indarra wifi-sareen hautatzailean."</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Bateria gutxiago kontsumituko da, eta sarearen errendimendua hobetuko."</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"Sare neurtua"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Neurtu gabeko sarea"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Erregistroen buffer-tamainak"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Erakutsi aplikazioak ez erantzutearen (ANR) leihoa atzeko planoan dabiltzan aplikazioen kasuan"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Erakutsi jakinarazpenen kanalen abisuak"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Bistaratu abisuak aplikazioek baliozko kanalik gabeko jakinarazpenak argitaratzean"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Erabili lasterbideak elkarrizketen jakinarazpenetan"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Eskatu jakinarazpenak partekatze-lasterbide iragankor batean oinarrituta egotea elkarrizketa-atalean agertzeko"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Behartu aplikazioak onartzea kanpoko memorian"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Aplikazioek kanpoko memorian idatz dezakete, ezarritako balioak kontuan izan gabe"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Behartu jardueren tamaina doitu ahal izatea"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 1c32926772f9..1687e54ca071 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"اشکالزدایی بیسیم"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"برای مشاهده و استفاده از دستگاههای در دسترس، اشکالزدایی بیسیم را روشن کنید"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"مرتبط کردن دستگاه با کد QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"دستگاههای جدید را با استفاده از اسکنر کد QR مرتبط کنید"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"دستگاههای جدید را بااستفاده از اسکنر کد QR مرتبط کنید"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"مرتبط کردن دستگاه با کد مرتبطسازی"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"دستگاههای جدید را با استفاده از کد شش رقمی مرتبط کنید"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"دستگاههای مرتبطشده"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"مرتبط کردن دستگاه انجام نشد. یا کد QR اشتباه بوده است، یا دستگاه به همان شبکه متصل نیست."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"نشانی IP و درگاه"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"اسکن کد QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"دستگاه را ازطریق Wi‑Fi و با اسکن کردن کد QR مرتبط کنید"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"دستگاه را ازطریق Wi‑Fi و با اسکن کردن کد QR مرتبط کنید"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"لطفاً به شبکه Wi-Fi متصل شوید"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"ADB (پل اشکالزدایی Android)، اشکالزدایی کردن، برنامهنویس"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"میانبر گزارش مشکل"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"گواهینامه نمایش بیسیم"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"فعال کردن گزارشگیری طولانی Wi‑Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"محدود کردن اسکن کردن Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"تصادفیسازی MAC بهبودیافته برای Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"داده تلفن همراه همیشه فعال باشد"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"شتاب سختافزاری اتصال به اینترنت با تلفن همراه"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"نمایش دستگاههای بلوتوث بدون نام"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"نمایش گزینهها برای گواهینامه نمایش بیسیم"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"افزایش سطح گزارشگیری Wi‑Fi، نمایش به ازای SSID RSSI در انتخابکننده Wi‑Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"تخلیه باتری راکاهش میدهد و عملکرد شبکه را بهبود میبخشد"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"فعال/غیرفعال کردن این تنظیم فقط درحالت کارخواه بر عملکرد تصادفیسازی MAC تأثیر میگذارد.\nوقتی این حالت فعال باشد، ممکن است در شبکههایی که تصادفیسازی MAC فعال است، نشانیهای MAC درطول ارتباط دوباره تصادفیسازی شوند، بسته به اینکه اتصال کارخواه آخرین بار چه زمانی از شبکه قطع شده باشد. اگر دستگاه ظرف ۴ ساعت یا کمتر دوباره متصل شود، تصادفیسازی مجدد انجام نمیشود."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"محدودشده"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"محدودنشده"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"اندازههای حافظه موقت ثبتکننده"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"نمایش گفتگوی \"برنامه پاسخ نمیدهد\" برای برنامههای پسزمینه"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"نمایش هشدارهای کانال اعلان"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"هنگامی که برنامهای بدون وجود کانالی معتبر، اعلانی پست میکند، هشدار روی صفحهای نمایش میدهد"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"اجرای میانبرها برای اعلانهای مکالمه"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"اعلانها باید با میانبر ماندگار همرسانی پشتیبانی شوند تا در بخش مکالمه نشان داده شوند"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"اجازه اجباری به برنامههای دستگاه ذخیره خارجی"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"بدون توجه به مقادیر آشکار، هر برنامهای را برای نوشتن در حافظه خارجی واجد شرایط میکند"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"اجبار فعالیتها به قابل تغییر اندازه بودن"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 765e08edd552..db9872bc71f1 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Langaton virheenkorjaus"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Laita langaton virheenkorjaus päälle, niin voit nähdä saatavilla olevat laitteet ja käyttää niitä"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Muodosta laitepari QR-koodilla"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Muodosta uusia laitepareja QR-koodiskannerilla"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Muodosta uusia laitepareja QR-koodiskannerilla"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Yhdistä laite laiteparikoodilla"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Muodosta uusia laitepareja kuusinumeroisella koodilla"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Laiteparit"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Laiteparin muodostus ei onnistunut. QR-koodi oli virheellinen, tai laitetta ei ole yhdistetty samaan verkkoon."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-osoite & portti"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skannaa QR-koodi"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Muodosta laitepari Wi-Fi-yhteyden kautta skannaamalla QR-koodi"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Muodosta laitepari Wi-Fi-yhteyden kautta skannaamalla QR-koodi"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Yhdistä langattomaan verkkoon"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, virheenkorjaus, kehittäminen"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Virheraportin pikakuvake"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Langattoman näytön sertifiointi"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Käytä Wi-Fin laajennettua lokikirjausta"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi-haun rajoitus"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiilidata aina käytössä"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Laitteistokiihdytyksen yhteyden jakaminen"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Näytä nimettömät Bluetooth-laitteet"</string> @@ -278,11 +280,13 @@ <string name="private_dns_mode_off" msgid="7065962499349997041">"Pois käytöstä"</string> <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Automaattinen"</string> <string name="private_dns_mode_provider" msgid="3619040641762557028">"Yksityisen DNS-tarjoajan isäntänimi"</string> - <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Anna isäntänimi tai DNS-tarjoaja."</string> + <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Anna isäntänimi tai DNS-tarjoaja"</string> <string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"Ei yhteyttä"</string> <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Näytä langattoman näytön sertifiointiin liittyvät asetukset."</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Lisää Wi‑Fin lokikirjaustasoa, näytä SSID RSSI -kohtaisesti Wi‑Fi-valitsimessa."</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Vähentää virrankulutusta ja parantaa verkon toimintaa"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"Maksullinen"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Maksuton"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Lokipuskurien koot"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Näytä taustalla olevien sovellusten Sovellus ei vastaa ‑valintaikkunat."</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Näytä ilmoituskanavan varoitukset"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Näyttää varoituksen, kun sovellus julkaisee ilmoituksen ilman kelvollista kanavaa."</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Pakota pikanäppäimet keskusteluilmoituksissa"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Vaadi ilmoitusten tukemista pitkäaikaisella jakopikanäppäimellä, jotta ne näkyvät keskusteluosiossa"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Salli aina ulkoinen tallennus"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Mahdollistaa sovelluksen tietojen tallentamisen ulkoiseen tallennustilaan luetteloarvoista riippumatta."</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Pakota kaikki toiminnot hyväksymään koon muutos"</string> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index d118e1fcb013..4778cba3adce 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Débogage sans fil"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Pour afficher et utiliser les appareils à proximité, activez le débogage sans fil"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Associer l\'appareil à l\'aide d\'un code QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Associer les nouveaux appareils à l\'aide d\'un lecteur de code QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Associer les nouveaux appareils à l\'aide d\'un lecteur de code QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Associer l\'appareil avec un code d\'association"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Associer les nouveaux appareils à l\'aide d\'un code à six chiffres"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Appareils associés"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Échec de l\'association de l\'appareil Soit le code QR est incorrect, soit l\'appareil n\'est pas connecté au même réseau."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adresse IP et port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Numériser le code QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Associer un appareil par Wi-Fi en numérisant un code QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Associer un appareil par Wi-Fi en numérisant un code QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Veuillez vous connecter à un réseau Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, débogage, concepteur"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Raccourci de rapport de bogue"</string> @@ -243,7 +243,7 @@ <string name="oem_unlock_enable" msgid="5334869171871566731">"Déverrouillage par le fabricant"</string> <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Autoriser le déverrouillage du fichier d\'amorce"</string> <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Permettre le déverrouillage par le fabricant?"</string> - <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"AVERTISSEMENT : Les fonctions de protection de l\'appareil ne fonctionneront pas sur cet appareil lorsque ce paramètre est activé."</string> + <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"AVERTISSEMENT : Les fonctionnalités de protection de l\'appareil ne fonctionneront pas sur cet appareil lorsque ce paramètre est activé."</string> <string name="mock_location_app" msgid="6269380172542248304">"Sélectionner l\'application de localisation factice"</string> <string name="mock_location_app_not_set" msgid="6972032787262831155">"Aucune application de localisation factice définie"</string> <string name="mock_location_app_set" msgid="4706722469342913843">"Application de localisation factice : <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certification de l\'affichage sans fil"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Autoriser enreg. données Wi-Fi détaillées"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limiter la recherche de réseaux Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Sélect. aléatoire adr. MAC optim. par Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Données cellulaires toujours actives"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Accélération matérielle pour le partage de connexion"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification d\'affichage sans fil"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler davantage les données Wi-Fi, afficher par SSID RSSI dans sélect. Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit l\'utilisation de la pile et améliore les performances réseau"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ce commutateur a un impact sur le comportement de sélection aléatoire des adresses MAC pour le mode client uniquement.\nLorsque ce mode est activé, l\'association pourrait forcer la réorganisation de manière aléatoire des adresses MAC pour les réseaux sur lesquels la sélection aléatoire des adresses MAC est activée, en fonction de la dernière fois que le client s\'est déconnecté du réseau. La réorganisation de manière aléatoire des adresses MAC ne se produit pas si l\'appareil se reconnecter d\'ici quatre heures ou moins."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Non mesuré"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des mémoires tampons d\'enregistreur"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Afficher le message « L\'application ne répond plus » pour les applications en arrière-plan"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Affich. avertiss. canal notification"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Afficher avertiss. à l\'écran quand une app présente une notific. sans canal valide"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Appliquer les raccourcis pour les notifications de conversation"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Exiger le soutien des notifications par un raccourci de partage longue durée pour qu\'elles s\'affichent dans la section des conversations"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Forcer l\'autor. d\'applis sur stockage externe"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Rend possible l\'enregistrement de toute application sur un espace de stockage externe, indépendamment des valeurs du fichier manifeste"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Forcer les activités à être redimensionnables"</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index f2dcbbaed91b..1b6ca29f473e 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"Débogage USB"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Mode débogage lorsqu\'un câble USB est connecté"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Annuler autorisations pour débog. USB"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Débogage via Wi-Fi"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Débogage sans fil"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Mode de débogage en connexion Wi-Fi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Erreur"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Débogage via Wi-Fi"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Débogage sans fil"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Pour afficher et utiliser les appareils disponibles, activez le débogage sans fil"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Associer l\'appareil avec un code QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Associer les nouveaux appareils à l\'aide d\'un lecteur de code QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Associer les nouveaux appareils à l\'aide d\'un lecteur de code QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Associer l\'appareil avec un code d\'association"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Associer les nouveaux appareils à l\'aide d\'un code à six chiffres"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Appareils associés"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Échec de l\'association à l\'appareil. Le code QR est incorrect, ou l\'appareil n\'est pas connecté au même réseau."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adresse IP et port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scanner un code QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Associer l\'appareil via le Wi‑Fi à l\'aide d\'un code QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Associer l\'appareil via le Wi‑Fi à l\'aide d\'un code QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Connectez-vous à un réseau Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, débogage, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Raccourci vers rapport de bug"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certification affichage sans fil"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Autoriser l\'enregistrement d\'infos Wi-Fi détaillées"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limiter la recherche Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Chgt aléatoire d\'adresse MAC sur Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Données mobiles toujours actives"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Accélération matérielle pour le partage de connexion"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification de l\'affichage sans fil"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler les infos Wi-Fi, afficher par RSSI de SSID dans l\'outil de sélection Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit la décharge de la batterie et améliore les performances du réseau"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ce paramètre modifie uniquement le changement aléatoire de l\'adresse MAC en mode client.\nSi ce mode est activé, les réseaux pour lesquels le changement aléatoire d\'adresse MAC est activé peuvent faire l\'objet de nouveaux changements aléatoires d\'adresse lors des associations, en fonction du temps écoulé depuis la dernière fois que le client s\'est déconnecté du réseau. Aucun changement aléatoire d\'adresse n\'a lieu si un appareil se connecte à nouveau après un délai inférieur à quatre heures."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Non facturé à l\'usage"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des tampons de l\'enregistreur"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Utiliser l\'accélération matérielle pour le partage de connexion, si disponible"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Autoriser le débogage USB ?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"Le débogage USB est conçu uniquement pour le développement. Utilisez-le pour copier des données entre votre ordinateur et votre appareil, installer des applications sur votre appareil sans notification et lire les données de journal."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Autoriser le débogage via Wi-Fi ?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Le débogage via Wi-Fi est conçu uniquement pour le développement. Utilisez-le pour copier des données entre votre ordinateur et votre appareil, installer des applications sur votre appareil sans notification et lire les données des journaux."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Autoriser le débogage sans fil ?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Le débogage sans fil est conçu uniquement pour le développement. Utilisez-le pour copier des données entre votre ordinateur et votre appareil, installer des applications sur votre appareil sans notification et lire les données des journaux."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Voulez-vous vraiment désactiver l\'accès au débogage USB de tous les ordinateurs précédemment autorisés ?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Activer les paramètres de développement ?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Ces paramètres sont en cours de développement. Ils peuvent endommager votre appareil et les applications qui s\'y trouvent, ou provoquer leur dysfonctionnement."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Afficher la boîte de dialogue \"L\'application ne répond plus\" pour les applications en arrière-plan"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Afficher les avertissements liés aux canaux de notification"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Afficher un avertissement lorsqu\'une application publie une notification sans canal valide"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Utiliser des raccourcis pour les notifications des conversations"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Exiger la sauvegarde des notifications via un raccourci de partage permanent pour qu\'elles s\'affichent dans la section des conversations"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Forcer l\'autorisation d\'applis sur stockage externe"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Autoriser l\'enregistrement de toute application sur un espace de stockage externe, indépendamment des valeurs du fichier manifeste"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Forcer le redimensionnement des activités"</string> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 9ee490f09ae2..bbc4e18754fe 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"Depuración por USB"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Modo de depuración de erros cando o USB está conectado"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Revogar as autorizacións de depuración por USB"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Depuración de erros sen fíos"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Depuración sen fíos"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Modo de depuración de erros ao conectarse a wifi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Produciuse un erro"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Depuración de erros sen fíos"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para ver e usar os dispositivos dispoñibles, activa a depuración de erros sen fíos"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Depuración sen fíos"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para ver e usar os dispositivos dispoñibles, activa a depuración sen fíos"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Vincular o dispositivo cun código QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Vincula dispositivos novos mediante un escáner de códigos QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Vincula dispositivos novos mediante un escáner de códigos QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Vincular o dispositivo co código de sincronización"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Vincula dispositivos novos mediante un código de seis díxitos"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivos vinculados"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Produciuse un erro ao sincronizar o dispositivo. O código QR era incorrecto ou o dispositivo non está conectado á mesma rede."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Enderezo IP e porto"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Escanear o código QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Vincula o dispositivo a través da wifi escaneando un código QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Vincula o dispositivo a través da wifi escaneando un código QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conéctate a unha rede wifi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, depuración, programador"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Atallo do informe de erros"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certificado de visualización sen fíos"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Activar rexistro detallado da wifi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitación da busca de wifi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Selección aleatoria de enderezo MAC"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Datos móbiles sempre activados"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleración de hardware para conexión compartida"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sen nomes"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra opcións para o certificado de visualización sen fíos"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumenta o nivel de rexistro da wifi, móstrao por SSID RSSI no selector de wifi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce o consumo de batería e mellora o rendemento da rede"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Esta opción só lle afecta ao comportamento da selección aleatoria de enderezo MAC do modo de cliente.\nCando este modo está activado, os enderezos MAC das redes que teñan activada a selección automática de enderezo MAC pódense volver seleccionar aleatoriamente durante a asociación. Isto depende de cando se desconectase da rede cada cliente por última vez, xa que a selección aleatoria non se repite se transcorreron 4 horas ou menos desde a última conexión."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Sen tarifa plana"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Con tarifa plana"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Tamaño dos búfers do rexistrador"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Se está dispoñible, úsase a aceleración de hardware para conexión compartida"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Queres permitir a depuración por USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"A depuración de erros USB está deseñada unicamente para fins de programación. Utilízaa para copiar datos entre o ordenador e o dispositivo, instalar aplicacións no dispositivo sen enviar notificacións e ler os datos do rexistro."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Queres permitir a depuración de erros sen fíos?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"A depuración de erros sen fíos está deseñada unicamente para fins de programación. Utilízaa para copiar datos entre o ordenador e o dispositivo, instalar aplicacións no dispositivo sen recibir notificacións e ler os datos do rexistro."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Queres permitir a depuración sen fíos?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"A depuración sen fíos está deseñada unicamente para fins de programación. Utilízaa para copiar datos entre o ordenador e o dispositivo, instalar aplicacións no dispositivo sen recibir notificacións e ler os datos do rexistro."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Queres revogar o acceso á depuración por USB desde todos os ordenadores que autorizaches previamente?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Permitir a configuración de programación?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Esta configuración só está destinada á programación. Esta pode provocar que o dispositivo e as aplicacións fallen ou se comporten incorrectamente."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Indica que unha aplicación en segundo plano non responde"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostrar avisos de notificacións"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Mostra avisos cando unha aplicación publica notificacións sen unha canle válida"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Usar atallos para notificacións de conversas"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Require que as notificacións teñan un atallo de uso compartido permanente para aparecer na sección de conversas"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Forzar permiso de aplicacións de forma externa"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Permite que calquera aplicación compatible se poida escribir nun almacenamento externo, independentemente dos valores do manifesto"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Forzar o axuste do tamaño das actividades"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 2fced2bdb6cf..7210b7b35609 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"વાયરલેસ ડિબગીંગ"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ઉપલબ્ધ ડિવાઇસને જોવા અને તેનો ઉપયોગ કરવા માટે, વાયરલેસ ડિબગીંગ ચાલુ કરો"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR કોડ વડે ડિવાઇસનું જોડાણ બનાવો"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR કોડ સ્કૅનરનો ઉપયોગ કરીને નવા ડિવાઇસનું જોડાણ બનાવો"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR કોડ સ્કૅનરનો ઉપયોગ કરીને નવા ડિવાઇસનું જોડાણ બનાવો"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"જોડાણ કરવાના કોડ વડે ડિવાઇસનું જોડાણ બનાવો"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"છ અંકના કોડનો ઉપયોગ કરીને નવા ડિવાઇસનું જોડાણ બનાવો"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"જોડાણ કરેલા ડિવાઇસ"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"ડિવાઇસનું જોડાણ કરવામાં નિષ્ફળ રહ્યાં. કાં તો QR કોડ ખોટો હતો અથવા ડિવાઇસ સમાન નેટવર્ક સાથે કનેક્ટ કરેલું નથી."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ઍડ્રેસ & પોર્ટ"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR કોડ સ્કૅન કરો"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR કોડને સ્કૅન કરીને વાઇ-ફાઇ પર ડિવાઇસનું જોડાણ બનાવો"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR કોડને સ્કૅન કરીને વાઇ-ફાઇ પર ડિવાઇસનું જોડાણ બનાવો"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"કૃપા કરીને વાઇ-ફાઇ નેટવર્કથી કનેક્ટ કરો"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ડિબગ, ડેવ"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"બગ રિપોર્ટ શોર્ટકટ"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"વાયરલેસ ડિસ્પ્લે પ્રમાણન"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"વાઇ-ફાઇ વર્બોઝ લૉગિંગ ચાલુ કરો"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"વાઇ-ફાઇ સ્કૅનની ક્ષમતા મર્યાદિત કરવી"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"મોબાઇલ ડેટા હંમેશાં સક્રિય"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"ટિથરિંગ માટે હાર્ડવેર ગતિવૃદ્ધિ"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"નામ વિનાના બ્લૂટૂથ ઉપકરણો બતાવો"</string> @@ -276,13 +278,15 @@ <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"ખાનગી DNS"</string> <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"ખાનગી DNS મોડને પસંદ કરો"</string> <string name="private_dns_mode_off" msgid="7065962499349997041">"બંધ"</string> - <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"આપમેળે"</string> + <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"ઑટોમૅટિક"</string> <string name="private_dns_mode_provider" msgid="3619040641762557028">"ખાનગી DNS પ્રદાતા હોસ્ટનું નામ"</string> <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"DNS પ્રદાતાના હોસ્ટનું નામ દાખલ કરો"</string> <string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"કનેક્ટ કરી શકાયું નથી"</string> <string name="wifi_display_certification_summary" msgid="8111151348106907513">"વાયરલેસ ડિસ્પ્લે પ્રમાણપત્ર માટેના વિકલ્પો બતાવો"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"વાઇ-ફાઇ લોગિંગ સ્તર વધારો, વાઇ-ફાઇ પીકરમાં SSID RSSI દીઠ બતાવો"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"બૅટરીનો ચાર્જ ઝડપથી ઓછો થવાનું ટાળે છે અને નેટવર્કની કાર્યક્ષમતામાં સુધારો કરે છે"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"મીટર કરેલ"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"મીટર ન કરેલ"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"લોગર બફર કદ"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"બૅકગ્રાઉન્ડ ઍપ માટે \"ઍપ પ્રતિસાદ આપતી નથી\" સંવાદ બતાવો"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"નોટિફિકેશન ચૅનલની ચેતવણી બતાવો"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ઍપ્લિકેશન માન્ય ચૅનલ વિના નોટિફિકેશન પોસ્ટ કરે તો સ્ક્રીન પર ચેતવણી દેખાય છે"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"વાતચીત સૂચનો માટે શૉર્ટકટ"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"વાતચીત વિભાગમાં દેખાવા એક લાંબું ટકતા શેરિંગ શૉર્ટકટ દ્વારા ટેકો મેળવતા નોટિફિકેશન જરૂરી છે"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"બાહ્ય પર એપ્લિકેશનોને મંજૂરી આપવાની ફરજ પાડો"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"મેનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, કોઈપણ ઍપ્લિકેશનને બાહ્ય સ્ટોરેજ પર લખાવા માટે લાયક બનાવે છે"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"પ્રવૃત્તિઓને ફરીથી કદ યોગ્ય થવા માટે ફરજ પાડો"</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index cb4110017241..f3a6e2594ffe 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"USB डीबग करना"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"डीबग मोड जब USB कनेक्ट किया गया हो"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB डीबग करने की मंज़ूरी रद्द करें"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"वायरलेस डीबग करना"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"वॉयरलेस डीबगिंग"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"डिवाइस के वाई-फ़ाई से कनेक्ट हाेने पर, डीबग मोड चालू करें"</string> <string name="adb_wireless_error" msgid="721958772149779856">"गड़बड़ी"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"वायरलेस डीबग करना"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"उपलब्ध डिवाइस देखने और इस्तेमाल करने के लिए, वायरलेस डीबग करने की सुविधा चालू करें"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"वॉयरलेस डीबगिंग"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"उपलब्ध डिवाइस देखने और इस्तेमाल करने के लिए, वॉयरलेस डीबगिंग की सुविधा चालू करें"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"क्यूआर कोड की मदद से डिवाइस जोड़ें"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"क्यूआर कोड स्कैनर का इस्तेमाल करके, नए डिवाइस जोड़ें"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"क्यूआर कोड स्कैनर का इस्तेमाल करके, नए डिवाइस जोड़ें"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"जोड़ने का कोड इस्तेमाल करके, डिवाइस जोड़ें"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"छह अंकों का कोड इस्तेमाल करके, नए डिवाइस जोड़ें"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"जोड़े गए डिवाइस"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"डिवाइस को जोड़ा नहीं जा सका. शायद, क्यूआर कोड ठीक नहीं था या फिर आपका डिवाइस और दूसरा डिवाइस, दाेनाें एक ही नेटवर्क से नहीं जुड़े हैं."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"आईपी पता और पोर्ट"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"क्यूआर कोड स्कैन करें"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"क्यूआर कोड स्कैन करके, वाई-फ़ाई से डिवाइस को जोड़ें"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"क्यूआर कोड स्कैन करके, वाई-फ़ाई नेटवर्क से डिवाइस जोड़ें"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"कृपया किसी वाई-फ़ाई नेटवर्क से कनेक्ट करें"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"गड़बड़ी की रिपोर्ट का शॉर्टकट"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"वायरलेस डिसप्ले सर्टिफ़िकेशन"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"वाई-फ़ाई वर्बोस लॉगिंग चालू करें"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"वाई-फ़ाई के लिए स्कैन की संख्या कम करें"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"बेहतर वाई-फ़ाई नेटवर्क से जुड़ने पर मैक पता बदलने की सुविधा"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"मोबाइल डेटा हमेशा चालू"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"हार्डवेयर से तेज़ी लाने के लिए टेदर करें"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"बिना नाम वाले ब्लूटूथ डिवाइस दिखाएं"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिसप्ले सर्टिफ़िकेशन के विकल्प दिखाएं"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"वाई-फ़ाई लॉगिंग का स्तर बढ़ाएं, वाई-फ़ाई पिकर में प्रति SSID RSSI दिखाएं"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"बैटरी की खपत कम और नेटवर्क की परफ़ॉर्मेंस बेहतर होती है"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"इस टॉगल से सिर्फ़ क्लाइंट मोड में, वाई-फ़ाई नेटवर्क से जुड़ते समय मैक पते को बदलने की सुविधा पर असर पड़ता है.\nजब इस मोड को चालू किया जाता है, तब ऐसे किसी भी नेटवर्क का मैक पता फिर से बदला जा सकता है जिन पर मैक पते को बदलने की सुविधा चालू होती है. ऐसा तभी होता है, जब वे नेटवर्क जुड़े हों. यह इस पर भी निर्भर करता है कि क्लाइंट ने उसे नेटवर्क से कब डिसकनेक्ट किया था. अगर डिवाइस चार घंटे या उससे कम में, फिर से कनेक्ट होता है, तो मैक पते को दोबारा बदला नहीं जा सकता."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"डेटा इस्तेमाल करने की सीमा तय की गई है"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"डेटा इस्तेमाल करने की सीमा तय नहीं की गई है"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"लॉगर बफ़र आकार"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"हार्डवेयर से तेज़ी लाने के लिए टेदर करने की सुविधा मौजूद होने पर उसका इस्तेमाल करें"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB डीबग करने की अनुमति दें?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB डीबग करने का मकसद केवल डेवेलप करना है. इसका इस्तेमाल आपके कंप्यूटर और आपके डिवाइस के बीच डेटा को कॉपी करने, बिना सूचना के आपके डिवाइस पर ऐप इंस्टॉल करने और लॉग डेटा पढ़ने के लिए करें."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"वायरलेस डीबग करने की अनुमति देना चाहते हैं?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"वायरलेस डीबग करने का मकसद सिर्फ़ डेवलपमेंट करना है. इसका इस्तेमाल, आपके कंप्यूटर और डिवाइस के बीच डेटा कॉपी करने, बिना सूचना के आपके डिवाइस पर ऐप्लिकेशन इंस्टॉल करने, और लॉग डेटा पढ़ने के लिए करें."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"वॉयरलेस डीबगिंग की अनुमति देना चाहते हैं?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"वॉयरलेस डीबगिंग का मकसद सिर्फ़ डेवलपमेंट करना है. इसका इस्तेमाल, आपके कंप्यूटर और डिवाइस के बीच डेटा कॉपी करने, बिना सूचना के आपके डिवाइस पर ऐप्लिकेशन इंस्टॉल करने, और लॉग डेटा पढ़ने के लिए करें."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"उन सभी कंप्यूटरों से USB डीबग करने की पहुंचर रद्द करें, जिन्हें आपने पहले इसकी मंज़ूरी दी थी?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"विकास सेटिंग की अनुमति दें?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"ये सेटिंग केवल विकास संबंधी उपयोग के प्रयोजन से हैं. वे आपके डिवाइस और उस पर स्थित ऐप्लिकेशन को खराब कर सकती हैं या उनके दुर्व्यवहार का कारण हो सकती हैं."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"बैकग्राउंड में चलने वाले ऐप्लिकेशन के लिए, यह ऐप्लिकेशन नहीं चल रहा मैसेज दिखाएं"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"सूचना चैनल चेतावनी दिखाएं"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ऐप्लिकेशन, मान्य चैनल के बिना सूचना पोस्ट करे तो स्क्रीन पर चेतावनी दिखाएं"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"सिर्फ़ वही सूचनाएं दिखाएं जो बातचीत सेक्शन में सही शॉर्टकट के साथ भी लिंक हैं"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"ज़रूरी सूचनाओं के लिए ऐसा शेयरिंग शॉर्टकट होना चाहिए जो हमेशा (long-lived) मौजूद रहे, ताकि सूचनाओं को बातचीत वाले सेक्शन में देखा जा सके"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"ऐप्लिकेशन को बाहरी मेमोरी पर ही चलाएं"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"इससे कोई भी ऐप्लिकेशन बाहरी मेमोरी में रखने लायक बन जाता है चाहे उसकी मेनिफ़ेस्ट वैल्यू कुछ भी हो"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"विंडो के हिसाब से गतिविधियों का आकार बदल दें"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index f1608d0d7c6e..5dbbdb2fb687 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Bežično otklanjanje pogrešaka"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Da biste vidjeli dostupne uređaje i mogli se njima koristiti, uključite bežično otklanjanje pogrešaka"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Uparivanje uređaja pomoću QR koda"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Uparivanje novih uređaja pomoću čitača QR koda"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Uparivanje novih uređaja pomoću čitača QR koda"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Uparivanje uređaja pomoću koda za uparivanje"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Uparivanje novih uređaja pomoću šesteroznamenkastog koda"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Upareni uređaji"</string> @@ -230,8 +230,8 @@ <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Uparivanje uređaja…"</string> <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Uparivanje uređaja nije uspjelo. QR kôd je neispravan ili uređaj nije povezan na istu mrežu."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP adresa i priključak"</string> - <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skeniraj QR kôd"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Uparivanje uređaja putem Wi-Fija skeniranjem QR koda"</string> + <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skenirajte QR kôd"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Uparivanje uređaja putem Wi-Fija skeniranjem QR koda"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Povežite se s Wifi mrežom"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, otklanjanje pogrešaka, razvoj"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Prečac izvješća o pogreškama"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certifikacija bežičnog prikaza"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogući opširnu prijavu na Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Usporavanje traženja Wi-Fija"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Nasum. odabir MAC-a poboljšan Wi‑Fi‑jem"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilni podaci uvijek aktivni"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardversko ubrzanje za modemsko povezivanje"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Prikaz opcija za certifikaciju bežičnog prikaza"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povećana razina prijave na Wi‑Fi, prikaz po SSID RSSI-ju u Biraču Wi‑Fi-ja"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Smanjuje potrošnju baterije i poboljšava rad mreže"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ovaj prekidač utječe na ponašanje nasumičnog odabira MAC-a samo za način korisnika.\nKad je aktiviran ovaj način rada, kod bilo koje mreže koja ima omogućen nasumični odabir MAC-a može doći do ponovnog nasumičnog odabira MAC adrese tijekom povezivanja, ovisno o tome kad se klijent posljednji put odspojio s mreže. Nema ponovnog nasumičnog odabira ako se uređaj ponovno spoji za manje od 4 sata."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"S ograničenim prometom"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez ograničenja prometa"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Veličine međuspremnika zapisnika"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Dijalog o pozadinskim aplikacijama koje ne reagiraju"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Prikaži upozorenja kanala obavijesti"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Prikazuje upozorenje na zaslonu kada aplikacija objavi obavijest bez važećeg kanala"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Primjena prečaca za obavijesti razgovora"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Obavijesti moraju imati dugotrajni prečac za dijeljenje da bi se prikazale u odjeljku razgovora"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Prisilno dopusti aplikacije u vanjskoj pohrani"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Aplikacije se mogu zapisivati u vanjsku pohranu neovisno o vrijednostima manifesta"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Nametni mogućnost promjene veličine za aktivnosti"</string> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index bb2f17cecab7..15f008bcb1f7 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Vezeték nélküli hibakeresés"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"A rendelkezésre álló eszközök megtekintéséhez és használatához kapcsolja be a vezeték nélküli hibakeresést"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Eszköz párosítása QR-kóddal"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Párosítsa az új eszközöket QR-kód-szkennelő használatával"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Párosítsa az új eszközöket QR-kód-szkennelő használatával"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Eszköz párosítása párosítókóddal"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Párosítsa az új eszközöket hatjegyű kód használatával"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Párosított eszközök"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Nem sikerült az eszközzel való párosítás. Vagy helytelen volt a QR-kód, vagy az eszköz másik hálózathoz csatlakozott."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-cím és port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR-kód beolvasása"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Párosítsa az eszközt Wi-Fi-n keresztül QR-kód beolvasásával"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Párosítsa az eszközt Wi-Fi-n keresztül QR-kód beolvasásával"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Csatlakozzon Wi-Fi-hálózathoz"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Hibabejelentési gomb"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Vezeték nélküli kijelző tanúsítványa"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Részletes Wi-Fi-naplózás engedélyezése"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi-Fi-hálózat szabályozása"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi‑re kiterjesztett, randomizált MAC"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"A mobilhálózati kapcsolat mindig aktív"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Internetmegosztás hardveres gyorsítása"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Név nélküli Bluetooth-eszközök megjelenítése"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vezeték nélküli kijelző tanúsítványával kapcsolatos lehetőségek megjelenítése"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi-naplózási szint növelése, RSSI/SSID megjelenítése a Wi‑Fi-választóban"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Csökkenti az akkumulátorhasználatot, és javítja a hálózat teljesítményét"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Kizárólag ügyfélmód esetében be- vagy kikapcsolja a MAC-címet randomizáló viselkedést.\nHa a mód aktív, az olyan hálózatokon, amelyeken engedélyezve van a MAC-címek randomizálása, a társítás során újra megtörténhet a randomizálás, attól függően, hogy az ügyfél mikor bontotta utoljára a kapcsolatot a hálózattal. Az ismételt randomizálás nem következik be, ha az eszköz négy órán belül újracsatlakozik."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Forgalomkorlátos"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Nem forgalomkorlátos"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Naplózási puffer mérete"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Az Alkalmazás nem válaszol ablak megjelenítése a háttérben futó alkalmazásoknál"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Értesítő csatorna figyelmeztetései"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Figyelmeztet, ha egy alkalmazás érvényes csatorna nélkül küld értesítést"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Gyorsparancsok kényszerítése beszélgetésértesítésekhez"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Megköveteli, hogy az értesítéseket hosszú életű megosztási gyorsparancs támogassa, hogy megjelenhessenek a beszélgetési szakaszban"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Külső tárhely alkalmazásainak engedélyezése"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Lehetővé teszi bármely alkalmazás külső tárhelyre való írását a jegyzékértékektől függetlenül"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Tevékenységek átméretezésének kényszerítése"</string> @@ -426,10 +430,10 @@ <string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"Körülbelül <xliff:g id="TIME_REMAINING">%1$s</xliff:g> maradt hátra az eszköz használata alapján (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <!-- no translation found for power_remaining_duration_only_short (7438846066602840588) --> <skip /> - <string name="power_discharge_by_enhanced" msgid="563438403581662942">"A használat alapján nagyjából még ennyit bír: <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"A használat alapján nagyjából még ennyit bír: <xliff:g id="TIME">%1$s</xliff:g>"</string> - <string name="power_discharge_by" msgid="4113180890060388350">"Nagyjából még ennyit bír: <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only" msgid="92545648425937000">"Nagyjából még ennyit bír: <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_enhanced" msgid="563438403581662942">"A használat alapján nagyjából eddig bírja: <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"A használat alapján nagyjából eddig bírja: <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by" msgid="4113180890060388350">"Nagyjából eddig bírja: <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_discharge_by_only" msgid="92545648425937000">"Nagyjából eddig bírja: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Eddig: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Az akkumulátor lemerülhet a következő időpontig: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"Kevesebb mint <xliff:g id="THRESHOLD">%1$s</xliff:g> van hátra"</string> @@ -443,7 +447,7 @@ <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"Előfordulhat, hogy a táblagép hamarosan kikapcsol (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"Előfordulhat, hogy az eszköz hamarosan kikapcsol (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string> - <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> van hátra a feltöltésig"</string> + <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> van hátra a feltöltésből"</string> <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a feltöltésig"</string> <string name="battery_info_status_unknown" msgid="268625384868401114">"Ismeretlen"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"Töltés"</string> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index 9cc883a928d5..7774a803e1f7 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Անլար վրիպազերծում"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Հասանելի սարքերը տեսնելու և օգտագործելու համար միացրեք անլար վրիպազերծումը"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Զուգակցեք սարքը՝ օգտագործելով QR կոդը"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Զուգակցեք նոր սարքեր՝ օգտագործելով QR կոդերի սկաները"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Զուգակցեք նոր սարքեր՝ օգտագործելով QR կոդերի սկաները"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Զուգակցեք սարքը՝ օգտագործելով զուգակցման կոդը"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Զուգակցեք նոր սարքեր՝ օգտագործելով վեցանիշ կոդը"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Զուգակցված սարքեր"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Չհաջողվեց զուգակցել սարքի հետ։ Հնարավոր է, որ QR կոդը սխալ է, կամ սարքը միացված չէ միևնույն ցանցին։"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP հասցե և միացք"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR կոդի սկանավորում"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Զուգակցեք սարքը՝ Wi‑Fi-ի օգնությամբ սկանավորելով QR կոդը"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Զուգակցեք սարքը՝ Wi‑Fi-ի օգնությամբ սկանավորելով QR կոդը"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Միացեք Wi-Fi ցանցի"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, վրիպազերծում, ծրագրավորող"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Սխալի հաղորդման դյուրանցում"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Անլար էկրանների հավաստագրում"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Միացնել Wi‑Fi մանրամասն գրանցամատյանները"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi-ի որոնման սահմանափակում"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"MAC հասցեների պատահական ընտրություն Wi-Fi-ին միանալիս"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Բջջային ինտերնետը միշտ ակտիվ է"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Սարքակազմի արագացման միացում"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ցուցադրել Bluetooth սարքերն առանց անունների"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Ցույց տալ անլար էկրանների հավաստագրման ընտրանքները"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Բարձրացնել մակարդակը, Wi‑Fi ընտրիչում ամեն մի SSID-ի համար ցույց տալ RSSI"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Նվազեցնում է մարտկոցի սպառումը և լավացնում ցանցի աշխատանքը"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Այս կարգավորումը միացնում է MAC հասցեների պատահական ընտրությունը միայն սպասառուի ռեժիմում։\nԵրբ այս ռեժիմն ակտիվացված է, բոլոր ցանցերը, որոնց համար միացված է MAC հասցեների պատահական ընտրությունը, կապակցման ժամանակ կարող են նորից պատահական MAC հասցե ընտրել՝ կախված այն բանից, թե երբ է սպասառուն վերջին անգամ անջատվել ցանցից։ Պատահական ընտրության կրկնությունը տեղի չի ունենում, եթե սարքը նորից է միանում ցանցին 4 ժամից պակաս ժամանակահատվածում։"</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Վճարովի թրաֆիկ"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Անսահմանափակ թրաֆիկ"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Մատյանի բուֆերի չափերը"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Ցուցադրել «Հավելվածը չի արձագանքում» պատուհանը ֆոնային հավելվածների համար"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Ցուցադրել ծանուցումների ալիքի զգուշացումները"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Էկրանին ցուցադրվում է զգուշացում, երբ որևէ հավելված փակցնում է ծանուցում առանց վավեր ալիքի"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Միացնել զրույցների ծանուցումների դյուրանցումները"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Պահանջել, որ ծանուցումները պահվեն երկարաժամկետ հասանելիության դյուրանցումով՝ զրույցների բաժնում հայտնվելու համար"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Թույլատրել պահումն արտաքին կրիչներում"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Թույլ է տալիս ցանկացած հավելված պահել արտաքին սարքում՝ մանիֆեստի արժեքներից անկախ"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Չափերի փոփոխում բազմապատուհան ռեժիմում"</string> @@ -503,7 +507,7 @@ <string name="alarm_template" msgid="3346777418136233330">"<xliff:g id="WHEN">%1$s</xliff:g>-ին"</string> <string name="alarm_template_far" msgid="6382760514842998629">"<xliff:g id="WHEN">%1$s</xliff:g>-ին"</string> <string name="zen_mode_duration_settings_title" msgid="1553451650289651489">"Տևողություն"</string> - <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Հարցնել ամեն անգամ"</string> + <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Ամեն անգամ հարցնել"</string> <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> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index d80eba24066f..861e97efeeb3 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -112,8 +112,8 @@ <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Gunakan untuk transfer file"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gunakan untuk masukan"</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">"Sandingkan"</string> - <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SANDINGKAN"</string> + <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Sambungkan"</string> + <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SAMBUNGKAN"</string> <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Batal"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Penyandingan memberi akses ke kontak dan histori panggilan saat tersambung"</string> <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Tidak dapat menyandingkan dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Proses debug nirkabel"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Untuk melihat dan menggunakan perangkat yang tersedia, aktifkan proses debug nirkabel"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Sambungkan perangkat dengan kode QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Sambungkan perangkat baru menggunakan Pemindai kode QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Sambungkan perangkat baru menggunakan pemindai kode QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Sambungkan perangkat dengan kode penghubung"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Sambungkan perangkat baru menggunakan kode enam digit"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Perangkat disambungkan"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Gagal menyambungkan perangkat. Kode QR salah, atau perangkat tidak tersambung ke jaringan yang sama."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Alamat IP & Port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Memindai kode QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Menyambungkan perangkat melalui Wi‑Fi dengan memindai Kode QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Menyambungkan perangkat melalui Wi‑Fi dengan memindai Kode QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Harap sambungkan ke jaringan Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Pintasan laporan bug"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Sertifikasi layar nirkabel"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktifkan Pencatatan Log Panjang Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Pembatasan pemindaian Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Pengacakan MAC yang ditingkatkan Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Kuota selalu aktif"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Akselerasi hardware tethering"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tampilkan perangkat Bluetooth tanpa nama"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Tampilkan opsi untuk sertifikasi layar nirkabel"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tingkatkan level pencatatan log Wi-Fi, tampilkan per SSID RSSI di Pemilih Wi‑Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Memperlambat kehabisan baterai & meningkatkan performa jaringan"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Pengaktifan mode ini memengaruhi perilaku pengacakan MAC hanya untuk mode klien.\nSaat mode ini diaktifkan, jaringan yang mengaktifkan pengacakan MAC mungkin mengalami pengacakan ulang alamat MAC selama terhubung, bergantung pada kapan klien terakhir kali terputus dari jaringan. Pengacakan ulang tidak terjadi jika perangkat terhubung kembali dalam 4 jam atau kurang."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Berbayar"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Tidak berbayar"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Ukuran buffer pencatat log"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Tampilkan dialog Aplikasi Tidak Merespons untuk aplikasi yang berjalan di background"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Tampilkan peringatan saluran notifikasi"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Menampilkan peringatan di layar saat aplikasi memposting notifikasi tanpa channel yang valid"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Terapkan pintasan untuk notifikasi percakapan"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Mengharuskan notifikasi didukung oleh pintasan berbagi yang berdurasi panjang untuk muncul di bagian percakapan"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Paksa izinkan aplikasi di eksternal"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksternal, terlepas dari nilai manifes"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Paksa aktivitas agar ukurannya dapat diubah"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 2e96446f974d..7f7d79c63d3f 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Þráðlaus villuleit"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Til að sjá og nota tiltæk tæki skal kveikja á þráðlausri villuleit"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Para tæki með QR-kóða"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Para ný tæki með QR-kóðaskanna"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Para ný tæki með QR-kóðaskanna"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Para tæki með pörunarkóða"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Para ný tæki með sex tölustafa kóða"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Pöruð tæki"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Ekki tókst að para við tækið. Annað hvort var QR-kóðinn rangur eða tækið ekki tengt sama neti."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-tala og gátt"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skanna QR-kóða"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Tengja tæki með Wi-Fi með því að skanna QR-kóða"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Tengja tæki með Wi-Fi með því að skanna QR-kóða"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Tengstu Wi-Fi neti"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, villuleit, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Flýtileið í villutilkynningu"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Vottun þráðlausra skjáa"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Kveikja á ítarlegri skráningu Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Hægja á Wi‑Fi leit"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Alltaf kveikt á farsímagögnum"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Vélbúnaðarhröðun fyrir tjóðrun"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Sýna Bluetooth-tæki án heita"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Sýna valkosti fyrir vottun þráðlausra skjáa"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Auka skráningarstig Wi-Fi, sýna RSSI fyrir hvert SSID í Wi-Fi vali"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Dregur úr rafhlöðunotkun og eykur netafköst"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"Mæld notkun"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Notkun ekki mæld"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Annálsritastærðir biðminna"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Sýna „Forrit svarar ekki“ fyrir bakgrunnsforrit"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Sýna viðvaranir tilkynningarásar"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Birtir viðvörun á skjánum þegar forrit birtir tilkynningu án gildrar rásar"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Þvinga flýtileiðir fyrir tilkynningar um samtöl"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Krefjast þess að flýtileiðir séu studdar af langvarandi deilingarflýtileið fyrir birtingu í samtalshluta"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Þvinga fram leyfi forrita í ytri geymslu"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Gerir öll forrit skrifanleg í ytra geymslurými, óháð gildum í upplýsingaskrá"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Þvinga breytanlega stærð virkni"</string> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index 2de543d745f1..2945af6def39 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -23,7 +23,7 @@ <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Impossibile cercare reti"</string> <string name="wifi_security_none" msgid="7392696451280611452">"Nessuna"</string> <string name="wifi_remembered" msgid="3266709779723179188">"Salvata"</string> - <string name="wifi_disconnected" msgid="7054450256284661757">"Nessuna connessione"</string> + <string name="wifi_disconnected" msgid="7054450256284661757">"Non connessa"</string> <string name="wifi_disabled_generic" msgid="2651916945380294607">"Disattivata"</string> <string name="wifi_disabled_network_failure" msgid="2660396183242399585">"Errore configurazione IP"</string> <string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"Impossibile connettersi a causa della bassa qualità della rete"</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Debug wireless"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Per trovare e utilizzare i dispositivi disponibili, attiva il debug wireless"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Accoppia il dispositivo con il codice QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Accoppia i nuovi dispositivi utilizzando lo scanner di codici QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Accoppia i nuovi dispositivi utilizzando lo scanner di codici QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Accoppia dispositivo con codice di accoppiamento"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Accoppia i nuovi dispositivi utilizzando un codice di sei cifre"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivi accoppiati"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Impossibile accoppiare il dispositivo. Il codice QR non era corretto oppure il dispositivo non è connesso alla stessa rete."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Indirizzo IP e porta"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scansiona codice QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Accoppia il dispositivo tramite Wi-Fi eseguendo la scansione di un codice QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Accoppia il dispositivo tramite Wi-Fi scansionando un codice QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Collegati a una rete Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"ADB, debug, sviluppatori"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Scorciatoia segnalazione bug"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certificazione display wireless"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Attiva logging dettagliato Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limita ricerca di reti Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Randomizzazione MAC con Wi‑Fi migliorato"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Dati mobili sempre attivi"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering accelerazione hardware"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra dispositivi Bluetooth senza nome"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostra opzioni per la certificazione display wireless"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumenta livello di logging Wi-Fi, mostra SSID RSSI nel selettore Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Riduce il consumo della batteria e migliora le prestazioni della rete"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Questa opzione influenza il comportamento della randomizzazione MAC solo nella modalità client.\nQuando questa modalità è attiva, durante l\'associazione gli indirizzi MAC di tutte le reti con randomizzazione MAC abilitata potrebbero essere nuovamente sottoposti a randomizzazione, a seconda di quando il client è stato disconnesso l\'ultima volta dalla rete. La randomizzazione non viene eseguita nuovamente se il dispositivo si riconnette entro quattro ore o meno."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"A consumo"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Non a consumo"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Dimensioni buffer logger"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Mostra finestra di dialogo ANR per app in background"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostra avvisi canale di notifica"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Viene mostrato un avviso sullo schermo quando un\'app pubblica una notifica senza un canale valido"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Applica scorciatoie per notifiche delle conversazioni"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Richiedi il supporto di una scorciatoia di condivisione di lunga durata per la visualizzazione delle notifiche nella sezione delle conversazioni"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Forza autorizzazione app su memoria esterna"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Consente l\'installazione di qualsiasi app su memoria esterna, indipendentemente dai valori manifest"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Imponi formato modificabile alle attività"</string> @@ -426,10 +430,10 @@ <string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"Tempo rimanente in base al tuo utilizzo (<xliff:g id="LEVEL">%2$s</xliff:g>): <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string> <!-- no translation found for power_remaining_duration_only_short (7438846066602840588) --> <skip /> - <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Tempo stimato rimanente in base al tuo utilizzo: <xliff:g id="TIME">%1$s</xliff:g> circa (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Tempo stimato rimanente in base al tuo utilizzo: <xliff:g id="TIME">%1$s</xliff:g> circa"</string> - <string name="power_discharge_by" msgid="4113180890060388350">"Tempo stimato rimanente: <xliff:g id="TIME">%1$s</xliff:g> circa (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only" msgid="92545648425937000">"Tempo stimato rimanente: <xliff:g id="TIME">%1$s</xliff:g> circa"</string> + <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Ora stimata esaurimento batteria in base al tuo utilizzo: <xliff:g id="TIME">%1$s</xliff:g> circa (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Ora stimata esaurimento batteria in base al tuo utilizzo: <xliff:g id="TIME">%1$s</xliff:g> circa"</string> + <string name="power_discharge_by" msgid="4113180890060388350">"Ora stimata esaurimento batteria: <xliff:g id="TIME">%1$s</xliff:g> circa (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_discharge_by_only" msgid="92545648425937000">"Ora stimata esaurimento batteria: <xliff:g id="TIME">%1$s</xliff:g> circa"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Fino alle ore <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"La batteria potrebbe esaurirsi entro <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"Tempo rimanente: meno di <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index 61f35abbe526..321558406acb 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"ניפוי באגים אלחוטי"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"כדי להציג את המכשירים הזמינים ולהשתמש בהם, יש להפעיל ניפוי באגים אלחוטי"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"התאמת מכשיר באמצעות קוד QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"התאמת מכשירים חדשים באמצעות סורק של קודי QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"התאמת מכשירים חדשים באמצעות סורק של קודי QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"התאמת מכשיר באמצעות קוד התאמה"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"התאמת מכשירים חדשים באמצעות קוד בן שש ספרות"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"מכשירים מותאמים"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"התאמת המכשיר נכשלה. קוד ה-QR היה שגוי או שהמכשיר לא מחובר לאותה רשת."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"יציאה וכתובת IP"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"סריקת קוד QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"יש לסרוק קוד QR כדי להתאים מכשיר באמצעות Wi‑Fi"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"יש לסרוק קוד QR כדי להתאים מכשיר באמצעות Wi‑Fi"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"יש להתחבר לרשת Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ניפוי באגים, פיתוח"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"קיצור של דוח באגים"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"אישור של תצוגת WiFi"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"הפעלת רישום מפורט של Wi‑Fi ביומן"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"ויסות סריקה לנקודות Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"רנדומיזציה משופרת של כתובות MAC ב-Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"חבילת הגלישה פעילה תמיד"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"שיפור מהירות באמצעות חומרה לצורך שיתוף אינטרנט בין ניידים"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"הצגת מכשירי Bluetooth ללא שמות"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"הצג אפשרויות עבור אישור של תצוגת WiFi"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"העלה את רמת הרישום של Wi‑Fi ביומן, הצג לכל SSID RSSI ב-Wi‑Fi Picker"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"מפחית את קצב התרוקנות הסוללה ומשפר את ביצועי הרשת"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"לחצן החלפת המצב משפיע על התנהגות הרנדומיזציה של כתובות MAC במצב לקוח בלבד.\nכשמצב זה מופעל, ברשת שבה מופעלת רנדומיזציה של כתובות MAC, ייתכן שתתבצע רנדומיזציה מחדש של כתובות ה-MAC במהלך השיוך, בהתאם למועד הניתוק האחרון של הלקוח מהרשת. לא תתבצע רנדומיזציה מחדש אם המכשיר מתחבר מחדש תוך ארבע שעות או פחות."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"נמדדת"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"לא נמדדת"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"גדלי מאגר של יומן רישום"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"הצגת תיבת דו-שיח של \'אפליקציה לא מגיבה\' עבור אפליקציות שפועלות ברקע"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"אזהרות לגבי ערוץ התראות"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"הצגת אזהרה כשאפליקציה שולחת התראה ללא ערוץ חוקי"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"אילוץ קיצורי דרך להתראות על שיחות"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"כדי שההודעות יופיעו בקטע השיחות, יש צורך בגיבוי שלהן באמצעות קיצור דרך לשיתוף בעל מחזור חיים ארוך"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"אילוץ הרשאת אפליקציות באחסון חיצוני"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"מאפשר כתיבה של כל אפליקציה באחסון חיצוני, ללא התחשבות בערכי המניפסט"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"אלץ יכולת קביעת גודל של הפעילויות"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index ea9cfd8a7d51..85641939b578 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"ワイヤレス デバッグ"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"利用可能なデバイスを確認して使用するには、ワイヤレス デバッグをオンにしてください"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR コードによるデバイスのペア設定"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR コードスキャナを使って新しいデバイスをペア設定します"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR コードスキャナを使って新しいデバイスをペア設定します"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"ペア設定コードによるデバイスのペア設定"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"6 桁のコードを使って新しいデバイスをペア設定します"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"ペア設定済みのデバイス"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"デバイスをペア設定できませんでした。QR コードが間違っているか、デバイスが同じネットワークに接続されていません。"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP アドレスとポート"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR コードのスキャン"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR コードをスキャンして Wi-Fi 経由でデバイスをペア設定します"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR コードをスキャンして Wi-Fi 経由でデバイスをペア設定します"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Wi-Fi ネットワークに接続してください"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, デバッグ, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"バグレポートのショートカット"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"ワイヤレスディスプレイ認証"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi-Fi詳細ログの有効化"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi スキャン スロットリング"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"モバイルデータを常に ON にする"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"テザリング時のハードウェア アクセラレーション"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth デバイスを名前なしで表示"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ワイヤレスディスプレイ認証のオプションを表示"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fiログレベルを上げて、Wi-Fi選択ツールでSSID RSSIごとに表示します"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"電池の消耗が軽減され、ネットワーク パフォーマンスが改善されます"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"従量制"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"定額制"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"ログバッファのサイズ"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"バックグラウンド アプリが応答しない場合にダイアログを表示"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"通知チャネルの警告を表示"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"アプリから有効なチャネルのない通知が投稿されたときに画面上に警告を表示します"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"会話通知用のショートカット"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"会話セクションに表示されるように、通知が長期の共有ショートカットに対応することを要件とします"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"外部ストレージへのアプリの書き込みを許可"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"マニフェストの値に関係なく、すべてのアプリを外部ストレージに書き込めるようになります"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"アクティビティをサイズ変更可能にする"</string> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index 106bc18f8451..d15b9c4fbe0f 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"შეცდომების უსადენო გამართვა"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ხელმისაწვდომი მოწყობილობების სანახავად და გამოსაყენებლად ჩართეთ შეცდომების უსადენო გამართვა"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"ახალი მოწყობილობების დაწყვილება QR კოდით"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"ახალი მოწყობილობების დაწყვილება QR კოდის სკანერის გამოყენებით"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"ახალი მოწყობილობების დაწყვილება QR კოდის სკანერის გამოყენებით"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"მოწყობილობის დაწყვილება დაკავშირების კოდით"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ახალი მოწყობილობების დაწყვილება ექვსნიშნა კოდის გამოყენებით"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"დაწყვილებული მოწყობილობები"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"მოწყობილობის დაწყვილება ვერ მოხერხდა. QR კოდი არასწორი იყო ან მოწყობილობა იმავე ქსელთან არ არის დაკავშირებული."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP მისამართი და პორტი"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR კოდის სკანირება"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"მოწყობილობის დაწყვილება Wi-Fi-ის მეშვეობით QR კოდის სკანირებით"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"მოწყობილობის დაწყვილება Wi-Fi-ის მეშვეობით QR კოდის სკანირებით"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"დაუკავშირდით Wi-Fi ქსელს"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, შეცდომების გამართვა, დეველოპერული"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ხარვეზის შეტყობინების მალსახმობი"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"უსადენო ეკრანის სერტიფიცირება"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi-ს დაწვრილებითი აღრიცხვის ჩართვა"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi სკანირების რეგულირება"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi‑თ გაძლიერებული MAC მისამართის შემთხვევითობა"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"მობილური ინტერნეტის ყოველთვის გააქტიურება"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"ტეტერინგის აპარატურული აჩქარება"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-მოწყობილობების ჩვენება სახელების გარეშე"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"უსადენო ეკრანის სერტიფიცირების ვარიანტების ჩვენება"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi-ს აღრიცხვის დონის გაზრდა, Wi‑Fi ამომრჩეველში ყოველ SSID RSSI-ზე ჩვენება"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ამცირებს ბატარეის ხარჯვას და აუმჯობესებს ქსელის მუშაობას"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ეს გადასართავი მხოლოდ კლიენტის რეჟიმში მოქმედებს MAC მისამართის შემთხვევითობაზე.\nამ რეჟიმის გააქტიურების შემთხვევაში, ნებისმიერმა ქსელმა, რომლისთვისაც MAC მისამართის შემთხვევითობა ჩართულია, შეიძლება ხელახლა მოახდინოს MAC მისამართთა შემთხვევითობის განხორციელება დაკავშირებისას, იმის გათვალისწინებით, თუ როდის გაწყვიტა კლიენტმა ბოლოს ქსელთან კავშირი. შემთხვევითობა აღარ განმეორდება, თუ ეს მოწყობილობა ქსელს 4 საათის ფარგლებში ან უფრო ნაკლებ დროში დაუკავშირდება."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"ლიმიტირებული"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"არალიმიტირებული"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"ჟურნალიზაციის ბუფერის ზომები"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"„აპი არ რეაგირებს“ შეტყობინების ჩვენება, როცა ფონური აპლიკაცია არ პასუხობს"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"შეტყობინებათა არხის გაფრთხილებების ჩვენება"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ეკრანზე აჩვენებს გაფრთხილებას, როცა აპი შეტყობინებას სწორი არხის გარეშე განათავსებს"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"მალსახმობების მოთხოვნა მიმოწერის შეტყობინებებისთვის"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"მოითხოვეთ, შეტყობინებები ეყრდნობოდეს ხანგრძლივად არსებულ გაზიარების მალსახმობებს მიმოწერის სექციაში გამოსაჩენად"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"აპების დაშვება გარე მეხსიერებაში"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"აპები ჩაიწერება გარე მეხსიერებაზე აღწერის ფაილების მნიშვნელობების მიუხედავად"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"ზომაცვლადი აქტივობების იძულება"</string> diff --git a/packages/SettingsLib/res/values-kk/arrays.xml b/packages/SettingsLib/res/values-kk/arrays.xml index 3c96f43ca548..fe5b5d2f00da 100644 --- a/packages/SettingsLib/res/values-kk/arrays.xml +++ b/packages/SettingsLib/res/values-kk/arrays.xml @@ -26,7 +26,7 @@ <item msgid="6050951078202663628">"Қосылуда..."</item> <item msgid="8356618438494652335">"Растауда…"</item> <item msgid="2837871868181677206">"IP мекенжайына қол жеткізуде…"</item> - <item msgid="4613015005934755724">"Қосылған"</item> + <item msgid="4613015005934755724">"Жалғанған"</item> <item msgid="3763530049995655072">"Уақытша тоқтатылды"</item> <item msgid="7852381437933824454">"Ажыратуда…"</item> <item msgid="5046795712175415059">"Ажыратылған"</item> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 0ef83bb183cb..828f18bce78b 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"USB жөндеу"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"USB жалғанғандағы жөндеу режимі"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB жөндеу рұқсаттарынан бас тарту"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Сымсыз желі арқылы түзету"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Сымсыз түзету"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi желісіне жалғанған кездегі түзету режимі"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Қате"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Сымсыз желі арқылы түзету"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Қолжетімді құрылғыларды көру және пайдалану үшін сымсыз желі арқылы түзетуді іске қосыңыз."</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Сымсыз түзету"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Қолжетімді құрылғыларды көру және пайдалану үшін сымсыз түзетуді іске қосыңыз."</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Құрылғыны QR коды арқылы жұптау"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Жаңа құрылғыларды QR коды сканері арқылы жұптау"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Жаңа құрылғыларды QR коды сканерімен жұптау"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Құрылғыны кодпен жұптау"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Жаңа құрылғыларды алты цифрлық код арқылы жұптау"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Жұпталған құрылғылар"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Құрылғы жұпталмады. QR коды дұрыс емес немесе құрылғы бір желіге жалғанбаған."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP мекенжайы және порт"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR кодын сканерлеу"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR кодын сканерлеп, құрылғыны Wi‑Fi арқылы жұптау"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR кодын сканерлеп, құрылғыны Wi‑Fi арқылы жұптау"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Wi-Fi желісіне қосылыңыз."</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, түзету, әзірлеуші"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Қате туралы хабарлау"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Сымсыз дисплей сертификаты"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi егжей-тегжейлі журналы"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi іздеуін шектеу"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Мобильдік интернет әрқашан қосулы"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Тетеринг режиміндегі аппараттық жеделдету"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth құрылғыларын атаусыз көрсету"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Сымсыз дисплей сертификаты опцияларын көрсету"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi тіркеу деңгейін арттыру, Wi‑Fi таңдағанда әр SSID RSSI бойынша көрсету"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батарея зарядының шығынын азайтады және желі жұмысын жақсартады."</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"Трафик саналады"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Трафик саналмайды"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Журналға тіркеуші буферінің өлшемдері"</string> @@ -300,8 +304,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Тетеринг режиміндегі аппараттық жеделдетуді пайдалану (қолжетімді болса)"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB жөндеулеріне рұқсат берілсін бе?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB жөндеу дамыту мақсаттарына ғана арналған. Оны компьютер және құрылғы арасында дерек көшіру, құрылғыға ескертусіз қолданба орнату және тіркелім деректерін оқу үшін қолданыңыз."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Сымсыз желі арқылы түзетуге рұқсат берілсін бе?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Сымсыз желі арқылы түзету функциясы дамыту мақсаттарына ғана арналған. Оны компьютер және құрылғы арасында дерек көшіру, құрылғыға ескертусіз қолданба орнату және журнал деректерін оқу үшін қолданыңыз."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Сымсыз түзетуге рұқсат берілсін бе?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Сымсыз түзету функциясы дамыту мақсаттарына ғана арналған. Оны компьютер және құрылғы арасында дерек көшіру, құрылғыға ескертусіз қолданба орнату және журнал деректерін оқу үшін қолданыңыз."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Бұған дейін рұқсат берілген барлық компьютерлерде USB жөндеу функциясына тыйым салынсын ба?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Жетілдіру параметрлеріне рұқсат берілсін бе?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Бұл параметрлер жетілдіру мақсатында ғана қолданылады. Олар құрылғыңыз бен қолданбаларыңыздың бұзылуына немесе әдеттен тыс әрекеттерге себеп болуы мүмкін."</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Фондық қолданбалар үшін \"Қолданба жауап бермейді\" терезесін шығару"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Хабарландыру арнасының ескертулерін көрсету"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Қолданба жарамсыз арна арқылы хабарландыру жариялағанда, экранға ескерту шығарады"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Чат хабарландырулары үшін таңбашаларды пайдалану"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Хабарландырулар чат бөлімінде көрсетілуі үшін, оларды ұзақ көрсетілетін таңбаша арқылы міндетті түрде қайталап көрсету"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Сыртқы жадта қолданбаларға рұқсат ету"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Манифест мәндеріне қарамастан, кез келген қолданбаны сыртқы жадқа жазу мүмкіндігін береді"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Әрекеттердің өлшемін өзгертуге рұқсат ету"</string> @@ -426,10 +432,10 @@ <string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"Пайдалану деректеріңізге сәйкес енді шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <!-- no translation found for power_remaining_duration_only_short (7438846066602840588) --> <skip /> - <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Пайдалануға байланысты шамамен <xliff:g id="TIME">%1$s</xliff:g> уақытқа жетеді (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Пайдалануға байланысты шамамен <xliff:g id="TIME">%1$s</xliff:g> уақытқа жетеді"</string> - <string name="power_discharge_by" msgid="4113180890060388350">"Шамамен <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) уақытқа жетеді"</string> - <string name="power_discharge_by_only" msgid="92545648425937000">"Шамамен <xliff:g id="TIME">%1$s</xliff:g> уақытқа жетеді"</string> + <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Пайдалануға байланысты шамамен <xliff:g id="TIME">%1$s</xliff:g> дейін жетеді (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Пайдалануға байланысты шамамен <xliff:g id="TIME">%1$s</xliff:g> дейін жетеді"</string> + <string name="power_discharge_by" msgid="4113180890060388350">"Шамамен <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) дейін жетеді"</string> + <string name="power_discharge_by_only" msgid="92545648425937000">"Шамамен <xliff:g id="TIME">%1$s</xliff:g> дейін жетеді"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> дейін"</string> <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Батарея заряды <xliff:g id="TIME">%1$s</xliff:g> сағатқа қарай бітуі мүмкін."</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g> шамасынан аз қалды"</string> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index 4cf8beda4098..ab297f24a4b5 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"ការជួសជុលដោយឥតខ្សែ"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ដើម្បីមើលឃើញ និងប្រើឧបករណ៍ដែលមាន សូមបើកការជួសជុលដោយឥតខ្សែ"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"ផ្គូផ្គងឧបករណ៍ដោយប្រើកូដ QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"ផ្គូផ្គងឧបករណ៍ថ្មីដោយប្រើកម្មវិធីស្កេនកូដ QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"ផ្គូផ្គងឧបករណ៍ថ្មីដោយប្រើកម្មវិធីស្កេនកូដ QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"ផ្គូផ្គងឧបករណ៍ដោយប្រើកូដផ្គូផ្គង"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ផ្គូផ្គងឧបករណ៍ថ្មីដោយប្រើកូដប្រាំមួយខ្ទង់"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"ឧបករណ៍ដែលបានផ្គូផ្គង"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"មិនអាចផ្គូផ្គងឧបករណ៍បានទេ។ កូដ QR មិនត្រឹមត្រូវ ឬមិនបានភ្ជាប់ឧបករណ៍ទៅបណ្ដាញដូចគ្នា។"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"អាសយដ្ឋាន IP និងច្រក"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"ស្កេនកូដ QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"ផ្គូផ្គងឧបករណ៍តាមរយៈ Wi‑Fi ដោយស្កេនកូដ QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"ផ្គូផ្គងឧបករណ៍តាមរយៈ Wi‑Fi ដោយស្កេនកូដ QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"សូមភ្ជាប់ទៅបណ្តាញ Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ជួសជុល, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ផ្លូវកាត់រាយការណ៍កំហុស"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"សេចក្តីបញ្ជាក់ការបង្ហាញឥតខ្សែ"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"បើកកំណត់ហេតុរៀបរាប់ Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"ការពន្យឺតការស្កេន Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"ការតម្រៀប MAC ដែលបានកែលម្អ Wi-Fi តាមលំដាប់ចៃដន្យ"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"ទិន្នន័យទូរសព្ទចល័តដំណើរការជានិច្ច"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"ការបង្កើនល្បឿនផ្នែករឹងសម្រាប់ការភ្ជាប់"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"បង្ហាញឧបករណ៍ប្ល៊ូធូសគ្មានឈ្មោះ"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"បង្ហាញជម្រើសសម្រាប់សេចក្តីបញ្ជាក់ការបង្ហាញឥតខ្សែ"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"បង្កើនកម្រិតកំណត់ហេតុ Wi-Fi បង្ហាញក្នុង SSID RSSI ក្នុងកម្មវិធីជ្រើសរើស Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"កាត់បន្ថយការប្រើប្រាស់ថ្ម និងកែលម្អប្រតិបត្តិការបណ្ដាញ"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ការបិទ/បើកនេះប៉ះពាល់ដល់សកម្មភាពតម្រៀប MAC តាមលំដាប់ចៃដន្យសម្រាប់មុខងារភ្ញៀវតែប៉ុណ្ណោះ។\nនៅពេលបើកដំណើរការមុខងារនេះ បណ្ដាញទាំងឡាយដែលបានបើកការតម្រៀប MAC តាមលំដាប់ចៃដន្យប្រហែលជាត្រូវបានតម្រៀបអាសយដ្ឋាន MAC របស់វាតាមលំដាប់ចៃដន្យឡើងវិញ អំឡុពេលភ្ជាប់ ដោយផ្អែកលើពេលវេលាដែលភ្ញៀវបានផ្ដាច់លើកចុងក្រោយពីបណ្ដាញ។ ការតម្រៀបតាមលំដាប់ចៃដន្យឡើងវិញមិនកើតឡើងទេ ប្រសិនបើឧបករណ៍ភ្ជាប់ឡើងវិញក្នុងរយៈពេល 4 ម៉ោង ឬឆាប់ជាងនេះ។"</string> <string name="wifi_metered_label" msgid="8737187690304098638">"មានការកំណត់"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"មិនមានការកំណត់"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"ទំហំកន្លែងផ្ទុករបស់ logger"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"បង្ហាញប្រអប់កម្មវិធីមិនឆ្លើយតបសម្រាប់កម្មវិធីផ្ទៃខាងក្រោយ"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"បង្ហាញការព្រមានអំពីបណ្តាញជូនដំណឹង"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"បង្ហាញការព្រមាននៅលើអេក្រង់ នៅពេលកម្មវិធីបង្ហោះការជូនដំណឹងដោយមិនមានបណ្តាញត្រឹមត្រូវ"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ជំរុញឱ្យប្រើផ្លូវកាត់សម្រាប់ការជូនដំណឹងពីការសន្ទនា"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"តម្រូវឱ្យបម្រុងទុកការជូនដំណឹង តាមរយៈផ្លូវកាត់ចែករំលែកដែលមានអាយុកាលយូរទើបអាចបង្ហាញនៅក្នុងផ្នែកនៃការសន្ទនាបាន"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"បង្ខំឲ្យអនុញ្ញាតកម្មវិធីលើឧបករណ៍ផ្ទុកខាងក្រៅ"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"ធ្វើឲ្យកម្មវិធីទាំងឡាយមានសិទ្ធិសរសេរទៅកាន់ឧបករណ៍ផ្ទុកខាងក្រៅ ដោយមិនគិតពីតម្លៃជាក់លាក់"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"បង្ខំឲ្យសកម្មភាពអាចប្តូរទំហំបាន"</string> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index ed854ac3af49..5bba830a40d7 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"ವೈರ್ಲೆಸ್ ಡೀಬಗ್ ಮಾಡುವಿಕೆ"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ಲಭ್ಯವಿರುವ ಸಾಧನಗಳನ್ನು ನೋಡಲು ಮತ್ತು ಬಳಸಲು, ವೈರ್ಲೆಸ್ ಡೀಬಗ್ ಮಾಡುವಿಕೆಯನ್ನು ಆನ್ ಮಾಡಿ"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR ಕೋಡ್ ಬಳಸಿ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR ಕೋಡ್ ಸ್ಕ್ಯಾನರ್ ಬಳಸಿ ಹೊಸ ಸಾಧನಗಳನ್ನು ಜೋಡಿಸಿ"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR ಕೋಡ್ ಸ್ಕ್ಯಾನರ್ ಬಳಸಿ ಹೊಸ ಸಾಧನಗಳನ್ನು ಜೋಡಿಸಿ"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"ಜೋಡಿಸುವ ಕೋಡ್ ಬಳಸಿ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ಆರು ಅಂಕಿಯ ಕೋಡ್ ಬಳಸಿ ಹೊಸ ಸಾಧನಗಳನ್ನು ಜೋಡಿಸಿ"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"ಜೋಡಿಸಲಾದ ಸಾಧನಗಳು"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"ಸಾಧನವನ್ನು ಜೋಡಿಸಲು ವಿಫಲವಾಗಿದೆ. QR ಕೋಡ್ ತಪ್ಪಾಗಿದೆ ಅಥವಾ ಸಾಧನವು ಒಂದೇ ನೆಟ್ವರ್ಕ್ಗೆ ಕನೆಕ್ಟ್ ಆಗಿಲ್ಲ."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ವಿಳಾಸ ಮತ್ತು ಪೋರ್ಟ್"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR ಕೋಡ್ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR ಕೋಡ್ ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡುವ ಮೂಲಕ ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ನಲ್ಲಿ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR ಕೋಡ್ ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡುವ ಮೂಲಕ ವೈ-ಫೈನಲ್ಲಿ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗೆ ಸಂಪರ್ಕಿಸಿ"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ಡೀಬಗ್, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ದೋಷ ವರದಿಯ ಶಾರ್ಟ್ಕಟ್"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"ವೈರ್ಲೆಸ್ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣ"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi ವೆರ್ಬೋಸ್ ಲಾಗಿಂಗ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"ವೈ-ಫೈ ಸ್ಕ್ಯಾನ್ ನಿರ್ಬಂಧಿಸಲಾಗುತ್ತಿದೆ"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"ಮೊಬೈಲ್ ಡೇಟಾ ಯಾವಾಗಲೂ ಸಕ್ರಿಯ"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"ಟೆಥರಿಂಗ್ಗಾಗಿ ಹಾರ್ಡ್ವೇರ್ ವೇಗವರ್ಧನೆ"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ಹೆಸರುಗಳಿಲ್ಲದ ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ತೋರಿಸಿ"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ವೈರ್ಲೆಸ್ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ತೋರಿಸು"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ಲಾಗಿಂಗ್ ಮಟ್ಟನ್ನು ಹೆಚ್ಚಿಸಿ, Wi‑Fi ಆಯ್ಕೆಯಲ್ಲಿ ಪ್ರತಿಯೊಂದು SSID RSSI ತೋರಿಸಿ"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ಬ್ಯಾಟರಿ ಹೆಚ್ಚು ಬಾಳಿಕೆ ಬರುವಂತೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ನೆಟ್ವರ್ಕ್ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಸುಧಾರಿಸುತ್ತದೆ"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"ಮೀಟರ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"ಮೀಟರ್ ಮಾಡಲಾಗಿಲ್ಲ"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"ಲಾಗರ್ ಬಫರ್ ಗಾತ್ರಗಳು"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"ಹಿನ್ನೆಲೆ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರತಿಕ್ರಿಯಿಸುತ್ತಿಲ್ಲ ಎಂಬ ಸಂಭಾಷಣೆ ತೋರಿಸಿ"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"ಅಧಿಸೂಚನೆ ಎಚ್ಚರಿಕೆ ತೋರಿಸಿ"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ಅಮಾನ್ಯ ಚಾನಲ್ ಅಧಿಸೂಚನೆಗಾಗಿ ಪರದೆಯಲ್ಲಿ ಎಚ್ಚರಿಕೆ"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ಸಂಭಾಷಣೆ ಅಧಿಸೂಚನೆಗಳಿಗಾಗಿ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಜಾರಿಗೊಳಿಸಿ"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"ಸಂಭಾಷಣೆ ವಿಭಾಗದಲ್ಲಿ ಕಾಣಿಸಿಕೊಳ್ಳಲು, ಅಧಿಸೂಚನೆಗಳನ್ನು ದೀರ್ಘಕಾಲದ ಹಂಚಿಕೆ ಶಾರ್ಟ್ಕಟ್ ಮೂಲಕ ಬೆಂಬಲಿಸುವ ಅಗತ್ಯವಿದೆ"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"ಬಾಹ್ಯವಾಗಿ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಒತ್ತಾಯವಾಗಿ ಅನುಮತಿಸಿ"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳು ಯಾವುದೇ ಆಗಿದ್ದರೂ, ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಒತ್ತಾಯ ಮಾಡಿ"</string> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index 6f642c3f59ee..a98bfd350543 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"무선 디버깅"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"사용 가능한 기기를 보고 사용하려면 무선 디버깅을 사용 설정하세요."</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR 코드로 기기 페어링"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR 코드 스캐너를 사용하여 새 기기 페어링"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR 코드 스캐너를 사용하여 새 기기 페어링"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"페어링 코드로 기기 페어링"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"6자리 코드를 사용하여 새 기기 페어링"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"페어링된 기기"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"기기를 페어링할 수 없습니다. QR 코드가 잘못되었거나 기기가 동일한 네트워크에 연결되어 있지 않습니다."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP 주소 및 포트"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR 코드 스캔"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR 코드를 스캔하여 Wi‑Fi를 통해 기기 페어링"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR 코드를 스캔하여 Wi‑Fi를 통해 기기 페어링"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Wi-Fi 네트워크에 연결하세요."</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, 디버그, 개발자"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"버그 신고 바로가기"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"무선 디스플레이 인증서"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi-Fi 상세 로깅 사용"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi 검색 제한"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi로 MAC 무작위 순서 지정 개선"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"항상 모바일 데이터 활성화"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"테더링 하드웨어 가속"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"이름이 없는 블루투스 기기 표시"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"무선 디스플레이 인증서 옵션 표시"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi 로깅 수준을 높이고, Wi‑Fi 선택도구에서 SSID RSSI당 값을 표시"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"배터리 소모를 줄이고 네트워크 성능 개선"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"이 전환은 클라이언트 모드의 MAC 무작위 순서 지정 방식에만 영향을 줍니다.\n이 모드를 활성화하면 네트워크와 클라이언트 연결이 끊긴 마지막 시점에 따라 MAC 무작위 순서 지정이 사용 설정된 네트워크에서 연결 중에 MAC 주소를 다시 무작위 순서로 지정할 수 있습니다. 기기가 4시간 이내에 재연결된 경우 무작위 순서 지정이 다시 발생하지 않습니다."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"종량제 네트워크"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"무제한 네트워크"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"로거 버퍼 크기"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"백그라운드 앱과 관련해 앱 응답 없음 대화상자 표시"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"알림 채널 경고 표시"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"앱에서 유효한 채널 없이 알림을 게시하면 화면에 경고 표시"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"대화 알림에 단축키 적용"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"알림이 대화 섹션에 표시되려면 오래 지속되는 공유 단축키의 지원을 받도록 요구"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"외부에서 앱 강제 허용"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"매니페스트 값과 관계없이 모든 앱이 외부 저장소에 작성되도록 허용"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"활동의 크기가 조정 가능하도록 설정"</string> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 417e5115ba5a..33b0aaf40833 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -37,7 +37,7 @@ <string name="wifi_no_internet" msgid="1774198889176926299">"Интернетке туташпай турат"</string> <string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> тарабынан сакталды"</string> <string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s аркылуу автоматтык түрдө туташты"</string> - <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Тармактар рейтингинин автору аркылуу автоматтык түрдө туташты"</string> + <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Тармактар рейтингинин булагы аркылуу автоматтык түрдө туташты"</string> <string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s аркылуу жеткиликтүү"</string> <string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> аркылуу туташты"</string> <string name="available_via_passpoint" msgid="1716000261192603682">"%1$s аркылуу жеткиликтүү"</string> @@ -146,7 +146,7 @@ <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB модем"</string> <string name="tether_settings_title_wifi" msgid="4803402057533895526">"Wi-Fi байланыш түйүнү"</string> <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Bluetooth модем"</string> - <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Жалгаштыруу"</string> + <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Модем режими"</string> <string name="tether_settings_title_all" msgid="8910259483383010470">"Модем режими"</string> <string name="managed_user_title" msgid="449081789742645723">"Жумуш профилинин колднмлр"</string> <string name="user_guest" msgid="6939192779649870792">"Конок"</string> @@ -171,7 +171,7 @@ <string name="tts_engine_security_warning" msgid="3372432853837988146">"Бул кепти синтездөө каражаты бардык айтыла турган текстти, анын ичинде сырсөздөр жана насыя карточкасынын номери сыяктуу жеке маалыматты, топтошу мүмкүн. Ал <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> каражатынан алынат. Бул кепти синтездөө каражаты колдонулсунбу?"</string> <string name="tts_engine_network_required" msgid="8722087649733906851">"Бул тилде кеп синтезаторун иштетүү үчүн Интернетке туташуу керек."</string> <string name="tts_default_sample_string" msgid="6388016028292967973">"Бул айтылганды синтездөөнүн мисалы"</string> - <string name="tts_status_title" msgid="8190784181389278640">"Абалкы тилдин абалы"</string> + <string name="tts_status_title" msgid="8190784181389278640">"Демейки тилдин абалы"</string> <string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> толук колдоого алынган"</string> <string name="tts_status_requires_network" msgid="8327617638884678896">"<xliff:g id="LOCALE">%1$s</xliff:g> желеге туташууну талап кылат"</string> <string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> колдоого алынган эмес"</string> @@ -201,18 +201,18 @@ <string name="development_settings_summary" msgid="8718917813868735095">"Колдонмо өндүрүү мүмкүнчүлүктөрүн орнотуу"</string> <string name="development_settings_not_available" msgid="355070198089140951">"Бул колдонуучуга өнүктүүрүүчү мүмкүнчүлүктөрү берилген эмес."</string> <string name="vpn_settings_not_available" msgid="2894137119965668920">"Бул колдонуучу VPN жөндөөлөрүн колдоно албайт"</string> - <string name="tethering_settings_not_available" msgid="266821736434699780">"Бул колдонуучу тетеринг жөндөөлөрүн колдоно албайт"</string> + <string name="tethering_settings_not_available" msgid="266821736434699780">"Бул колдонуучу модем режиминин жөндөөлөрүн өзгөртө албайт"</string> <string name="apn_settings_not_available" msgid="1147111671403342300">"Бул колдонуучу мүмкүндүк алуу түйүнүнүн аталышынын жөндөөлөрүн колдоно албайт"</string> <string name="enable_adb" msgid="8072776357237289039">"USB аркылуу мүчүлүштүктөрдү оңдоо"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"USB компьютерге сайылганда мүчүлүштүктөрдү оңдоо режими иштейт"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB аркылуу мүчүлүштүктөрдү оңдоо уруксатын артка кайтаруу"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Мүчүлүштүктөрдү зымсыз оңдоо"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоо"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi\'га туташтырылганда мүчүлүштүктөрдү оңдоо режими"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Ката"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Мүчүлүштүктөрдү зымсыз оңдоо"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Жеткиликтүү түзмөктөрдү көрүү үчүн мүчүлүштүктөрдү зымсыз оңдоону күйгүзүңүз"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоо"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Жеткиликтүү түзмөктөрдү көрүү үчүн мүчүлүштүктөрдү Wi-Fi аркылуу оңдоону күйгүзүңүз"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR кодун колдонуп, түзмөктү жупташтырыңыз"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR кодунун сканерин колдонуп, жаңы түзмөктөрдү жупташтырыңыз"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR кодунун сканерин колдонуп, жаңы түзмөктөрдү жупташтырыңыз"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Жупташтыруучу код менен түзмөктү жупташтырыңыз"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Алты сандан турган кодду колдонуп, жаңы түзмөктөрдү жупташтырыңыз"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Жупташтырылган түзмөктөр"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Түзмөк жупташтырылган жок. QR коду туура эмес же түзмөк бир тармакка туташпай турат."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP дареги жана Оюкча"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR кодун скандоо"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR кодун скандап, түзмөктү Wi‑Fi аркылуу жупташтырыңыз"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR кодун скандап, түзмөктү Wi‑Fi аркылуу жупташтырыңыз"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Wi-Fi тармагына туташыңыз"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, мүчүлүштүктөрдү оңдоо, иштеп чыгуу"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Ката жөнүндө кабарлоо"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Зымсыз мониторлорду тастыктамалоо"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi дайын-даректүү журналы"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi тармактарын издөөнү жөнгө салуу"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Мобилдик Интернет иштей берет"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Модем режиминде аппараттын иштешин тездетүү"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Аталышсыз Bluetooth түзмөктөрү көрсөтүлсүн"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Зымсыз мониторлорду тастыктамалоо параметрлери көрүнүп турат"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi тандалганда ар бир SSID үчүн RSSI көрүнүп турат"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батареянын коротулушун чектеп, тармактын иштешин жакшыртат"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"Трафик ченелет"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Чектелбеген тармак"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Журнал буферинин өлчөмү"</string> @@ -300,8 +304,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Мүмкүнчүлүккө жараша, модем режиминде аппарат тезирээк иштей баштайт"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB аркылуу жөндөөгө уруксат бересизби?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB-жөндөө - өндүрүү максатында гана түзүлгөн. Аны компүтериңиз менен түзмөгүңүздүн ортосунда берилиштерди алмашуу, түзмөгүңүзгө колдонмолорду эскертүүсүз орнотуу жана лог берилиштерин окуу үчүн колдонсоңуз болот."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Мүчүлүштүктөрдү зымсыз оңдоого уруксат берилсинби?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Мүчүлүштүктөрдү зымсыз оңдоо – өндүрүү максатында гана түзүлгөн. Аны компьютериңиз менен түзмөгүңүздүн ортосунда маалыматты алмашуу, колдонмолорду түзмөгүңүзгө эскертүүсүз орнотуу жана маалыматтар таржымалын окуу үчүн колдонсоңуз болот."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоого уруксат берилсинби?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоо – өндүрүү максатында гана түзүлгөн. Аны компьютериңиз менен түзмөгүңүздүн ортосунда маалыматты алмашуу, колдонмолорду түзмөгүңүзгө эскертүүсүз орнотуу жана маалыматтар таржымалын окуу үчүн колдонсоңуз болот."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Сиз мурун USB жөндөөлөрүнө уруксат берген бардык компүтерлердин жеткиси жокко чыгарылсынбы?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Жөндөөлөрдү өзгөртүү"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Бул орнотуулар өндүрүүчүлөр үчүн гана берилген. Булар түзмөгүңүздүн колдонмолорун бузулушуна же туура эмес иштешине алып келиши мүмкүн."</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Фондогу колдонмо жооп бербей жатат деп билдирип турат"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Билдирмелер каналынын эскертүүлөрүн көрсөтүү"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Тыюу салынган каналдын колдонмосунун жаңы билдирмелери тууралуу эскертүүлөр көрүнөт"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Жазышуу билдирмелери үчүн ыкчам баскычтарды иштетиңиз"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Жазышуу бөлүмүндө көрсөтүү үчүн билдирмелерди узак убакытка колдонулуучу ыкчам баскычтар менен колдоону талап кылыңыз"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Тышкы сактагычка сактоого уруксат берүү"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Манифест маанилерине карабастан бардык колдонмолорду тышкы сактагычка сактоого уруксат берет"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Бир нече терезе режиминде өлчөмдү өзгөртүү"</string> @@ -428,8 +434,8 @@ <skip /> <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Колдонгонуңузга караганда болжол менен <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) кийин өчөт"</string> <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Колдонгонуңузга караганда болжол менен <xliff:g id="TIME">%1$s</xliff:g> кийин өчөт"</string> - <string name="power_discharge_by" msgid="4113180890060388350">"Болжол менен <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) кийин өчөт"</string> - <string name="power_discharge_by_only" msgid="92545648425937000">"Болжол менен <xliff:g id="TIME">%1$s</xliff:g> кийин өчөт"</string> + <string name="power_discharge_by" msgid="4113180890060388350">"Болжол менен саат <xliff:g id="TIME">%1$s</xliff:g> өчөт, (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_discharge_by_only" msgid="92545648425937000">"Болжол менен саат <xliff:g id="TIME">%1$s</xliff:g> өчөт"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> чейин"</string> <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Батарея <xliff:g id="TIME">%1$s</xliff:g> отуруп калышы мүмкүн"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g> жетпеген убакыт калды"</string> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 58c8c39b4ea5..bdbc8efd976f 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"ການດີບັກໄຮ້ສາຍ"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ເພື່ອເບິ່ງ ແລະ ໃຊ້ອຸປະກອນທີ່ມີຢູ່, ກະລຸນາເປີດການດີບັກໄຮ້ສາຍ"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"ຈັບຄູ່ອຸປະກອນດ້ວຍລະຫັດ QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"ຈັບຄູ່ອຸປະກອນໃໝ່ໂດຍໃຊ້ຕົວສະແກນລະຫັດ QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"ຈັບຄູ່ອຸປະກອນໃໝ່ໂດຍໃຊ້ຕົວສະແກນລະຫັດ QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"ຈັບຄູ່ອຸປະກອນໂດຍໃຊ້ລະຫັດການຈັບຄູ່"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ຈັບຄູ່ອຸປະກອນໃໝ່ໂດຍໃຊ້ລະຫັດຫົກຕົວເລກ"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"ອຸປະກອນທີ່ຈັບຄູ່ແລ້ວ"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"ຈັບຄູ່ອຸປະກອນບໍ່ສຳເລັດ. ລະຫັດ QR ບໍ່ຖືກຕ້ອງ ຫຼື ອຸປະກອນບໍ່ໄດ້ເຊື່ອມຕໍ່ຫາເຄືອຂ່າຍດຽວກັນ."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"ທີ່ຢູ່ IP ແລະ ຜອດ"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"ສະແກນລະຫັດ QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"ຈັບຄູ່ອຸປະກອນຜ່ານ Wi‑Fi ໂດຍການສະແກນລະຫັດ QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"ຈັບຄູ່ອຸປະກອນຜ່ານ Wi‑Fi ໂດຍການສະແກນລະຫັດ QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"ກະລຸນາເຊື່ອມຕໍ່ກັບເຄືອຂ່າຍ Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ທາງລັດລາຍງານຂໍ້ຜິດພາດ"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"ສະແດງການຮັບຮອງຂອງລະບົບໄຮ້ສາຍ"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"ເປີດນຳໃຊ້ການເກັບປະຫວັດ Verbose Wi‑Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"ການຈຳກັດການສະແກນ Wi‑Fi"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"ເປີດໃຊ້ອິນເຕີເນັດມືຖືຕະຫຼອດເວລາ"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"ເປີດໃຊ້ການເລັ່ງຄວາມໄວດ້ວຍຮາດແວ"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ສະແດງອຸປະກອນ Bluetooth ທີ່ບໍ່ມີຊື່"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ສະແດງໂຕເລືອກສຳລັບການສະແດງການຮັບຮອງລະບົບໄຮ້ສາຍ"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ເພີ່ມລະດັບການເກັບປະຫວັດ Wi‑Fi, ສະແດງຕໍ່ SSID RSSI ໃນ Wi‑Fi Picker"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ຫຼຸດການໃຊ້ແບັດເຕີຣີ ແລະ ປັບປຸງປະສິດທິພາບເຄືອຂ່າຍ"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"ມີການວັດແທກ"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"ບໍ່ໄດ້ວັດແທກ"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"ຂະໜາດບັບເຟີຕົວບັນທຶກ"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"ສະແດງກ່ອງຂໍ້ຄວາມບໍ່ຕອບສະໜອງແອັບສຳລັບແອັບພື້ນຫຼັງ"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"ສະແດງຄຳເຕືອນຊ່ອງການແຈ້ງເຕືອນ"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ສະແດງຄຳເຕືອນໃນໜ້າຈໍເມື່ອແອັບໂພສການແຈ້ງເຕືອນໂດຍບໍ່ມີຊ່ອງທີ່ຖືກຕ້ອງ"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ບັງຄັບໃຊ້ທາງລັດສຳລັບການແຈ້ງເຕືອນການສົນທະນາ"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"ຕ້ອງໃຊ້ການແຈ້ງເຕືອນເພື່ອຮັບການສະໜັບສະໜຸນໂດຍທາງລັດການແບ່ງປັນທີ່ຢູ່ດົນເພື່ອໃຫ້ປາກົດໃນພາກສ່ວນການສົນທະນາ"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"ບັງຄັບອະນຸຍາດແອັບຢູ່ພາຍນອກ"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"ເຮັດໃຫ້ທຸກແອັບມີສິດໄດ້ຮັບການຂຽນໃສ່ພື້ນທີ່ຈັດເກັບຂໍ້ມູນພາຍນອກ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າ manifest"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"ບັງຄັງໃຫ້ການເຄື່ອນໄຫວປ່ຽນຂະໜາດໄດ້"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index 94800ea8b3a7..e2ccc3a30877 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Belaidžio ryšio derinimas"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Jei norite peržiūrėti ir naudoti pasiekiamus įrenginius, įjunkite belaidžio ryšio derinimą"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Įrenginio susiejimas naudojant QR kodą"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Susiekite naujus įrenginius naudodami QR kodų skaitytuvą"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Susiekite naujus įrenginius naudodami QR kodų skaitytuvą"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Įrenginio susiejimas naudojant susiejimo kodą"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Susiekite naujus įrenginius naudodami šešių skaitmenų kodą"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Susieti įrenginiai"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Nepavyko susieti įrenginio. Netinkamas QR kodas arba įrenginys neprijungtas prie to paties tinklo."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP adresas ir prievadas"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR kodo nuskaitymas"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Susiekite įrenginį „Wi‑Fi“ ryšiu nuskaitydami QR kodą"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Susiekite įrenginį „Wi‑Fi“ ryšiu nuskaitydami QR kodą"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Prisijunkite prie „Wi-Fi“ tinklo"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"ADB, derinti, kūrėjas"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Pranešimo apie riktą spartusis klavišas"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Belaidžio rodymo sertifikavimas"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Įgal. „Wi‑Fi“ daugiaž. įraš. į žurnalą"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"„Wi‑Fi“ nuskaitymo ribojimas"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"„Wi‑Fi“ patob. atsit. MAC adr. parink."</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiliojo ryšio duomenys visada suaktyvinti"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Įrenginio kaip modemo naudojimo aparatinės įrangos spartinimas"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rodyti „Bluetooth“ įrenginius be pavadinimų"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Rodyti belaidžio rodymo sertifikavimo parinktis"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Padidinti „Wi‑Fi“ įrašymo į žurnalą lygį, rodyti SSID RSSI „Wi-Fi“ rinkiklyje"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Sumažinamas akumuliatoriaus eikvojimas ir patobulinamas tinklo našumas"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Perjungiamas tik atsitiktinis MAC adreso parinkimas dirbant kliento režimu.\nKai suaktyvintas šis režimas, visuose tinkluose, kuriuose įgalintas atsitiktinis MAC adreso parinkimas, susiejant šie adresai gali būti atsitiktinai parenkami iš naujo, atsižvelgiant į tai, kada klientas paskutinį kartą atsijungė nuo tinklo. Atsitiktinis MAC adreso parinkimas nevykdomas iš naujo, jei įrenginys vėl prisijungia ne daugiau nei po keturių valandų."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Matuojamas"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Neišmatuotas"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Registruotuvo buferio dydžiai"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Foninėse programose rodyti dialogo langą „Programa neatsako“"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Rodyti pran. kan. įspėj."</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Ekr. rod. įsp., kai progr. pask. pr. be tink. kan."</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Nustatyti pokalbio pranešimų šaukinius"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kad pranešimai būtų rodomi pokalbių skiltyje, būtinas ilgalaikis jų bendrinimo šaukinys"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Priverstinai leisti programas išorinėje atmintin."</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Nustatoma, kad visas programas būtų galima įrašyti į išorinę saugyklą, nepaisant aprašo verčių"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Priv. nust., kad veiksm. b. g. atl. kelių d. lang."</string> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index d7816aa54a1a..64368b7b0e95 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Bezvadu atkļūdošana"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Lai skatītu un izmantotu pieejamās ierīces, ieslēdziet bezvadu atkļūdošanu."</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Ierīču savienošana pārī, izmantojot QR kodu"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Savienot pārī jaunas ierīces, izmantojot QR koda skeneri"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Savienot pārī jaunas ierīces, izmantojot QR koda skeneri"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Ierīču savienošana pārī, izmantojot kodu"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Savienojiet pārī jaunas ierīces, izmantojot sešu ciparu kodu"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Pārī savienotās ierīces"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Neizdevās izveidot savienojumu pārī ar ierīci. QR kods nebija pareizs, vai ierīcei nebija izveidots savienojums ar to pašu tīklu."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP adrese un ports"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR koda skenēšana"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Izveidojiet savienojumu pārī ar ierīci Wi‑Fi tīklā, skenējot QR kodu."</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Izveidojiet savienojumu pārī ar ierīci Wi‑Fi tīklā, skenējot QR kodu."</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Lūdzu, izveidojiet savienojumu ar Wi-Fi tīklu"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, atkļūdošana, izstrādātājiem"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Kļūdu pārskata saīsne"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Bezvadu attēlošanas sertifikācija"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Iespējot Wi‑Fi detalizēto reģistrēšanu"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi meklēšanas ierobežošana"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"MAC adrešu nejauša izveide ar Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Vienmēr aktīvs mobilo datu savienojums"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Paātrināta aparatūras darbība piesaistei"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rādīt Bluetooth ierīces bez nosaukumiem"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Rādīt bezvadu attēlošanas sertifikācijas iespējas"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Palieliniet Wi‑Fi reģistrēšanas līmeni; rādīt katram SSID RSSI Wi‑Fi atlasītājā."</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Samazina akumulatora izlādi un uzlabo tīkla veiktspēju"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Šis slēdzis ietekmē MAC adrešu nejaušas izveides darbību tikai klienta režīmā.\nJa šis režīms ir aktivizēts, visos tīklos, kuros MAC adrešu nejauša izveide ir iespējota, saistīšanas laikā MAC adreses var tikt atkārtoti nejauši izveidotas atkarībā no tā, kad klients pēdējoreiz pārtrauca savienojumu ar tīklu. Atkārtota nejauša izveide netiek veikta, ja ierīces savienojums tiek atjaunots ne vairāk kā 4 stundu laikā."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Maksas"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Bezmaksas"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Reģistrētāja buferu lielumi"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Rādīt fona lietotņu dialoglodziņu Lietotne nereaģē"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Paziņojumu kanāla brīdinājumi"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Brīdinājums ekrānā, kad lietotne publicē paziņojumu, nenorādot derīgu kanālu"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Ieviest saīsnes sarunu paziņojumiem"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Pieprasīt izmantot paziņojumiem ilgstošas darbības kopīgošanas saīsni rādīšanai sarunu sadaļā"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Lietotņu piespiedu atļaušana ārējā krātuvē"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Ļauj jebkuru lietotni ierakstīt ārējā krātuvē neatkarīgi no manifesta vērtības."</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Pielāgot darbības"</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index 754c3a07db15..934fcf74f9f8 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -23,7 +23,7 @@ <string name="wifi_fail_to_scan" msgid="2333336097603822490">"Не може да скенира за мрежи"</string> <string name="wifi_security_none" msgid="7392696451280611452">"Ниедна"</string> <string name="wifi_remembered" msgid="3266709779723179188">"Зачувано"</string> - <string name="wifi_disconnected" msgid="7054450256284661757">"Исклучен"</string> + <string name="wifi_disconnected" msgid="7054450256284661757">"Прекината врска"</string> <string name="wifi_disabled_generic" msgid="2651916945380294607">"Оневозможено"</string> <string name="wifi_disabled_network_failure" msgid="2660396183242399585">"Конфигурирањето ИП не успеа"</string> <string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"Не е поврзано поради нискиот квалитет на мрежата"</string> @@ -37,7 +37,7 @@ <string name="wifi_no_internet" msgid="1774198889176926299">"Нема пристап до интернет"</string> <string name="saved_network" msgid="7143698034077223645">"Зачувано од <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="connected_via_network_scorer" msgid="7665725527352893558">"Автоматски поврзано преку %1$s"</string> - <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Автоматски поврзано преку оператор за оценување мрежа"</string> + <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Автоматски поврзано преку оценувач на мрежа"</string> <string name="connected_via_passpoint" msgid="7735442932429075684">"Поврзано преку %1$s"</string> <string name="connected_via_app" msgid="3532267661404276584">"Поврзано преку <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="available_via_passpoint" msgid="1716000261192603682">"Достапно преку %1$s"</string> @@ -143,10 +143,10 @@ <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Отстранети апликации"</string> <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Отстранети апликации и корисници"</string> <string name="data_usage_ota" msgid="7984667793701597001">"Ажурирања на системот"</string> - <string name="tether_settings_title_usb" msgid="3728686573430917722">"Поврзување со USB"</string> + <string name="tether_settings_title_usb" msgid="3728686573430917722">"Интернет преку USB"</string> <string name="tether_settings_title_wifi" msgid="4803402057533895526">"Преносл. точка на пристап"</string> - <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Поврзување со Bluetooth"</string> - <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Поврзување"</string> + <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Интернет преку Bluetooth"</string> + <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Врзување"</string> <string name="tether_settings_title_all" msgid="8910259483383010470">"Поврзување и пренослива точка на пристап"</string> <string name="managed_user_title" msgid="449081789742645723">"Сите апликации за работа"</string> <string name="user_guest" msgid="6939192779649870792">"Гостин"</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Безжично отстранување грешки"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"За да ги гледате и користите достапните уреди, вклучете го безжичното отстранување грешки"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Спарете уред преку QR-код"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Спарете нови уреди преку скенер за QR-код"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Спарете нови уреди преку скенер за QR-код"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Спарете уред преку код за спарување"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Спарете нови уреди преку шестцифрен код"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Спарени уреди"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Уредот не успеа да се спари. Или QR-кодот беше погрешен или уредот не е поврзан на истата мрежа."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-адреса и порта"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Скенирајте QR-код"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Спарете го уредот преку Wi‑Fi со скенирање QR-код"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Спарете го уредот преку Wi‑Fi со скенирање QR-код"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Поврзете се на Wi-Fi-мрежа"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, отстранува грешка, програмер"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Кратенка за извештај за грешка"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Приказ на сертификација на безжична мрежа"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Овозможи преопширно пријавување Wi‑Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Регулирање на скенирањето за Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Рандомизација на MAC подобрена со Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Мобилниот интернет е секогаш активен"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Хардверско забрзување за врзување"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажувај уреди со Bluetooth без имиња"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Покажи ги опциите за безжичен приказ на сертификат"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Зголеми Wi‑Fi ниво на пријавување, прикажи по SSID RSSI во Wi‑Fi бирач"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Го намалува искористувањето на батеријата и ја подобрува изведбата на мрежата"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Овој прекинувач влијае на однесувањето на рандомизацијата на MAC само за клиентски режим.\nКога е активиран режимов, можно е да се изврши повторна рандомизација на MAC-адресите на сите мрежи што имаат овозможена рандомизација на MAC за време на асоцијацијата, зависно од тоа кога клиентот последен пат се исклучил од мрежата. Повторната рандомизација не се случува ако уредот се поврзе повторно во рок од 4 часа или помалку."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Со ограничен интернет"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Без ограничен интернет"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Величини на меѓумеморија за дневникот"</string> @@ -301,7 +303,7 @@ <string name="adb_warning_title" msgid="7708653449506485728">"Овозможи отстранување грешки на USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"Отстранувањето грешки на USB е наменето само за целите на развој. Користете го за копирање податоци меѓу вашиот компјутер и вашиот уред, за инсталирање апликации на вашиот уред без известување и за читање евиденција на податоци."</string> <string name="adbwifi_warning_title" msgid="727104571653031865">"Да се дозволи безжично отстранување грешки?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Безжичното отстранување грешки е наменето само за развојни цели. Користете го за копирање податоци помеѓу компјутерот и уредот, за инсталирање апликации на уредот без известување и за читање податоци од евиденцијата."</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Безжичното отстранување грешки е наменето само за програмирање. Користете го за копирање податоци помеѓу компјутерот и уредот, за инсталирање апликации на уредот без известување и за читање податоци од евиденцијата."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Отповикај пристап кон отстранување грешка од USB од сите претходно овластени компјутери?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Дозволи поставки за развој?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Овие поставки се наменети само за употреба за развој. Тие може да предизвикаат уредот и апликациите во него да се расипат или да се однесуваат необично."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Прикажи го дијалогот „Апликацијата не реагира“ за апликации во заднина"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Прикажи ги предупредувањата на каналот за известувањe"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Предупредува кога апликација дава известување без важечки канал"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Кратенки за известувањата"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Известувања со долготрајна кратенка за споделување"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Принуд. дозволете апликации на надворешна меморија"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Прави секоја апликација да биде подобна за запишување на надворешна меморија, независно од вредностите на манифестот"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Принуди ги активностите да ја менуваат големината"</string> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index c593bee5e1f6..dbca5e7f3956 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -206,13 +206,14 @@ <string name="enable_adb" msgid="8072776357237289039">"USB ഡീബഗ്ഗിംഗ്"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"USB കണക്റ്റുചെയ്തിരിക്കുമ്പോഴുള്ള ഡീബഗ് മോഡ്"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB ഡീബഗ്ഗിംഗ് അംഗീകാരം പിൻവലിക്കുക"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"വയർലെസ് ഡീബഗ് ചെയ്യൽ"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"വയർലെസ് ഡീബഗ്ഗിംഗ്"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"വൈഫൈ കണക്റ്റ് ചെയ്തിരിക്കുമ്പോൾ ഡീബഗ് ചെയ്യൽ മോഡിലാക്കുക"</string> <string name="adb_wireless_error" msgid="721958772149779856">"പിശക്"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"വയർലെസ് ഡീബഗ് ചെയ്യൽ"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ലഭ്യമായ ഉപകരണങ്ങൾ കാണാനും ഉപയോഗിക്കാനും വയർലെസ് ഡീബഗ് ചെയ്യൽ ഓണാക്കുക"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"വയർലെസ് ഡീബഗ്ഗിംഗ്"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ലഭ്യമായ ഉപകരണങ്ങൾ കാണാനും ഉപയോഗിക്കാനും വയർലെസ് ഡീബഗ്ഗിംഗ് ഓണാക്കുക"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR കോഡ് ഉപയോഗിച്ച് ഉപകരണം ജോടിയാക്കുക"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR കോഡ് സ്കാനർ ഉപയോഗിച്ച് പുതിയ ഉപകരണങ്ങൾ ജോടിയാക്കുക"</string> + <!-- no translation found for adb_pair_method_qrcode_summary (7130694277228970888) --> + <skip /> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"ജോടിയാക്കൽ കോഡ് ഉപയോഗിച്ച് ഉപകരണം ജോടിയാക്കുക"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ആറക്ക കോഡ് ഉപയോഗിച്ച് പുതിയ ഉപകരണങ്ങൾ ജോടിയാക്കുക"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"ജോടിയാക്കിയ ഉപകരണങ്ങൾ"</string> @@ -231,7 +232,8 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"ഉപകരണം ജോടിയാക്കാനായില്ല. ഒന്നുകിൽ QR കോഡ് തെറ്റായിരുന്നു അല്ലെങ്കിൽ ഉപകരണം ഒരേ നെറ്റ്വർക്കിൽ അല്ല കണക്റ്റ് ചെയ്തിട്ടുള്ളത്."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP വിലാസവും പോർട്ടും"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR കോഡ് സ്കാൻ ചെയ്യുക"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR കോഡ് സ്കാൻ ചെയ്ത് വൈഫൈയിലൂടെ ഉപകരണം ജോടിയാക്കുക"</string> + <!-- no translation found for adb_wireless_qrcode_pairing_description (6014121407143607851) --> + <skip /> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"ഒരു വൈഫൈ നെറ്റ്വർക്കിലേക്ക് കണക്റ്റ് ചെയ്യുക"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ബഗ് റിപ്പോർട്ട് കുറുക്കുവഴി"</string> @@ -251,6 +253,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"വയർലെസ് ഡിസ്പ്ലേ സർട്ടിഫിക്കേഷൻ"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"വൈഫൈ വെർബോസ് ലോഗിംഗ് പ്രവർത്തനക്ഷമമാക്കുക"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"വൈഫൈ സ്കാൻ പ്രവർത്തനരഹിതമാക്കുന്നു"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"മൊബൈൽ ഡാറ്റ എല്ലായ്പ്പോഴും സജീവം"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"ടെതറിംഗ് ഹാർഡ്വെയർ ത്വരിതപ്പെടുത്തൽ"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"പേരില്ലാത്ത Bluetooth ഉപകരണങ്ങൾ കാണിക്കുക"</string> @@ -283,7 +287,9 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"വയർലെസ് ഡിസ്പ്ലേ സർട്ടിഫിക്കേഷനായി ഓപ്ഷനുകൾ ദൃശ്യമാക്കുക"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"വൈഫൈ പിക്കറിൽ ഓരോ SSID RSSI പ്രകാരം കാണിക്കാൻ വൈഫൈ ലോഗിംഗ് നില വർദ്ധിപ്പിക്കുക"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ബാറ്ററി ചാർജ് വേഗത്തിൽ തീരുന്ന അവസ്ഥ കുറച്ച് നെറ്റ്വർക്ക് പ്രകടനം മെച്ചപ്പെടുത്തുന്നു"</string> - <string name="wifi_metered_label" msgid="8737187690304098638">"മീറ്റർചെയ്ത"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> + <string name="wifi_metered_label" msgid="8737187690304098638">"മീറ്റർ ചെയ്തത്"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"മീറ്റർമാപകമല്ലാത്തത്"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"ലോഗർ ബഫർ വലുപ്പം"</string> <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"ഓരോ ലോഗ് ബഫറിനും വലുപ്പം തിരഞ്ഞെടുക്കൂ"</string> @@ -300,8 +306,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"ലഭ്യമാണെങ്കിൽ \'ടെതറിംഗ് ഹാർഡ്വെയർ ത്വരിതപ്പെടുത്തൽ\' ഉപയോഗിക്കുക"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB ഡീബഗ്ഗുചെയ്യാൻ അനുവദിക്കണോ?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB ഡീബഗ്ഗിംഗ് വികസന ആവശ്യകതകൾക്ക് മാത്രമുള്ളതാണ്. നിങ്ങളുടെ കമ്പ്യൂട്ടറിനും ഉപകരണത്തിനുമിടയിൽ ഡാറ്റ പകർത്തുന്നതിനും അറിയിപ്പില്ലാതെ തന്നെ നിങ്ങളുടെ ഉപകരണത്തിൽ അപ്ലിക്കേഷനുകൾ ഇൻസ്റ്റാളുചെയ്യുന്നതിനും ലോഗ് ഡാറ്റ റീഡുചെയ്യുന്നതിനും ഇത് ഉപയോഗിക്കുക."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"വയർലെസ് ഡീബഗ് ചെയ്യൽ അനുവദിക്കണോ?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"വയർലെസ് ഡീബഗ് ചെയ്യൽ ഡെവലപ്മെന്റ് ആവശ്യങ്ങൾക്ക് മാത്രമുള്ളതാണ്. നിങ്ങളുടെ കമ്പ്യൂട്ടറിൽ നിന്ന് ഉപകരണത്തിലേക്കും തിരിച്ചും ഡാറ്റ പകർത്തുന്നതിനും ലോഗ് ഡാറ്റ റീഡ് ചെയ്യുന്നതിനും അറിയിപ്പില്ലാതെ നിങ്ങളുടെ ഉപകരണത്തിൽ ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യുന്നതിനും ഇത് ഉപയോഗിക്കുക."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"വയർലെസ് ഡീബഗ്ഗിംഗ് അനുവദിക്കണോ?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"വയർലെസ് ഡീബഗ്ഗിംഗ് ഡെവലപ്മെന്റ് ആവശ്യങ്ങൾക്ക് മാത്രമുള്ളതാണ്. നിങ്ങളുടെ കമ്പ്യൂട്ടറിൽ നിന്ന് ഉപകരണത്തിലേക്കും തിരിച്ചും ഡാറ്റ പകർത്തുന്നതിനും അറിയിപ്പില്ലാതെ തന്നെ നിങ്ങളുടെ ഉപകരണത്തിൽ ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യുന്നതിനും ലോഗ് ഡാറ്റ റീഡ് ചെയ്യുന്നതിനും ഇത് ഉപയോഗിക്കുക."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"നിങ്ങൾ മുമ്പ് അംഗീകരിച്ച എല്ലാ കമ്പ്യൂട്ടറുകളിൽ നിന്നും USB ഡീബഗ്ഗുചെയ്യുന്നതിനുള്ള ആക്സസ്സ് പിൻവലിക്കണോ?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"വികസന ക്രമീകരണങ്ങൾ അനുവദിക്കണോ?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"ഈ ക്രമീകരണങ്ങൾ വികസന ഉപയോഗത്തിന് മാത്രമായുള്ളതാണ്. അവ നിങ്ങളുടെ ഉപകരണവും അതിലെ അപ്ലിക്കേഷനുകളും തകരാറിലാക്കുന്നതിനോ തെറ്റായി പ്രവർത്തിക്കുന്നതിനോ ഇടയാക്കാം."</string> @@ -371,6 +377,10 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"പശ്ചാത്തല ആപ്പുകൾക്കായി \'ആപ്പ് പ്രതികരിക്കുന്നില്ല\' ഡയലോഗ് പ്രദര്ശിപ്പിക്കുക"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"ചാനൽ മുന്നറിയിപ്പ് കാണിക്കൂ"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"സാധുതയുള്ള ചാനലിൽ അല്ലാതെ ഒരു ആപ്പ്, അറിയിപ്പ് പോസ്റ്റ് ചെയ്യുമ്പോൾ ഓൺ-സ്ക്രീൻ മുന്നറിയിപ്പ് പ്രദർശിപ്പിക്കുന്നു"</string> + <!-- no translation found for enforce_shortcuts_for_conversations (7040735163945040763) --> + <skip /> + <!-- no translation found for enforce_shortcuts_for_conversations_summary (1860168037282467862) --> + <skip /> <string name="force_allow_on_external" msgid="9187902444231637880">"ബാഹ്യമായതിൽ നിർബന്ധിച്ച് അനുവദിക്കുക"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, ബാഹ്യ സ്റ്റോറേജിലേക്ക് എഴുതപ്പെടുന്നതിന് ഏതൊരു ആപ്പിനെയും യോഗ്യമാക്കുന്നു"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"വലുപ്പം മാറ്റാൻ പ്രവർത്തനങ്ങളെ നിർബന്ധിക്കുക"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index d3e41f727409..69e4c710356a 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"USB дебаг"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"USB холбодсон үеийн согог засах горим"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB дебагын зөвшөөрлийг хураах"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Утасгүй алдаа засах"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Wireless debugging"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi-Fi холбогдсон үед дебаг хийх горим"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Алдаа"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Утасгүй алдаа засах"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Боломжтой төхөөрөмжүүдийг харах болох ашиглахын тулд утасгүй алдаа засахыг асаана уу"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Wireless debugging"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Боломжтой төхөөрөмжүүдийг харах болох ашиглахын тулд wireless debugging-г асаана уу"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Хурдан хариу үйлдлийн кодоор төхөөрөмжийг хослуул"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Хурдан хариу үйлдлийн кодын сканнерыг ашиглан шинэ төхөөрөмжүүдийг хослуулна уу"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Хурдан хариу үйлдлийн кодын сканнер ашиглан шинэ төхөөрөмжүүдийг хослуулна уу"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Хослуулах кодоор төхөөрөмжийг хослуулна уу"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Зургаан оронтой кодыг ашиглан шинэ төхөөрөмжүүдийг хослуулна уу"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Хослуулсан төхөөрөмжүүд"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Төхөөрөмжийг хослуулж чадсангүй. Хурдан хариу үйлдлийн код буруу эсвэл төхөөрөмжийг ижил сүлжээнд холбоогүй байна."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP хаяг ба порт"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Хурдан хариу үйлдлийн кодыг скан хийх"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Хурдан хариу үйлдлийн кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Хурдан хариу үйлдлийн кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Wi-Fi сүлжээнд холбогдоно уу"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, дебаг хийх, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Алдаа мэдээлэх товчлол"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Утасгүй дэлгэцийн сертификат"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi дэлгэрэнгүй лог-г идэвхжүүлэх"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi скан бууруулалт"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Мобайл дата байнга идэвхтэй"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Модем болгох техник хангамжийн хурдасгуур"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Нэргүй Bluetooth төхөөрөмжийг харуулах"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Утасгүй дэлгэцийн сертификатын сонголтыг харуулах"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi лог-н түвшинг нэмэгдүүлэх, Wi‑Fi Сонгогч дээрх SSID-д ногдох RSSI-г харуулах"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Батарей зарцуулалтыг бууруулж, сүлжээний гүйцэтгэлийг сайжруулдаг"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"Хязгаартай"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Хязгааргүй"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Логгерын буферын хэмжээ"</string> @@ -300,8 +304,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Модем болгох техник хангамжийн хурдасгуурыг боломжтой тохиолдолд ашиглах"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB дебаг хийхийг зөвшөөрөх үү?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB дебаг нь зөвхөн хөгжүүлэлтийн зорилготой. Үүнийг өөрийн компьютер болон төхөөрөмжийн хооронд өгөгдөл хуулах, өөрийн төхөөрөмж дээр мэдэгдэлгүйгээр аппликейшн суулгах, лог датаг унших зэрэгт ашиглаж болно."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Утасгүй алдаа засахыг зөвшөөрөх үү?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Утасгүй алдаа засах нь зөвхөн хөгжүүлэлтийн зориулалттай. Үүнийг компьютер болон төхөөрөмж хооронд өгөгдөл хуулах, төхөөрөмждөө мэдэгдэлгүйгээр аппууд суулгах болон лог өгөгдлийг унших зэрэгт ашиглана уу."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Wireless debugging-г зөвшөөрөх үү?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Wireless debugging нь зөвхөн хөгжүүлэлтийн зориулалттай. Үүнийг компьютер болон төхөөрөмж хооронд өгөгдөл хуулах, төхөөрөмждөө мэдэгдэлгүйгээр аппууд суулгах болон лог өгөгдлийг унших зэрэгт ашиглана уу."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Таны өмнө нь зөвшөөрөл өгсөн бүх компьютерээс USB дебаг хандалтыг нь хураах уу?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Хөгжлийн тохиргоог зөвшөөрөх үү?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Эдгээр тохиргоо нь зөвхөн хөгжүүлэлтэд ашиглах зорилготой. Эдгээр нь таны төхөөрөмж буюу түүн дээрх аппликейшнүүдийг эвдрэх, буруу ажиллах шалтгаан нь болж болно."</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Апп хариу өгөхгүй байна гэсэн харилцах цонхыг цаана байгаа аппад харуулах"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Мэдэгдлийн сувгийн анхааруулгыг харуулах"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Апп хүчинтэй суваггүйгээр мэдэгдэл гаргах үед дэлгэцэд сануулга харуулна"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Харилцан ярианы мэдэгдлийн товчлолыг хэрэгжүүлэх"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Харилцан ярианы хэсэгт харуулахын тулд санах ойд хадгалсан хуваалцах товчлолоор мэдэгдлийг нөөцлөхийг шаардах"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Аппыг гадаад санах ойд хадгалахыг зөвшөөрөх"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Манифест утгыг нь үл хамааран дурын апп-г гадаад санах ойд бичих боломжтой болгодог"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Үйл ажиллагааны хэмжээг өөрчилж болохуйц болгох"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index c222bd353890..749f6ee5cf41 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"वायरलेस डीबगिंग"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"उपलब्ध डिव्हाइस पाहण्यासाठी आणि वापरण्यासाठी वायरलेस डीबगिंग सुरू करा"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR कोडसह डिव्हाइस जोडा"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR कोड स्कॅनर वापरून नवीन डिव्हाइस जोडा"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR कोड स्कॅनर वापरून नवीन डिव्हाइस पेअर करा"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"पेअरींग कोडसह डिव्हाइस जोडा"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"सहा अंकी कोड वापरून नवीन डिव्हाइस जोडा"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"पेअर केलेले डिव्हाइस"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"डिव्हाइस पेअर करता आले नाही. QR कोड चुकीचा होता किंवा डिव्हाइस समान नेटवर्कशी कनेक्ट केलेले नाही."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"आयपी अॅड्रेस आणि पोर्ट"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR कोड स्कॅन करा"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR कोड स्कॅन करून वाय-फाय वापरून डिव्हाइस पेअर करा"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR कोड स्कॅन करून वाय-फाय वरून डिव्हाइस पेअर करा"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"कृपया एका वाय-फाय नेटवर्कशी कनेक्ट करा"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"ADB, डीबग, डेव्हलपर"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"बग रिपोर्ट शॉर्टकट"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"वायरलेस डिस्प्ले प्रमाणीकरण"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"वाय-फाय व्हर्बोझ लॉगिंग सुरू करा"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"वाय-फाय स्कॅन थ्रॉटलिंग"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"मोबाइल डेटा नेहमी सक्रिय"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"टेदरिंग हार्डवेअर प्रवेग"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नावांशिवाय ब्लूटूथ डिव्हाइस दाखवा"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"वायरलेस डिस्प्ले प्रमाणिकरणाचे पर्याय दाखवा"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"वाय-फाय लॉगिंग स्तर वाढवा, वाय-फाय सिलेक्टरमध्ये प्रति SSID RSSI दर्शवा"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"बॅटरी जलदरीतीने संपण्यापासून रोखते आणि नेटवर्क परफॉर्मन्समध्ये सुधारणा करते"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"मीटरने मोजलेले"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"मीटरने न मोजलेले"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"लॉगर बफर आकार"</string> @@ -301,7 +305,7 @@ <string name="adb_warning_title" msgid="7708653449506485728">"USB डीबग करण्यास अनुमती द्यायची?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB डीबग करण्याचा हेतू फक्त विकास उद्देशांसाठी आहे. याचा वापर तुमचा कॉंप्युटर आणि तुमचे डिव्हाइस यांच्या दरम्यान डेटा कॉपी करण्यासाठी करा, सूचनेशिवाय तुमच्या डिव्हाइस वर अॅप्स इंस्टॉल करा आणि लॉग डेटा वाचा."</string> <string name="adbwifi_warning_title" msgid="727104571653031865">"वायरलेस डीबगिंग करण्याची अनुमती द्यायची आहे का?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"वायरलेस डीबग करण्याचा हेतू फक्त विकास उद्देशांसाठी आहे. याचा वापर तुमचा कॉंप्युटर आणि तुमचे डिव्हाइस यांच्या दरम्यान डेटा कॉपी करण्यासाठी करा, सूचनेशिवाय तुमच्या डिव्हाइसवर अॅप्स इंस्टॉल करा आणि लॉग डेटा वाचा."</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"वायरलेस डीबगिंग करण्याचा हेतू फक्त विकास उद्देशांसाठी आहे. याचा वापर तुमचा कॉंप्युटर आणि तुमचे डिव्हाइस यांच्या दरम्यान डेटा कॉपी करण्यासाठी करा, सूचनेशिवाय तुमच्या डिव्हाइसवर अॅप्स इंस्टॉल करा आणि लॉग डेटा वाचा."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"तुम्ही पूर्वी ऑथोराइझ केलेल्या सर्व संगणकांवरुन USB डीबग करण्यासाठी अॅक्सेस रीव्होक करायचा?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"विकास सेटिंग्जला अनुमती द्यायची?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"या सेटिंग्जचा हेतू फक्त विकास वापरासाठी आहे. त्यामुळे तुमचे डिव्हाइस आणि त्यावरील ॲप्लिकेशन ब्रेक होऊ शकतात किंवा नेहमीपेक्षा वेगळे वर्तन करू शकतात."</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"बॅकग्राउंड अॅप्ससाठी अॅप प्रतिसाद देत नाही दाखवते"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"सूचना चॅनेल चेतावण्या दाखवा"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"एखादे अॅप वैध चॅनेलशिवाय सूचना पोस्ट करते तेव्हा स्क्रीनवर चेतावणी देते"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"संभाषण सूचना शॉर्टकट ठेवा"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"सूचनांना जुन्या शॉर्टकटचा सपोर्ट आवश्यक"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"बाह्यवर ॲप्सना अनुमती देण्याची सक्ती करा"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"manifest मूल्यांकडे दुर्लक्ष करून, कोणत्याही ॲपला बाह्य स्टोरेजवर लेखन केले जाण्यासाठी पात्र बनविते"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"ॲक्टिव्हिटीचा आकार बदलण्यायोग्य होण्याची सक्ती करा"</string> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index 1dc3dc4fbdb2..09a558db495f 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -155,7 +155,7 @@ <string name="launch_defaults_some" msgid="3631650616557252926">"Beberapa lalai ditetapkan"</string> <string name="launch_defaults_none" msgid="8049374306261262709">"Tiada lalai ditetapkan"</string> <string name="tts_settings" msgid="8130616705989351312">"Tetapan teks kepada pertuturan"</string> - <string name="tts_settings_title" msgid="7602210956640483039">"Output teks ke pertuturan"</string> + <string name="tts_settings_title" msgid="7602210956640483039">"Output teks kepada pertuturan"</string> <string name="tts_default_rate_title" msgid="3964187817364304022">"Kadar pertuturan"</string> <string name="tts_default_rate_summary" msgid="3781937042151716987">"Kelajuan pertuturan teks"</string> <string name="tts_default_pitch_title" msgid="6988592215554485479">"Pic"</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Penyahpepijatan wayarles"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Untuk melihat dan menggunakan peranti yang tersedia, hidupkan penyahpepijatan wayarles"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Gandingkan peranti dengan kod QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Gandingkan peranti baharu menggunakan Pengimbas kod QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Gandingkan peranti baharu menggunakan pengimbas kod QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Gandingkan peranti dengan kod gandingan"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Gandingkan peranti baharu menggunakan kod enam digit"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Peranti gandingan"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Gagal menggandingkan peranti. Kod QR salah atau peranti tidak disambungkan kepada rangkaian yang sama."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Alamat IP & Port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Imbas kod QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Gandingkan peranti melalui Wi-Fi dengan mengimbas Kod QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Gandingkan peranti melalui Wi-Fi dengan mengimbas kod QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Sila sambungkan kepada rangkaian Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Pintasan laporan pepijat"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Pensijilan paparan wayarles"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Dayakan Pengelogan Berjela-jela Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Pendikitan pengimbasan Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Perawakan MAC dipertingkat Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Data mudah alih sentiasa aktif"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Pecutan perkakasan penambatan"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tunjukkan peranti Bluetooth tanpa nama"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Tunjukkan pilihan untuk pensijilan paparan wayarles"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tingkatkan tahap pengelogan Wi-Fi, tunjuk setiap SSID RSSI dalam Pemilih Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Mengurangkan penyusutan bateri & meningkatkan prestasi rangkaian"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Togol ini melibatkan gelagat perawakan MAC untuk mod pelanggan sahaja.\nApabila mod ini diaktifkan, alamat MAC bagi mana-mana rangkaian yang telah mendayakan perawakan MAC mungkin dirawakkan semula semasa perkaitan, bergantung pada kali terakhir pelanggan diputuskan sambungan daripada rangkaian. Perawakan semula tidak berlaku jika peranti menyambung semula dalam tempoh 4 jam atau kurang."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Bermeter"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Tidak bermeter"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Saiz penimbal pengelog"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Paparkan dialog Apl Tiada Respons untuk apl latar belakang"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Papar amaran saluran pemberitahuan"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Memaparkan amaran pada skrin apabila apl menyiarkan pemberitahuan tanpa saluran sah"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Kuat kuasakan pintasan utk pemberitahuan perbualan"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Perlukan pemberitahuan disokong oleh pintasan perkongsian hayat panjang untuk muncul dalam bahagian perbualan"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Benarkan apl secara paksa pada storan luaran"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Menjadikan sebarang apl layak ditulis ke storan luaran, tanpa mengambil kira nilai manifes"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Paksa aktiviti supaya boleh diubah saiz"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index e6ebaf9afb13..b525a0a146c4 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -116,7 +116,7 @@ <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ချိတ်တွဲရန်"</string> <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"မလုပ်တော့"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"ချိတ်တွဲမှုက ချိတ်ဆက်ထားလျှင် သင်၏ အဆက်အသွယ်များ နှင့် ခေါ်ဆိုမှု မှတ်တမ်းကို ရယူခွင့် ပြုသည်။"</string> - <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>နှင့် တွဲချိတ်မရပါ"</string> + <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> နှင့် တွဲချိတ်မရပါ"</string> <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"ပင်နံပါတ် သို့မဟုတ် ဖြတ်သန်းခွင့်ကီးမမှန်ကန်သောကြောင့်<xliff:g id="DEVICE_NAME">%1$s</xliff:g>နှင့် တွဲချိတ်မရပါ။"</string> <string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>နှင့်ဆက်သွယ်မရပါ"</string> <string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>နှင့်တွဲချိတ်ရန် ပယ်ချခံရသည်"</string> @@ -212,12 +212,12 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"ကြိုးမဲ့ အမှားရှာပြင်ခြင်း"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ရနိုင်သည့် စက်ပစ္စည်းများကို ကြည့်ပြီး အသုံးပြုနိုင်ရန် ကြိုးမဲ့ အမှားရှာပြင်ခြင်းကို ဖွင့်ပါ"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR ကုဒ်ဖြင့် စက်ပစ္စည်းကို အတူတွဲပါ"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR ကုဒ်ဖတ်စက် သုံး၍ စက်ပစ္စည်းသစ်များကို အတူတွဲပါ"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR ကုဒ် စကင်ဖတ်စက် သုံး၍ စက်အသစ်များကို အတူတွဲနိုင်သည်"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"တွဲချိတ်ကုဒ်ဖြင့် စက်ပစ္စည်းကို အတူတွဲပါ"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ဂဏန်းခြောက်လုံးကုဒ်ဖြင့် စက်ပစ္စည်းသစ်များကို အတူတွဲပါ"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"တွဲချိတ်ပြီး စက်ပစ္စည်းများ"</string> <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"လက်ရှိ ချိတ်ဆက်ထားသည်"</string> - <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"စက်ပစ္စည်း အသေးစိတ်"</string> + <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"စက်အသေးစိတ်များ"</string> <string name="adb_device_forget" msgid="193072400783068417">"မေ့ပစ်ရန်"</string> <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"စက်ပစ္စည်း လက်ဗွေ- <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string> <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"ချိတ်ဆက်ခြင်း မအောင်မြင်ပါ"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"စက်ပစ္စည်းကို အတူတွဲ၍မရပါ။ QR ကုဒ်မမှန်ပါ သို့မဟုတ် စက်ပစ္စည်းသည် ကွန်ရက်တစ်ခုတည်းသို့ ချိတ်ဆက်မထားပါ။"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"အိုင်ပီ (IP) လိပ်စာနှင့် ပို့တ်"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR ကုဒ်ကို စကင်ဖတ်ပါ"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR ကုဒ် စကင်ဖတ်ခြင်းဖြင့် Wi-Fi ပေါ်တွင် စက်ပစ္စည်းကို အတူတွဲပါ"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR ကုဒ် စကင်ဖတ်ခြင်းဖြင့် Wi-Fi ပေါ်တွင် စက်ကို အတူတွဲနိုင်သည်"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Wi-Fi ကွန်ရက်သို့ ချိတ်ဆက်ပါ"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ချွတ်ယွင်းမှု အစီရင်ခံရန် ဖြတ်လမ်း"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"ကြိုးမဲ့ပြသမှု အသိအမှတ်ပြုလက်မှတ်"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi Verbose မှတ်တမ်းတင်ခြင်းအား ဖွင့်မည်"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi ရှာဖွေခြင်း ထိန်းချုပ်မှု"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi တိုးမြှင့် MAC ကျပန်းပြုလုပ်ခြင်း"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"မိုဘိုင်းဒေတာကို အမြဲဖွင့်ထားရန်"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"ဖုန်းကို မိုဒမ်အဖြစ်အသုံးပြုမှု စက်ပစ္စည်းဖြင့် အရှိန်မြှင့်တင်ခြင်း"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"အမည်မရှိသော ဘလူးတုသ်စက်ပစ္စည်းများကို ပြသရန်"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ကြိုးမဲ့ အခင်းအကျင်း အသိအမှတ်ပြုလက်မှတ်အတွက် ရွေးချယ်စရာများပြရန်"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi မှတ်တမ်းတင်ခြင်း နှုန်းအားမြင့်ကာ၊ Wi‑Fi ရွေးရာတွင် SSID RSSI ဖြင့်ပြပါ"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ဘက်ထရီ အသုံးပြုမှုကို လျှော့ကျစေပြီး ကွန်ရက်စွမ်းဆောင်ရည်ကို ပိုမိုကောင်းမွန်စေသည်"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"ဤဖွင့်ပိတ်ခလုတ်က ကလိုင်းယင့်မုဒ် အတွက်သာ MAC ကျပန်းပြုလုပ်ခြင်း အပြုအမူကို သက်ရောက်စေသည်။\nဤမုဒ်အသုံးပြုသည့်အခါ MAC ကျပန်းပြုလုပ်ခြင်း ဖွင့်ထားသော ကွန်ရက်များသည် ကွန်ရက်မှ ကလိုင်းယင့် ချိတ်ဆက်မှုဖြုတ်သည့် နောက်ဆုံးအချိန်ပေါ် မူတည်၍ ချိတ်ဆက်နေစဉ်အတွင်း ၎င်းတို့၏ MAC လိပ်စာများကို ပြန်လည်ကျပန်းပြုလုပ်နိုင်သည်။ စက်သည် ၄ နာရီအတွင်း ပြန်ချိန်ဆက်ထားပါက ပြန်လည်ကျပန်းပြုလုပ်မည် မဟုတ်ပါ။"</string> <string name="wifi_metered_label" msgid="8737187690304098638">"အခမဲ့ မဟုတ်ပါ"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"အခမဲ့"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"မှတ်တမ်းကြားခံနယ် အရွယ်အစားများ"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"နောက်ခံ အက်ပ်များအတွက် \'အက်ပ်တုံ့ပြန်မှုမရှိ\' ဟု ပြရန်"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"ချန်နယ်သတိပေးချက်များပြပါ"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ချန်နယ်မရှိဘဲ အကြောင်းကြားလျှင် စကရင်တွင်သတိပေးသည်"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ဖြတ်လမ်းလင့်ခ် သုံးရန်"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"အချိန်ကြာမျှဝေသော ဖြတ်လမ်းလင့်ခ် သုံးရန် လိုအပ်သည်"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"ပြင်ပစက်တွင် အက်ပ်များခွင့်ပြုရန်"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"တိကျစွာ သတ်မှတ်ထားသည့်တန်ဖိုးများရှိသော်လည်း၊ ပြင်ပသိုလှောင်ခန်းများသို့ မည်သည့်အက်ပ်ကိုမဆို ဝင်ရောက်ခွင့်ပြုပါ"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"လုပ်ဆောင်ချက်များ အရွယ်ပြောင်းနိုင်ခြင်း"</string> @@ -464,7 +468,7 @@ <item msgid="7529124349186240216">"၁၀၀%"</item> </string-array> <string name="charge_length_format" msgid="6941645744588690932">"ပြီးခဲ့သည့် <xliff:g id="ID_1">%1$s</xliff:g> က"</string> - <string name="remaining_length_format" msgid="4310625772926171089">"<xliff:g id="ID_1">%1$s</xliff:g> ကျန်ပါသည်"</string> + <string name="remaining_length_format" msgid="4310625772926171089">"<xliff:g id="ID_1">%1$s</xliff:g> ကျန်"</string> <string name="screen_zoom_summary_small" msgid="6050633151263074260">"သေး"</string> <string name="screen_zoom_summary_default" msgid="1888865694033865408">"မူရင်း"</string> <string name="screen_zoom_summary_large" msgid="4706951482598978984">"ကြီး"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 58213a7cef04..cc883ab1e63d 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -112,7 +112,7 @@ <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Bruk til filoverføring"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Bruk for inndata"</string> <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Bruk for høreapparater"</string> - <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Sammenkoble"</string> + <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Koble til"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"KOBLE TIL"</string> <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Avbryt"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Med sammenkobling får den andre enheten tilgang til kontaktene og anropsloggen din når den er tilkoblet."</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Trådløs feilsøking"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"For å se og bruke tilgjengelige enheter, slå på trådløs feilsøking"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Koble til enheten med en QR-kode"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Koble til nye enheter med en QR-kodeskanner"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Koble til nye enheter med en QR-kodeskanner"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Koble til enheten med en tilkoblingskode"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Koble til nye enheter med en sekssifret kode"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Tilkoblede enheter"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Kunne ikke koble til enheten. Enten var QR-koden feil, eller enheten er ikke koblet til samme nettverk."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adresse og port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skann QR-koden"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Koble til enheten via Wi-Fi ved å skanne en QR-kode"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Koble til enheten via Wi-Fi ved å skanne en QR-kode"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Koble til et Wi-Fi-nettverk"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, feilsøking, utvikler"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Snarvei til feilrapport"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Trådløs skjermsertifisering"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Slå på detaljert Wi-Fi-loggføring"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Begrensning av Wi‑Fi-skanning"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi‑forbedret MAC-tilfeldiggjøring"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobildata er alltid aktiv"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Maskinvareakselerasjon for internettdeling"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheter uten navn"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vis alternativer for sertifisering av trådløs skjerm"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Øk Wi-Fi-loggenivå – vis per SSID RSSI i Wi-Fi-velgeren"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduserer batteriforbruket og forbedrer nettverksytelsen"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Denne av/på-bryteren påvirker bare atferden til MAC-tilfeldiggjøring for klientmodus.\nNår denne modusen er aktivert, kan nettverk som har tilfeldig valgt MAC, få MAC-adressen tilfeldig valgt på nytt under tilknytning, avhengig av når klienten sist ble koblet fra nettverket. Ny tilfeldiggjøring oppstår ikke hvis enheten kobler seg til igjen innen fire timer."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Med datamåling"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Uten datamåling"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Bufferstørrelser for logg"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Vis Appen svarer ikke-dialog for bakgrunnsapper"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Vis varselskanaladvarsler"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Viser advarsler på skjermen når apper publiserer varsler uten en gyldig kanal"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Håndhev snarveier for samtalevarsler"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Krev at varsler støttes av en langvarig delingssnarvei for å vises i samtaledelen"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Tving frem tillatelse for ekstern lagring av apper"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Dette gjør at alle apper kan lagres på eksterne lagringsmedier – uavhengig av manifestverdier"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Tving aktiviteter til å kunne endre størrelse"</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index cc26483b791b..eaac303d86c8 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"USB डिबग गर्दै"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"USB जडित हुँदा डिबग मोड"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB डिबग गर्ने प्राधिकरणहरू उल्टाउनुहोस्"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"वायरलेस डिबग गर्ने प्रक्रिया"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"वायरलेस डिबगिङ"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi मा जोडिँदा डिबग मोड सक्षम पार्ने कि नपार्ने"</string> <string name="adb_wireless_error" msgid="721958772149779856">"त्रुटि"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"वायरलेस डिबग गर्ने प्रक्रिया"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"उपलब्ध यन्त्रहरू हेर्न र प्रयोग गर्न वायरलेस डिबग गर्ने प्रक्रिया सक्रिय गर्नुहोस्"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"वायरलेस डिबगिङ"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"उपलब्ध यन्त्रहरू हेर्न र प्रयोग गर्न वायरलेस डिबगिङ सेवा सक्रिय गर्नुहोस्"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR कोडमार्फत यन्त्रको जोडा बनाउनुहोस्"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR कोड स्क्यानर प्रयोग गरी नयाँ यन्त्रहरूको जोडा बनाउनुहोस्"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR कोड स्क्यानर प्रयोग गरी नयाँ यन्त्रहरूको जोडा बनाउनुहोस्"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"जोडा मिलाउने कोडमार्फत यन्त्रको जोडा बनाउनुहोस्"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"छ अङ्कको कोड प्रयोग गरी नयाँ यन्त्रहरूको जोडा बनाउनुहोस्"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"जोडा बनाइएका यन्त्रहरू"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"यन्त्रसँग जोडा बनाउन सकिएन। कि त QR कोड गलत छ कि यन्त्र उही नेटवर्कमा जोडिएको छैन।"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ठेगाना र पोर्ट"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR कोड स्क्यान गर्नुहोस्"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR कोड स्क्यान गरेर Wi‑Fi प्रयोग गरी यन्त्रको जोडा बनाउनुहोस्"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR कोड स्क्यान गरी Wi‑Fi मार्फत यन्त्रको जोडा बनाउनुहोस्"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"कृपया कुनै Wi-Fi मा कनेक्ट गर्नुहोस्"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"बग प्रतिवेदन सर्टकट"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"ताररहित प्रदर्शन प्रमाणीकरण"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi-Fi वर्बोज लग सक्षम पार्नुहोस्"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi स्क्यान थ्रोटलिङ"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"मोबाइल डेटा सधैँ सक्रिय राख्नुहोस्"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"टेदरिङको लागि हार्डवेयरको प्रवेग"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नामकरण नगरिएका ब्लुटुथ यन्त्रहरू देखाउनुहोस्"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi लग स्तर बढाउनुहोस्, Wi-Fi चयनकर्तामा प्रति SSID RSSI देखाइन्छ"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ब्याट्रीको खपत कम गरी नेटवर्कको कार्यसम्पादनमा सुधार गर्दछ"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"सशुल्क वाइफाइ"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"मिटर नगरिएको"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"लगर बफर आकारहरू"</string> @@ -300,8 +304,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"उपलब्ध भएमा टेदरिङको लागि हार्डवेयरको प्रवेग प्रयोग गर्नुहोस्"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB डिबग गर्न लागि अनुमति दिने हो?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"युएसबी डिबगिङ विकास प्रयोजनका लागि मात्र निर्मित हुन्छ। यसलाई तपाईँको कम्प्युटर र तपाईँको उपकरणका बीच डेटा प्रतिलिपि गर्न, बिना सूचना तपाईँको उपकरणमा अनुप्रयोगहरू स्थापना गर्न र लग डेटा पढ्नका लागि प्रयोग गर्नुहोस्।"</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"वायरलेस डिबग गर्ने प्रक्रिया सक्षम पार्ने हो?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"वायरलेस डिबग गर्ने प्रक्रिया विकास प्रयोजनका लागि मात्रै हो। यसलाई आफ्ना कम्प्युटर र उपकरणका बिच डेटा प्रतिलिपि गर्न, सूचना नदिई आफ्नो उपकरणमा अनुप्रयोगहरू स्थापना गर्न र लगसम्बन्धी डेटा रिड गर्नका लागि प्रयोग गर्नुहोस्।"</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"वायरलेस डिबगिङ सेवा सक्षम पार्ने हो?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"वायरलेस डिबगिङ डिभलपमेन्ट प्रयोजनका लागि मात्रै हो। यसलाई आफ्ना कम्प्युटर र उपकरणका बिच डेटा प्रतिलिपि गर्न, सूचना नदिई आफ्नो उपकरणमा अनुप्रयोगहरू स्थापना गर्न र लग डेटा पढ्न प्रयोग गर्नुहोस्।"</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"तपाईं पहिले नै अधिकृत गर्नुभएका सबै कम्प्यूटरबाट USB डिबग गर्नको लागि पहुँच रद्द गर्ने हो?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"विकास सेटिङहरू अनुमति दिने हो?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"यी सेटिङहरू केवल विकास प्रयोगको लागि विचार गरिएको हो। तिनीहरूले तपाईंको उपकरण र अनुप्रयोगहरूलाई विच्छेदन गर्न वा दुर्व्यवहार गर्न सक्दछ।"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"पृष्ठभूमिका अनुप्रयोगहरूको संवादको प्रतिक्रिया नदिइरहेका अनुप्रयोगहरू प्रदर्शन गर्नुहोस्"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"सूचना च्यानलका चेतावनी देखाउनुहोस्"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"अनुप्रयोगले कुनै मान्य च्यानल बिना सूचना पोस्ट गर्दा स्क्रिनमा चेतावनी देखाउँछ"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"कुराकानी नामक स्थानमा मान्य सर्टकटसँग पनि लिंक गरिएका सूचनाहरू मात्र देखाइयोस्"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"कुराकानी नामक स्थानमा सूचनाहरू देखिन सकून् भन्नाका खातिर ती सूचनामा सधैँ सक्रिय रहने (long-lived) सेयरिङ सर्टकट समावेश भएको हुनु पर्छ"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"बाह्यमा बल प्रयोगको अनुमति प्राप्त अनुप्रयोगहरू"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"म्यानिफेेस्टका मानहरूको ख्याल नगरी कुनै पनि अनुप्रयोगलाई बाह्य भण्डारणमा लेख्न सकिने खाले बनाउँछ"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"आकार बदल्न योग्य हुने बनाउन गतिविधिहरूलाई बाध्यात्मक बनाउनुहोस्।"</string> @@ -467,9 +473,9 @@ <string name="remaining_length_format" msgid="4310625772926171089">"<xliff:g id="ID_1">%1$s</xliff:g> बाँकी"</string> <string name="screen_zoom_summary_small" msgid="6050633151263074260">"सानो"</string> <string name="screen_zoom_summary_default" msgid="1888865694033865408">"पूर्वनिर्धारित"</string> - <string name="screen_zoom_summary_large" msgid="4706951482598978984">"ठूलो"</string> - <string name="screen_zoom_summary_very_large" msgid="7317423942896999029">"अझ ठूलो"</string> - <string name="screen_zoom_summary_extremely_large" msgid="1438045624562358554">"सबैभन्दा ठूलो"</string> + <string name="screen_zoom_summary_large" msgid="4706951482598978984">"ठुलो"</string> + <string name="screen_zoom_summary_very_large" msgid="7317423942896999029">"अझ ठुलो"</string> + <string name="screen_zoom_summary_extremely_large" msgid="1438045624562358554">"सबैभन्दा ठुलो"</string> <string name="screen_zoom_summary_custom" msgid="3468154096832912210">"आफू अनुकूल (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string> <string name="content_description_menu_button" msgid="6254844309171779931">"मेनु"</string> <string name="retail_demo_reset_message" msgid="5392824901108195463">"डेमो मोडमा फ्याक्ट्री रिसेट गर्न पासवर्ड प्रविष्टि गर्नुहोस्"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 57fc87aa8d6f..c566dc23d2b0 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Draadloze foutopsporing"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Schakel draadloze foutopsporing in om beschikbare apparaten te bekijken en te gebruiken"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Apparaat koppelen met QR-code"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Nieuwe apparaten koppelen via QR-codescanner"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Nieuwe apparaten koppelen via QR-codescanner"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Apparaat koppelen met koppelingscode"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Nieuwe apparaten koppelen via een zescijferige code"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Gekoppelde apparaten"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Kan het apparaat niet koppelen. De QR-code was onjuist of het apparaat is niet verbonden met hetzelfde netwerk."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adres en poort"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR-code scannen"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Apparaat koppelen via wifi door een QR-code te scannen"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Apparaat koppelen via wifi door een QR-code te scannen"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Maak verbinding met een wifi-netwerk"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, foutopsporing, ontwikkeling"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Snelle link naar bugrapport"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certificering van draadloze weergave"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Uitgebreide wifi-logregistratie insch."</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wifi-scannen beperken"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Via wifi ondersteunde MAC-herschikking"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobiele data altijd actief"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardwareversnelling voor tethering"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-apparaten zonder namen weergeven"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Opties weergeven voor certificering van draadloze weergave"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verlaagt het batterijverbruik en verbetert de netwerkprestaties"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Deze schakelaar beïnvloedt het gedrag van MAC-herschikking uitsluitend voor de clientmodus.\nAls deze modus is ingeschakeld, worden de MAC-adressen van netwerken die MAC-herschikking hebben ingeschakeld, mogelijk opnieuw in willekeurige volgorde herschikt als verbinding wordt gemaakt. Dit is afhankelijk van wanneer de client voor het laatst de verbinding met het netwerk verbrak. Opnieuw herschikken gebeurt niet als het apparaat binnen vier uur opnieuw verbinding maakt."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Met datalimiet"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Gratis"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Logger-buffergrootten"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Dialoogvenster \'App reageert niet\' weergeven voor achtergrond-apps"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Kanaalwaarschuwingen voor meldingen weergeven"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Geeft een waarschuwing op het scherm weer wanneer een app een melding post zonder geldig kanaal"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Snelkoppelingen voor gespreksmeldingen afdwingen"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Vereisen dat meldingen een langdurige snelkoppeling voor delen krijgen om bij gesprekken te kunnen worden getoond"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Toestaan van apps op externe opslag afdwingen"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Hiermee komt elke app in aanmerking voor schrijven naar externe opslag, ongeacht de manifestwaarden"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Formaat activiteiten geforceerd aanpasbaar maken"</string> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index 3a7f2c5acaa6..f14d67f262a7 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -86,7 +86,7 @@ <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍"</string> <string name="bluetooth_profile_hid" msgid="2969922922664315866">"ଇନ୍ପୁଟ୍ ଡିଭାଇସ୍"</string> <string name="bluetooth_profile_pan" msgid="1006235139308318188">"ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍"</string> - <string name="bluetooth_profile_pbap" msgid="7064307749579335765">"ଯୋଗାଯୋଗ ସେୟାରିଙ୍ଗ୍"</string> + <string name="bluetooth_profile_pbap" msgid="7064307749579335765">"ଯୋଗାଯୋଗ ସେୟାରିଂ"</string> <string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"ଯୋଗାଯୋଗ ସେୟାର୍ କରିବା ପାଇଁ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ଶେୟାରିଙ୍ଗ"</string> <string name="bluetooth_profile_map" msgid="8907204701162107271">"ଟେକ୍ସଟ୍ ମେସେଜ୍"</string> @@ -126,7 +126,7 @@ <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ଇମେଜିଙ୍ଗ"</string> <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"ହେଡ୍ଫୋନ୍"</string> <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ଇନ୍ପୁଟ୍ ଉପକରଣ"</string> - <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ବ୍ଲୁଟୂଥ୍"</string> + <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ବ୍ଲୁଟୁଥ"</string> <string name="bluetooth_hearingaid_left_pairing_message" msgid="8561855779703533591">"ବାମ ଶ୍ରବଣ ଯନ୍ତ୍ର ପେୟାର୍ କରାଯାଉଛି…"</string> <string name="bluetooth_hearingaid_right_pairing_message" msgid="2655347721696331048">"ଡାହାଣ ଶ୍ରବଣ ଯନ୍ତ୍ର ପେୟାର୍ କରାଯାଉଛି…"</string> <string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"ବାମ - <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବ୍ୟାଟେରୀ"</string> @@ -143,10 +143,10 @@ <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"କଢ଼ାଯାଇଥିବା ଆପ୍ଗୁଡ଼ିକ"</string> <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"ଆପ୍ ଏବଂ ଉପଯୋଗକର୍ତ୍ତା ବାହାର କରାଗଲା"</string> <string name="data_usage_ota" msgid="7984667793701597001">"ସିଷ୍ଟମ୍ ଅପ୍ଡେଟ୍"</string> - <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB ଟିଥରିଙ୍ଗ"</string> + <string name="tether_settings_title_usb" msgid="3728686573430917722">"USB ଟିଥରିଂ"</string> <string name="tether_settings_title_wifi" msgid="4803402057533895526">"ପୋର୍ଟବଲ୍ ହଟସ୍ପଟ୍"</string> - <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"ବ୍ଲୁଟୂଥ ଟିଥରିଙ୍ଗ"</string> - <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"ଟିଥର୍ କରୁଛି"</string> + <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"ବ୍ଲୁଟୁଥ ଟିଥରିଂ"</string> + <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"ଟିଥରିଂ"</string> <string name="tether_settings_title_all" msgid="8910259483383010470">"ଟିଥରିଙ୍ଗ ଓ ପୋର୍ଟବଲ୍ ହଟ୍ସ୍ପଟ୍"</string> <string name="managed_user_title" msgid="449081789742645723">"ସମସ୍ତ କାର୍ଯ୍ୟ ଆପ୍"</string> <string name="user_guest" msgid="6939192779649870792">"ଅତିଥି"</string> @@ -206,13 +206,14 @@ <string name="enable_adb" msgid="8072776357237289039">"USB ଡିବଗ୍ ହେଉଛି"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"USB ସଂଯୁକ୍ତ ହେବାବେଳେ ଡିବଗ୍ ମୋଡ୍"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB ଡିବଗିଙ୍ଗ ଅଧିକାରକୁ କାଢ଼ିଦିଅନ୍ତୁ"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"ୱେୟାରଲେସ୍ ଡିବଗିଂ"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"ୱାୟାରଲେସ୍ ଡିବଗିଂ"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"ୱାଇ-ଫାଇ ସଂଯୁକ୍ତ ଥିବା ବେଳେ ଡିବଗ୍ ମୋଡ୍"</string> <string name="adb_wireless_error" msgid="721958772149779856">"ତ୍ରୁଟି"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"ୱେୟାରଲେସ୍ ଡିବଗିଂ"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ଉପଲବ୍ଧ ଡିଭାଇସଗୁଡ଼ିକୁ ଦେଖିବାକୁ ଏବଂ ବ୍ୟବହାର କରିବାକୁ ୱେୟାରଲେସ୍ ଡିବଗିଂ ଚାଲୁ କରନ୍ତୁ"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"ୱାୟାରଲେସ୍ ଡିବଗିଂ"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ଉପଲବ୍ଧ ଡିଭାଇସଗୁଡ଼ିକୁ ଦେଖିବାକୁ ଏବଂ ବ୍ୟବହାର କରିବାକୁ ୱାୟାରଲେସ୍ ଡିବଗିଂ ଚାଲୁ କରନ୍ତୁ"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR କୋଡରେ ଡିଭାଇସକୁ ପେୟାର୍ କରନ୍ତୁ"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR କୋଡ୍ ସ୍କାନର୍ ବ୍ୟବହାର କରି ନୂଆ ଡିଭାଇସଗୁଡ଼ିକୁ ପେୟାର୍ କରନ୍ତୁ"</string> + <!-- no translation found for adb_pair_method_qrcode_summary (7130694277228970888) --> + <skip /> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"ପେୟାରିଂ କୋଡରେ ଡିଭାଇସକୁ ପେୟାର୍ କରନ୍ତୁ"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ଛଅ ଡିଜିଟ୍ କୋଡ୍ ବ୍ୟବହାର କରି ନୂଆ ଡିଭାଇସଗୁଡ଼ିକୁ ପେୟାର୍ କରନ୍ତୁ"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"ପେୟାର୍ ହୋଇଥିବା ଡିଭାଇସଗୁଡ଼ିକ"</string> @@ -231,7 +232,8 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"ଡିଭାଇସରୁ ପେୟାର୍ ହେବାରେ ବିଫଳ ହୋଇଛି। QR କୋଡ୍ ସଠିକ୍ ନଥିଲା ବା ଡିଭାଇସ୍ ସମାନ ନେଟୱାର୍କରେ ସଂଯୋଗ ହୋଇନାହିଁ।"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ଠିକଣା ଓ ପୋର୍ଟ"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR କୋଡ୍ ସ୍କାନ୍ କରନ୍ତୁ"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"ଏକ QR କୋଡ୍ ସ୍କାନ୍ କରି ୱାଇ-ଫାଇରେ ଡିଭାଇସ୍ ପେୟାର୍ କରନ୍ତୁ"</string> + <!-- no translation found for adb_wireless_qrcode_pairing_description (6014121407143607851) --> + <skip /> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"ଦୟାକରି ଏକ ୱାଇ-ଫାଇ ନେଟୱାର୍କରେ ସଂଯୋଗ କରନ୍ତୁ"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ଡିବଗ୍, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ବଗ୍ ରିପୋର୍ଟ ସର୍ଟକଟ୍"</string> @@ -251,6 +253,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"ୱାୟରଲେସ୍ ଡିସ୍ପ୍ଲେ ସାର୍ଟିଫିକେସନ୍"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"ୱାଇ-ଫାଇ ଭର୍ବୋସ୍ ଲଗିଙ୍ଗ ସକ୍ଷମ କରନ୍ତୁ"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"ୱାଇ-ଫାଇ ସ୍କାନ୍ ନିୟନ୍ତ୍ରଣ"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"ମୋବାଇଲ୍ ଡାଟା ସର୍ବଦା ସକ୍ରିୟ"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"ଟିଥରିଙ୍ଗ ହାର୍ଡୱେର ଆକ୍ସିଲିରେସନ୍"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ବ୍ଲୁଟୂଥ୍ ଡିଭାଇସ୍ଗୁଡ଼ିକୁ ନାମ ବିନା ଦେଖନ୍ତୁ"</string> @@ -283,6 +287,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ୱେୟାରଲେସ୍ ଡିସ୍ପ୍ଲେ ସାର୍ଟିଫିକେସନ୍ ପାଇଁ ବିକଳ୍ପ ଦେଖାନ୍ତୁ"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ୱାଇ-ଫାଇ ଲଗିଙ୍ଗ ସ୍ତର ବଢ଼ାନ୍ତୁ, ୱାଇ-ଫାଇ ପିକର୍ରେ ପ୍ରତି SSID RSSI ଦେଖାନ୍ତୁ"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ବ୍ୟାଟେରୀ ଖର୍ଚ୍ଚ କମ୍ ଏବଂ ନେଟ୍ୱାର୍କ କାର୍ଯ୍ୟକ୍ଷମତା ଉନ୍ନତ କରିଥାଏ"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"ମପାଯାଉଥିବା"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"ମପାଯାଉନଥିବା"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"ଲଗର୍ ବଫର୍ ସାଇଜ୍"</string> @@ -300,8 +306,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"ଯଦି ଉପଲବ୍ଧ ଥାଏ, ଟିଥରିଙ୍ଗ ହାର୍ଡୱେର୍ ଆକ୍ସିଲିରେସନ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB ଡିବଗିଙ୍ଗ କରିବେ?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB ଡିବଗିଂ କେବଳ ଡେଭଲପମେଣ୍ଟ ଉଦ୍ଦେଶ୍ୟ ପାଇଁ ଉଦ୍ଦିଷ୍ଟ ଅଟେ। ଆପଣଙ୍କ କମ୍ପ୍ୟୁଟର ଏବଂ ଡିଭାଇସ୍ ମଧ୍ୟରେ ଡାଟା କପି କରିବାକୁ, ବିନା ବିଜ୍ଞପ୍ତିରେ ଆପଣଙ୍କ ଡିଭାଇସରେ ଆପସ୍ ସଂସ୍ଥାପନ କରିବାକୁ, ଏବଂ ଲଗ୍ ଡାଟା ପଢିବାକୁ ଏହା ବ୍ୟବହାର କରନ୍ତୁ।"</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"ୱେୟାରଲେସ୍ ଡିବଗିଂ ପାଇଁ ଅନୁମତି ଦେବେ?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"ୱେୟାରଲେସ୍ ଡିବଗିଂ କେବଳ ଉନ୍ନତି ଉଦ୍ଦେଶ୍ୟ ପାଇଁ ଉଦ୍ଦିଷ୍ଟ ଅଟେ। ଆପଣଙ୍କ କମ୍ପ୍ୟୁଟର ଏବଂ ଡିଭାଇସ୍ ମଧ୍ୟରେ ଡାଟା କପି କରିବାକୁ, ବିନା ବିଜ୍ଞପ୍ତିରେ ଆପଣଙ୍କ ଡିଭାଇସରେ ଆପ୍ସ ଇନଷ୍ଟଲ୍ କରିବାକୁ ଏବଂ ଲଗ୍ ଡାଟା ପଢ଼ିବା ପାଇଁ ଏହାକୁ ବ୍ୟବହାର କରନ୍ତୁ।"</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"ୱାୟାରଲେସ୍ ଡିବଗିଂ ପାଇଁ ଅନୁମତି ଦେବେ?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"ୱାୟାରଲେସ୍ ଡିବଗିଂ କେବଳ ଉନ୍ନତି ପାଇଁ ଉଦ୍ଦିଷ୍ଟ ଅଟେ। ଆପଣଙ୍କ କମ୍ପ୍ୟୁଟର ଏବଂ ଡିଭାଇସ୍ ମଧ୍ୟରେ ଡାଟା କପି କରିବାକୁ, ବିନା ବିଜ୍ଞପ୍ତିରେ ଆପଣଙ୍କ ଡିଭାଇସରେ ଆପ୍ସ ଇନଷ୍ଟଲ୍ କରିବାକୁ ଏବଂ ଲଗ୍ ଡାଟା ପଢ଼ିବା ପାଇଁ ଏହାକୁ ବ୍ୟବହାର କରନ୍ତୁ।"</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"ଅଧିକୃତ ସମସ୍ତ କମ୍ପ୍ୟୁଟରରୁ USB ଡିବଗ୍ କରିବା ଆକ୍ସେସ୍ ପ୍ରତ୍ୟାହାର କରିବେ କି?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"ଡେଭଲପମେଣ୍ଟ ସେଟିଙ୍ଗ ଅନୁମତି ଦେବେ?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"ଏହି ସେଟିଙ୍ଗଗୁଡ଼ିକ କେବଳ ବିକାଶ ବ୍ୟବହାର ପାଇଁ ଉଦ୍ଦିଷ୍ଟ। ସେଗୁଡ଼ିକ କାରଣରୁ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଓ ଆପ୍ଲିକେଶନ୍ଗୁଡ଼ିକ ଠିକ୍ ଭାବେ କାମ ନକରିପାରେ।"</string> @@ -371,6 +377,10 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"ବ୍ୟାକ୍ଗ୍ରାଉଣ୍ଡ ଆପ୍ଗୁଡ଼ିକ ପାଇଁ \"ଆପ୍ ଉତ୍ତର ଦେଉନାହିଁ\" ଡାୟଲଗ୍ ଦେଖାନ୍ତୁ"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"ବିଜ୍ଞପ୍ତି ଚେନାଲ୍ ଚେତାବନୀ ଦେଖାନ୍ତୁ"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ବୈଧ ଚ୍ୟାନେଲ୍ ବିନା ଗୋଟିଏ ଆପ୍ ଏକ ବିଜ୍ଞପ୍ତି ପୋଷ୍ଟ କରିବାବେଳେ ଅନ୍-ସ୍କ୍ରୀନ୍ ସତର୍କତା ଦେଖାଏ"</string> + <!-- no translation found for enforce_shortcuts_for_conversations (7040735163945040763) --> + <skip /> + <!-- no translation found for enforce_shortcuts_for_conversations_summary (1860168037282467862) --> + <skip /> <string name="force_allow_on_external" msgid="9187902444231637880">"ଆପ୍କୁ ଏକ୍ସଟର୍ନଲ୍ ମେମୋରୀରେ ଫୋର୍ସ୍ ଅନୁମତି ଦିଅନ୍ତୁ"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"ଯେକୌଣସି ଆପ୍କୁ ଏକ୍ସଟର୍ନଲ୍ ଷ୍ଟୋରେଜ୍ରେ ଲେଖାଯୋଗ୍ୟ କରନ୍ତୁ, ମେନିଫେଷ୍ଟ ମୂଲ୍ୟ ଯାହା ହୋଇଥାଉ ନା କାହିଁକି"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"ୱିଣ୍ଡୋ ହିସାବରେ କାର୍ଯ୍ୟକଳାପର ଆକାର ବଦଳାନ୍ତୁ"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 980225710156..83046c48ad69 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -112,8 +112,8 @@ <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ ਲਈ ਵਰਤੋ"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ਇਨਪੁਟ ਲਈ ਵਰਤੋ"</string> <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"ਸੁਣਨ ਦੇ ਸਾਧਨਾਂ ਲਈ ਵਰਤੋ"</string> - <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"ਪੇਅਰ ਕਰੋ"</string> - <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ਪੇਅਰ ਕਰੋ"</string> + <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"ਜੋੜਾਬੱਧ ਕਰੋ"</string> + <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ਜੋੜਾਬੱਧ ਕਰੋ"</string> <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"ਰੱਦ ਕਰੋ"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"ਜੋੜਾਬੱਧ ਕਰਨਾ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ ਤੇ ਤੁਹਾਡੇ ਸੰਪਰਕਾਂ ਅਤੇ ਕਾਲ ਇਤਿਹਾਸ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string> <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਪੇਅਰ ਨਹੀਂ ਕਰ ਸਕਿਆ।"</string> @@ -195,7 +195,7 @@ </string-array> <string name="choose_profile" msgid="343803890897657450">"ਪ੍ਰੋਫਾਈਲ ਚੁਣੋ"</string> <string name="category_personal" msgid="6236798763159385225">"ਨਿੱਜੀ"</string> - <string name="category_work" msgid="4014193632325996115">"ਦਫ਼ਤਰ"</string> + <string name="category_work" msgid="4014193632325996115">"ਕਾਰਜ-ਸਥਾਨ"</string> <string name="development_settings_title" msgid="140296922921597393">"ਵਿਕਾਸਕਾਰ ਵਿਕਲਪ"</string> <string name="development_settings_enable" msgid="4285094651288242183">"ਵਿਕਾਸਕਾਰ ਵਿਕਲਪਾਂ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string> <string name="development_settings_summary" msgid="8718917813868735095">"ਐਪ ਵਿਕਾਸ ਲਈ ਚੋਣਾਂ ਸੈੱਟ ਕਰੋ"</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"ਵਾਇਰਲੈੱਸ ਡੀਬੱਗਿੰਗ"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ਉਪਲਬਧ ਡੀਵਾਈਸਾਂ ਨੂੰ ਦੇਖਣ ਅਤੇ ਵਰਤਣ ਲਈ, ਵਾਇਰਲੈੱਸ ਡੀਬੱਗਿੰਗ ਚਾਲੂ ਕਰੋ"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR ਕੋਡ ਨਾਲ ਡੀਵਾਈਸ ਨੂੰ ਜੋੜਾਬੱਧ ਕਰੋ"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR ਕੋਡ ਸਕੈਨਰ ਵਰਤ ਕੇ ਨਵੇਂ ਡੀਵਾਈਸਾਂ ਨੂੰ ਜੋੜਾਬੱਧ ਕਰੋ"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR ਕੋਡ ਸਕੈਨਰ ਵਰਤ ਕੇ ਨਵੇਂ ਡੀਵਾਈਸਾਂ ਨੂੰ ਜੋੜਾਬੱਧ ਕਰੋ"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"ਜੋੜਾਬੱਧਕਰਨ ਕੋਡ ਨਾਲ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ਛੇ ਅੰਕਾਂ ਵਾਲਾ ਕੋਡ ਵਰਤ ਕੇ ਨਵੇਂ ਡੀਵਾਈਸਾਂ ਨੂੰ ਜੋੜਾਬੱਧ ਕਰੋ"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"ਜੋੜਾਬੱਧ ਕੀਤੇ ਡੀਵਾਈਸ"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"ਡੀਵਾਈਸ ਨੂੰ ਜੋੜਾਬੱਧ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ। ਜਾਂ ਤਾਂ QR ਕੋਡ ਗਲਤ ਸੀ, ਜਾਂ ਡੀਵਾਈਸ ਉਸੇ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੈ।"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ਪਤਾ & ਪੋਰਟ"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR ਕੋਡ ਸਕੈਨ ਕਰੋ"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR ਕੋਡ ਸਕੈਨ ਕਰਕੇ ਵਾਈ-ਫਾਈ \'ਤੇ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR ਕੋਡ ਸਕੈਨ ਕਰਕੇ ਵਾਈ-ਫਾਈ \'ਤੇ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"ਕਿਰਪਾ ਕਰਕੇ ਕਿਸੇ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ਡੀਬੱਗ, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ਬੱਗ ਰਿਪੋਰਟ ਸ਼ਾਰਟਕੱਟ"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"ਵਾਈ-ਫਾਈ ਵਰਬੋਸ ਲੌਗਿੰਗ ਚਾਲੂ ਕਰੋ"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"ਸੀਮਤ ਵਾਈ‑ਫਾਈ ਸਕੈਨ"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"ਮੋਬਾਈਲ ਡਾਟਾ ਹਮੇਸ਼ਾਂ ਕਿਰਿਆਸ਼ੀਲ"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"ਟੈਦਰਿੰਗ ਹਾਰਡਵੇਅਰ ਐਕਸੈੱਲਰੇਸ਼ਨ"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਦਿਖਾਓ"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"ਵਾਇਰਲੈੱਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਚੋਣਾਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕਰੋ"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"ਵਾਈ‑ਫਾਈ ਲੌਗਿੰਗ ਪੱਧਰ ਵਧਾਓ, ਵਾਈ‑ਫਾਈ Picker ਵਿੱਚ ਪ੍ਰਤੀ SSID RSSI ਦਿਖਾਓ"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਘਟਾ ਕੇ ਨੈੱਟਵਰਕ ਕਾਰਗੁਜ਼ਾਰੀ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਂਦਾ ਹੈ"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"ਮੀਟਰਬੱਧ ਕੀਤਾ ਗਿਆ"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"ਗੈਰ-ਮੀਟਰਬੱਧ ਕੀਤਾ ਗਿਆ"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"ਲੌਗਰ ਬਫ਼ਰ ਆਕਾਰ"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"ਬੈਕਗ੍ਰਾਊਂਡ ਐਪਾਂ ਲਈ \'ਐਪ ਪ੍ਰਤਿਕਿਰਿਆ ਨਹੀਂ ਦੇ ਰਹੀ ਹੈ\' ਵਿੰਡੋ ਦਿਖਾਓ"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"ਸੂਚਨਾ ਚੈਨਲ ਚਿਤਾਵਨੀਆਂ ਦਿਖਾਓ"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ਐਪ ਵੱਲੋਂ ਵੈਧ ਚੈਨਲ ਤੋਂ ਬਿਨਾਂ ਸੂਚਨਾ ਪੋਸਟ ਕਰਨ \'ਤੇ ਸਕ੍ਰੀਨ \'ਤੇ ਚਿਤਾਵਨੀ ਦਿਖਾਉਂਦੀ ਹੈ"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"ਗੱਲਬਾਤ ਸੰਬੰਧੀ ਸੂਚਨਾਵਾਂ ਲਈ ਸ਼ਾਰਟਕੱਟ ਲਾਗੂ ਕਰੋ"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਵਿੱਚ ਦਿਸਣ ਲਈ ਚਿਰਸਥਾਈ ਸਾਂਝਾਕਰਨ ਸ਼ਾਰਟਕੱਟ ਨਾਲ ਸੂਚਨਾਵਾਂ ਦਾ ਬੈਕਅੱਪ ਲੈਣਾ ਲੋੜੀਂਦਾ ਹੈ"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"ਐਪਾਂ ਨੂੰ ਜ਼ਬਰਦਸਤੀ ਬਾਹਰੀ ਸਟੋਰੇਜ \'ਤੇ ਆਗਿਆ ਦਿਓ"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"ਮੈਨੀਫੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਕਿਸੇ ਵੀ ਐਪ ਨੂੰ ਬਾਹਰੀ ਸਟੋਰੇਜ \'ਤੇ ਲਿਖਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦੀ ਹੈ"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"ਮੁੜ-ਆਕਾਰ ਬਦਲਣ ਲਈ ਸਰਗਰਮੀਆਂ \'ਤੇ ਜ਼ੋਰ ਦਿਓ"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 734b25757bfc..114e302f4bae 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Debugowanie bezprzewodowe"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Aby wyświetlić dostępne urządzenia i ich używać, włącz debugowanie bezprzewodowe"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Sparuj urządzenie przy pomocy kodu QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Sparuj nowe urządzenie, skanując kod QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Sparuj nowe urządzenie, skanując kod QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Sparuj urządzenie przy pomocy kodu parowania"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Sparuj nowe urządzenie przy pomocy 6-cyfrowego kodu"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Sparowane urządzenia"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Nie udało się sparować z urządzeniem. Kod QR jest nieprawidłowy albo urządzenie nie jest podłączone do tej samej sieci."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adres IP i port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Zeskanuj kod QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Sparuj urządzenia przez Wi-Fi, skanując kod QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Sparuj urządzenia przez Wi-Fi, skanując kod QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Połącz się z siecią Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Skrót do zgłoszenia błędu"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Wyświetlacz bezprzewodowy"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Szczegółowy dziennik Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Ograniczanie skanowania Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Randomizacja MAC ulepszona w zakresie Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilna transmisja danych zawsze aktywna"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Akceleracja sprzętowa tetheringu"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Pokaż urządzenia Bluetooth bez nazw"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Pokaż opcje certyfikacji wyświetlacza bezprzewodowego"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zwiększ poziom rejestrowania Wi‑Fi, pokazuj według RSSI SSID w selektorze Wi‑Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmniejsza zużycie baterii i zwiększa wydajność sieci"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ten przełącznik wpływa na zachowanie randomizacji MAC tylko w przypadku trybu klienta.\nKiedy ten tryb jest aktywny, adresy MAC dowolnej sieci, która ma włączoną randomizację MAC, podczas powiązywania mogą zostać poddane ponownej randomizacji, w zależności od tego, kiedy klient ostatni raz rozłączył się z siecią. Ponowna randomizacja nie zachodzi, jeśli urządzenie połączy się ponownie w ciągu 4 lub mniejszej liczby godzin."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Użycie danych jest mierzone"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Użycie danych nie jest mierzone"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Rozmiary bufora rejestratora"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Wyświetlaj okno Aplikacja nie odpowiada dla aplikacji w tle"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Pokaż ostrzeżenia kanału powiadomień"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Wyświetla ostrzeżenie, gdy aplikacja publikuje powiadomienie bez prawidłowego kanału"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Wymuszaj skróty do powiadomień o rozmowie"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Wymagaj używania długoterminowych skrótów do udostępniania powiadomień, które pojawiałyby się w sekcji rozmowy"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Wymuś zezwalanie na aplikacje w pamięci zewnętrznej"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Pozwala na zapis aplikacji w pamięci zewnętrznej niezależnie od wartości w pliku manifestu"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Wymuś zmianę rozmiaru okien aktywności"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index d98c9ff071bf..845433df6d96 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Depuração por Wi-Fi"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para ver e usar dispositivos disponíveis, ative a depuração por Wi-Fi"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Parear o dispositivo com um código QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Parear novos dispositivos usando um leitor de código QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Parear novos dispositivos usando um leitor de código QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Parear o dispositivo com um código de pareamento"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Parear novos dispositivos usando um código de seis dígitos"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivos pareados"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Falha ao parear o dispositivo. O código QR está incorreto ou o dispositivo não está conectado à mesma rede."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Endereço IP e porta"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Ler código QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conecte-se a uma rede Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Atalho para relatório de bugs"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certificação de Display sem fio"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Ativar registro detalhado de Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitar busca por Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"MAC aleatório melhorado por Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Dados móveis sempre ativos"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleração de hardware de tethering"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções de certificação de Display sem fio"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de registro de Wi-Fi; mostrar conforme o RSSI do SSID no seletor de Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo de bateria e melhora o desempenho da rede"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Essa opção afeta o comportamento de ordem aleatória de MAC somente para o modo cliente.\nQuando esse modo é ativado, todas as redes que tiverem a ordem aleatória de MAC ativada poderão ter a ordem aleatória refeita durante a associação, dependendo de quando o cliente se desconectou da rede pela última vez. A ordem aleatória não será refeita se o dispositivo se reconectar em até quatro horas."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Limitada"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Ilimitada"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos de buffer de logger"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Usar aceleração de hardware de tethering quando disponível"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Permitir a depuração USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"A depuração USB serve apenas para fins de desenvolvimento. Use-a para copiar dados entre o computador e o dispositivo, instalar apps no seu aparelho sem notificação e ler dados de registro."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Permitir a depuração sem fio?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"A depuração sem fio serve apenas para fins de desenvolvimento. Use-a para copiar dados entre o computador e o dispositivo, instalar apps no seu aparelho sem notificação e ler dados de registro."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Permitir a depuração por Wi-Fi?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"A depuração por Wi-Fi serve apenas para fins de desenvolvimento. Use para copiar dados entre o computador e o dispositivo, instalar apps no seu aparelho sem notificação e ler dados de registro."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Revogar o acesso à depuração USB para todos os computadores autorizados?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Ativar as configurações de desenvolvimento?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Essas configurações são destinadas apenas para o uso de desenvolvedores. Elas podem causar a desativação ou mau funcionamento do dispositivo e dos apps contidos nele."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Exibir a caixa de diálogo \"App não responde\" para apps em segundo plano"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostrar avisos de notificações"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Exibir aviso na tela quando um app posta notificação sem canal válido"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Usar atalhos para notificações de conversa"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Exigir que as notificações sejam apoiadas por um atalho de compartilhamento de longa duração para que elas possam aparecer na seção de conversa"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Forçar permissão de apps em armazenamento externo"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Qualificar apps para gravação em armazenamento externo, independentemente de valores de manifestos"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Forçar atividades a serem redimensionáveis"</string> @@ -426,10 +430,10 @@ <string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"Tempo restante aproximado, com base no seu uso: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <!-- no translation found for power_remaining_duration_only_short (7438846066602840588) --> <skip /> - <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g> com base no seu uso (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g> com base no seu uso"</string> - <string name="power_discharge_by" msgid="4113180890060388350">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only" msgid="92545648425937000">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Deve durar até por volta de <xliff:g id="TIME">%1$s</xliff:g> com base no seu uso (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Deve durar até por volta de <xliff:g id="TIME">%1$s</xliff:g> com base no seu uso"</string> + <string name="power_discharge_by" msgid="4113180890060388350">"Deve durar até por volta de <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_discharge_by_only" msgid="92545648425937000">"Deve durar até por volta de <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Até <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"A bateria pode acabar neste horário: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"Menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> restante(s)"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index c12f2d7d5616..a008504420c6 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Depuração sem fios"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para ver e utilizar dispositivos disponíveis, ative a depuração sem fios."</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Sincronize o dispositivo com o código QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Sincronize novos dispositivos com o leitor de códigos QR."</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Sincronize novos dispositivos com o leitor de códigos QR."</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Sincronize dispositivo com código de sincronização"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Sincronize novos dispositivos através do código de seis dígitos."</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivos sincronizados"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Falha ao sincronizar o dispositivo. O código QR estava incorreto ou o dispositivo não está ligado à mesma rede."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Porta e endereço IP"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Leia o código QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Sincronize o dispositivo através de Wi-Fi ao ler um código QR."</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Sincronize o dispositivo através de Wi-Fi ao ler um código QR."</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Estabeleça ligação a uma rede Wi-Fi."</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, depurar, programador"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Atalho para relatório de erro"</string> @@ -242,7 +242,7 @@ <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Capturar os pacotes Bluetooth (ative/desative o Bluetooth após alterar esta definição)"</string> <string name="oem_unlock_enable" msgid="5334869171871566731">"Desbloqueio de OEM"</string> <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Permitir o desbloqueio do carregador de arranque"</string> - <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Pretende permitir o desbloqueio de OEM?"</string> + <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Permitir o desbloqueio de OEM?"</string> <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"AVISO: as funcionalidades de proteção do dispositivo não funcionam neste dispositivo enquanto esta definição estiver ativada."</string> <string name="mock_location_app" msgid="6269380172542248304">"Selecionar aplicação de localização fictícia"</string> <string name="mock_location_app_not_set" msgid="6972032787262831155">"Aplicação de localização fictícia não definida"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certificação de display sem fios"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Ativar o registo verboso de Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Controlo da procura de Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Seleção aleatória do MAC otimizado Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Dados móveis sempre ativos"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleração de hardware para ligação (à Internet) via telemóvel"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções da certificação de display sem fios"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de reg. de Wi-Fi, mostrar por RSSI de SSID no Selec. de Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo rápido da bateria e melhora o desempenho da rede"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Este botão ativar/desativar afeta o comportamento da seleção aleatória do MAC apenas para o modo de cliente.\nQuando este modo está ativado, qualquer rede que tenha a seleção aleatória do MAC ativa pode fazer com que os seus endereços MAC sejam novamente selecionados de forma aleatória durante a associação, dependendo de quando o cliente se desligou da rede pela última vez. A nova seleção aleatória não ocorre se a ligação do dispositivo for restabelecida em 4 horas ou menos."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Acesso limitado"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Acesso ilimitado"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos da memória intermédia do registo"</string> @@ -300,7 +302,7 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Se disponível, utilizar a aceleração de hardware para ligação (à Internet) via telemóvel"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Permitir depuração USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"A depuração USB é utilizada apenas para fins de programação. Utilize-a para copiar dados entre o computador e o aparelho, instalar aplicações no aparelho sem notificação e ler dados de registo."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Pretende permitir a depuração sem fios?"</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Permitir a depuração sem fios?"</string> <string name="adbwifi_warning_message" msgid="8005936574322702388">"A depuração sem fios é utilizada apenas para fins de programação. Utilize-a para copiar dados entre o computador e o dispositivo, instalar apps no dispositivo sem notificação e ler dados de registo."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Revogar acesso à depuração USB de todos os computadores anteriormente autorizados?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Permitir definições de programação?"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Mostrar caixa de diálogo A aplicação não está a responder para aplicações em segundo plano"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostrar avisos do canal de notificações"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Mostra um aviso no ecrã quando uma aplicação publica uma notificação sem o canal ser válido"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Aplicar atalhos para notificações de conversas"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Solicitar cópia de seg. das notif. por atalho de partilha de longa duração p/ apresentação na secção de conversas"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Forçar permissão de apps no armazenamento externo"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Torna qualquer aplicação elegível para ser gravada no armazenamento externo, independentemente dos valores do manifesto"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Forçar as atividades a serem redimensionáveis"</string> @@ -451,7 +455,7 @@ <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Carregamento lento"</string> <string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está a carregar"</string> <string name="battery_info_status_not_charging" msgid="8330015078868707899">"Ligada à corrente, não é possível carregar neste momento"</string> - <string name="battery_info_status_full" msgid="4443168946046847468">"Completo"</string> + <string name="battery_info_status_full" msgid="4443168946046847468">"Carregada"</string> <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlado pelo gestor"</string> <string name="disabled" msgid="8017887509554714950">"Desativada"</string> <string name="external_source_trusted" msgid="1146522036773132905">"Autorizada"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index d98c9ff071bf..845433df6d96 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Depuração por Wi-Fi"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para ver e usar dispositivos disponíveis, ative a depuração por Wi-Fi"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Parear o dispositivo com um código QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Parear novos dispositivos usando um leitor de código QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Parear novos dispositivos usando um leitor de código QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Parear o dispositivo com um código de pareamento"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Parear novos dispositivos usando um código de seis dígitos"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivos pareados"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Falha ao parear o dispositivo. O código QR está incorreto ou o dispositivo não está conectado à mesma rede."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Endereço IP e porta"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Ler código QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Parear dispositivo na rede Wi‑Fi fazendo a leitura do código QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conecte-se a uma rede Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Atalho para relatório de bugs"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certificação de Display sem fio"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Ativar registro detalhado de Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitar busca por Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"MAC aleatório melhorado por Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Dados móveis sempre ativos"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Aceleração de hardware de tethering"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Mostrar opções de certificação de Display sem fio"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Aumentar o nível de registro de Wi-Fi; mostrar conforme o RSSI do SSID no seletor de Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduz o consumo de bateria e melhora o desempenho da rede"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Essa opção afeta o comportamento de ordem aleatória de MAC somente para o modo cliente.\nQuando esse modo é ativado, todas as redes que tiverem a ordem aleatória de MAC ativada poderão ter a ordem aleatória refeita durante a associação, dependendo de quando o cliente se desconectou da rede pela última vez. A ordem aleatória não será refeita se o dispositivo se reconectar em até quatro horas."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Limitada"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Ilimitada"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Tamanhos de buffer de logger"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Usar aceleração de hardware de tethering quando disponível"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Permitir a depuração USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"A depuração USB serve apenas para fins de desenvolvimento. Use-a para copiar dados entre o computador e o dispositivo, instalar apps no seu aparelho sem notificação e ler dados de registro."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Permitir a depuração sem fio?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"A depuração sem fio serve apenas para fins de desenvolvimento. Use-a para copiar dados entre o computador e o dispositivo, instalar apps no seu aparelho sem notificação e ler dados de registro."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Permitir a depuração por Wi-Fi?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"A depuração por Wi-Fi serve apenas para fins de desenvolvimento. Use para copiar dados entre o computador e o dispositivo, instalar apps no seu aparelho sem notificação e ler dados de registro."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Revogar o acesso à depuração USB para todos os computadores autorizados?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Ativar as configurações de desenvolvimento?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Essas configurações são destinadas apenas para o uso de desenvolvedores. Elas podem causar a desativação ou mau funcionamento do dispositivo e dos apps contidos nele."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Exibir a caixa de diálogo \"App não responde\" para apps em segundo plano"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Mostrar avisos de notificações"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Exibir aviso na tela quando um app posta notificação sem canal válido"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Usar atalhos para notificações de conversa"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Exigir que as notificações sejam apoiadas por um atalho de compartilhamento de longa duração para que elas possam aparecer na seção de conversa"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Forçar permissão de apps em armazenamento externo"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Qualificar apps para gravação em armazenamento externo, independentemente de valores de manifestos"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Forçar atividades a serem redimensionáveis"</string> @@ -426,10 +430,10 @@ <string name="power_discharging_duration_enhanced" msgid="1800465736237672323">"Tempo restante aproximado, com base no seu uso: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <!-- no translation found for power_remaining_duration_only_short (7438846066602840588) --> <skip /> - <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g> com base no seu uso (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g> com base no seu uso"</string> - <string name="power_discharge_by" msgid="4113180890060388350">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only" msgid="92545648425937000">"Deve durar até cerca de <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_enhanced" msgid="563438403581662942">"Deve durar até por volta de <xliff:g id="TIME">%1$s</xliff:g> com base no seu uso (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Deve durar até por volta de <xliff:g id="TIME">%1$s</xliff:g> com base no seu uso"</string> + <string name="power_discharge_by" msgid="4113180890060388350">"Deve durar até por volta de <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> + <string name="power_discharge_by_only" msgid="92545648425937000">"Deve durar até por volta de <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Até <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"A bateria pode acabar neste horário: <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"Menos de <xliff:g id="THRESHOLD">%1$s</xliff:g> restante(s)"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 586040944b9e..b0d78cde0ae8 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"Remedierea erorilor prin USB"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Mod de depanare când este conectat USB"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Revoc autorizații remediere a erorilor prin USB"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Remedierea erorilor prin wireless"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Remedierea erorilor wireless"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Modul de remediere a erorilor când rețeaua Wi-Fi este conectată"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Eroare"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Remedierea erorilor prin wireless"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Remedierea erorilor wireless"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Activați remedierea erorilor wireless pentru a vedea și a folosi dispozitivele disponibile"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Asociați dispozitivul folosind codul QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Asociați dispozitive noi folosind scannerul de coduri QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Asociați dispozitive noi folosind scannerul de coduri QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Asociați dispozitivul folosind codul de conectare"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Asociați dispozitive noi folosind codul din șase cifre"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispozitive asociate"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Nu s-a asociat dispozitivul. Codul QR este incorect sau dispozitivul nu este conectat la aceeași rețea."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adresa IP și portul"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scanați codul QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Asociați dispozitivul prin Wi-Fi scanând un cod QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Asociați dispozitivul prin Wi-Fi scanând un cod QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conectați-vă la o rețea Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, remedierea erorilor, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Comandă rapidă pentru raportul de erori"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certificare Ecran wireless"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Înregistrare prin Wi-Fi de volume mari de date"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limitare căutare de rețele Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Randomizare MAC îmbunătățită prin Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Date mobile permanent active"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Accelerare hardware pentru tethering"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afișați dispozitivele Bluetooth fără nume"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afișați opțiunile pentru certificarea Ecran wireless"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Măriți niv. de înr. prin Wi‑Fi, afișați în fcț. de SSID RSSI în Selectorul Wi‑Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduce descărcarea bateriei și îmbunătățește performanța rețelei"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Acest comutator influențează comportamentul de randomizare a adresei MAC numai pentru modul client.\nCând este activat acest mod, toate rețelele care au activată randomizarea adresei MAC pot randomiza din nou adresele MAC în timpul asocierii, în funcție de ora ultimei deconectări a clientului de la rețea. Randomizarea nu se repetă dacă dispozitivul se reconectează în decurs de 4 ore."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Contorizată"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Necontorizată"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Dimensiunile memoriei temporare a jurnalului"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Folosiți accelerarea hardware pentru tethering, dacă este disponibilă"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Permiteți remedierea erorilor prin USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"Remedierea erorilor prin USB are exclusiv scopuri de dezvoltare. Utilizați-o pentru a copia date de pe computer pe dispozitiv, pentru a instala aplicații pe dispozitiv fără notificare și pentru a citi datele din jurnale."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Permiteți remedierea erorilor prin wireless?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Remedierea erorilor prin wireless are exclusiv scopuri de dezvoltare. Folosiți-o pentru a copia date de pe computer pe dispozitiv, pentru a instala aplicații pe dispozitiv fără notificare și pentru a citi datele din jurnale."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Permiteți remedierea erorilor wireless?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Remedierea erorilor wireless are exclusiv scopuri de dezvoltare. Folosiți-o pentru a copia date de pe computer pe dispozitiv, pentru a instala aplicații pe dispozitiv fără notificare și pentru a citi datele din jurnale."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Revocați accesul la remedierea erorilor prin USB de pe toate computerele pe care le-ați autorizat anterior?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Permiteți setările pentru dezvoltare?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Aceste setări sunt destinate exclusiv utilizării pentru dezvoltare. Din cauza lor, este posibil ca dispozitivul dvs. și aplicațiile de pe acesta să nu mai funcționeze sau să funcționeze necorespunzător."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Afișați dialogul Aplicația nu răspunde pentru aplicațiile din fundal"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Afișați avertismentele de pe canalul de notificări"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Afișați avertisment pe ecran când o aplicație postează o notificare fără canal valid"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Comenzi rapide pt. notif. de conversație"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Notificările trebuie susținute de o comandă rapidă veche de trimitere ca să apară în secțiunea conversației"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Forțați accesul aplicațiilor la stocarea externă"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Faceți ca orice aplicație eligibilă să fie scrisă în stocarea externă, indiferent de valorile manifestului"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Forțați redimensionarea activităților"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index ab230b768f20..57f980f74211 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -112,7 +112,7 @@ <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Используется для передачи файлов"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Использовать для ввода"</string> <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Использовать для слухового аппарата"</string> - <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Подключить"</string> + <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Добавить"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"ДОБАВИТЬ"</string> <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Отмена"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Установление соединения обеспечивает доступ к вашим контактам и журналу звонков при подключении."</string> @@ -194,8 +194,8 @@ <item msgid="581904787661470707">"Максимальная"</item> </string-array> <string name="choose_profile" msgid="343803890897657450">"Выбор профиля"</string> - <string name="category_personal" msgid="6236798763159385225">"Личные данные"</string> - <string name="category_work" msgid="4014193632325996115">"Работа"</string> + <string name="category_personal" msgid="6236798763159385225">"Личный профиль"</string> + <string name="category_work" msgid="4014193632325996115">"Рабочий профиль"</string> <string name="development_settings_title" msgid="140296922921597393">"Для разработчиков"</string> <string name="development_settings_enable" msgid="4285094651288242183">"Включить параметры для разработчиков"</string> <string name="development_settings_summary" msgid="8718917813868735095">"Настройка параметров для разработчиков"</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Отладка по Wi-Fi"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Чтобы посмотреть и использовать доступные устройства, включите отладку по Wi-Fi"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Подключить устройство с помощью QR-кода"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Подключение новых устройств с помощью сканера QR-кодов"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Подключение новых устройств с помощью сканера QR-кодов"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Подключить устройство с помощью кода подключения"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Подключение новых устройств с помощью шестизначного кода"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Подключенные устройства"</string> @@ -230,8 +230,8 @@ <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Подключение устройства…"</string> <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Не удалось подключить устройство. QR-код неверный, или устройство находится в другой сети."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-адрес и порт"</string> - <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Сканировать QR-код"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Подключение устройства через Wi‑Fi с использованием QR-кода"</string> + <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Отсканируйте QR-код"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Подключение устройства через Wi‑Fi с использованием QR-кода"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Подключите устройство к сети Wi-Fi."</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, отладка, разработчик"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Отчет об ошибке"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Серт. беспроводн. мониторов"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Подробный журнал Wi‑Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Ограничивать поиск сетей Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Случайные MAC-адреса в сети Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Не отключать мобильный Интернет"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Аппаратное ускорение в режиме модема"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показывать Bluetooth-устройства без названий"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показывать параметры сертификации беспроводных мониторов"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Вести подробный журнал, показывать RSSI для каждого SSID при выборе сети"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Уменьшает расход заряда батареи и улучшает работу сети"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Эта настройка влияет на использование случайных MAC-адресов только в клиентском режиме.\nВо время подключения к любой сети происходит повторное создание случайного MAC-адреса в зависимости от того, когда клиент последний раз отключался от сети. Это невозможно, если соединение возобновляется через четыре часа или раньше."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Сеть с тарификацией трафика"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Сеть без тарификации трафика"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Размер буфера журнала"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Уведомлять о том, что приложение, запущенное в фоновом режиме, не отвечает"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Показывать предупреждения канала передачи уведомлений"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Показывать предупреждение о новых уведомлениях приложения вне допустимого канала"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Принудительное использование ярлыков для уведомлений из чатов"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Обязательно дублировать уведомления с помощью долго отображаемых ярлыков, чтобы уведомления появлялись в разделе чатов"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Разрешить сохранение на внешние накопители"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Разрешить сохранение приложений на внешних накопителях (независимо от значений в манифесте)"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Изменение размера в многооконном режиме"</string> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index d87e2884ceb0..d22a643a7856 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"නොරැහැන් දෝෂාවේක්ෂණය"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"ලබා ගත හැකි උපාංග බැලීමට, නොරැහැන් දෝෂාවේක්ෂණය ක්රියාත්මක කරන්න"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR කේතය සමගින් උපාංගය යුගල කරන්න"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR කේත ස්කෑනරය භාවිතයෙන් නව උපාංග යුගල කරන්න"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR කේත ස්කෑනරය භාවිතයෙන් නව උපාංග යුගල කරන්න"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"යුගල කිරීමේ කේතය සමගින් උපාංගය යුගල කරන්න"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ඉලක්කම් හයක කේතය භාවිතයෙන් නව උපාංග යුගල කරන්න"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"යුගල කළ උපාංග"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"උපාංගය යුගල කිරීමට අසමත් විය. QR කේතය වැරදිය නැතහොත් එකම ජාලයට සම්බන්ධ කර නැත."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ලිපිනය & තොට"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR කේතය ස්කෑන් කරන්න"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR කේතය ස්කෑන් කිරීමෙන් Wi‑Fi හරහා උපාංගය යුගල කරන්න"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR කේතය ස්කෑන් කිරීමෙන් Wi‑Fi හරහා උපාංගය යුගල කරන්න"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"කරුණාකර Wi-Fi ජාලයකට සම්බන්ධ වන්න"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, දෝෂාවෙක්ෂණ, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"දෝෂය වාර්තා කිරීමේ කෙටිමඟ"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"නොරැහැන් සංදර්ශක සහතිකය"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"විස්තරාත්මක Wi‑Fi ලොග් කිරීම සබල කරන්න"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi ස්කෑන් අවකරණය"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi-Fi‑වැඩිදියුණු කළ MAC සසම්භාවීකරණය"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"ජංගම දත්ත සැමවිට ක්රියාකාරීය"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"ටෙදරින් දෘඪාංග ත්වරණය"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"නම් නොමැති බ්ලූටූත් උපාංග පෙන්වන්න"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"නොරැහැන් සංදර්ශක සහතිකය සඳහා විකල්ප පෙන්වන්න"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ලොග් මට්ටම වැඩි කරන්න, Wi‑Fi තෝරනයෙහි SSID RSSI අනුව පෙන්වන්න"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"බැටරි බැසීම අඩු කරන අතර ජාල කාර්ය සාධනය වැඩි දියුණු කරයි"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"මෙම ටොගලය සේවාලාභී ප්රකාරය සඳහා පමණක් MAC සසම්භාවීකරණ හැසිරීමට බලපායි.\nමෙම ප්රකාරය සක්රිය කර ඇති විට, MAC සසම්භාවීකරණය සබල කර ඇති ඕනෑම ජාලයකට, සේවාලාභියා අවසන් වරට ජාලයෙන් විසන්ධි වූයේ කවදාද යන්න මත පදනම්ව සම්බන්ධය අතරතුර ඔවුන්ගේ MAC ලිපින යළි සසම්භාවිකරණය කර තිබිය හැකිය. උපාංගය පැය 4කින් හෝ ඊට අඩු කාලයකදී නැවත සම්බන්ධ වන්නේ නම් යළි සසම්භාවිකරණය සිදු නොවේ."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"මනිනු ලැබේ"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"මනින්නේ නැත"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"ලෝගයේ අන්තරාවක ප්රමාණය"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"පසුබිම් යෙදුම්වලට යෙදුම ප්රතිචාර නොදක්වයි කවුළුව සංදර්ශනය කරන්න"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"දැනුම්දීම් නාලිකා අනතුරු ඇඟවීම් පෙන්."</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"යෙදුමක් වලංගු නාලිකාවකින් තොරව දැනුම්දීමක් පළ කරන විට තිරය-මත අනතුරු ඇඟවීමක් සංදර්ශනය කරයි."</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"සංවාද දැනුම් දීම් සඳහා කෙටිමං බලාත්මක කරන්න"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"සංවාද කොටසේ පෙනී සිටීම පිණිස දිගු කාලයක් පවතින බෙදා ගැනීමේ කෙටිමඟක් මඟින් දැනුම් දීම් අවහිර කිරීමට අවශ්ය වේ"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"බාහිර මත යෙදුම් ඉඩ දීම බල කරන්න"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"මැනිෆෙස්ට් අගයන් නොසලකා, ඕනෑම යෙදුමක් බාහිර ගබඩාවට ලිවීමට සුදුසුකම් ලබා දෙයි"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"ක්රියාකාරකම් ප්රතිප්රමාණ කළ හැකි බවට බල කරන්න"</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 73cfce1d73d7..79a9c2443a9a 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Bezdrôtové ladenie"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Ak chcete zobraziť a používať dostupné zariadenia, zapnite bezdrôtové ladenie"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Spárovať zariadenie pomocou QR kódu"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Spárujte nové zariadenia pomocou skenera QR kódov"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Spárujte nové zariadenia pomocou skenera QR kódov"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Spárovať zariadenie pomocou párovacieho kódu"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Spárujte nové zariadenia pomocou šesťmiestneho kódu"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Spárované zariadenia"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Zariadenie sa nepodarilo spárovať. Buď bol QR kód nesprávny, alebo zariadenie nie je pripojené k rovnakej sieti."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adresa IP a port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Naskenujte QR kód"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Spárujte zariadenie cez sieť Wi-Fi naskenovaním QR kódu"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Spárujte zariadenie cez sieť Wi-Fi naskenovaním QR kódu"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Pripojte sa k sieti Wi‑Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ladenie, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Skratka hlásenia chyby"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certifikácia bezdrôtového zobrazenia"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Podrobné denníky Wi‑Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Pribrzdenie vyhľadávania sietí Wi‑Fi"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobilné dáta ponechať vždy aktívne"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardvérová akcelerácia tetheringu"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovať zariadenia Bluetooth bez názvov"</string> @@ -277,12 +279,14 @@ <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Výber súkromného režimu DNS"</string> <string name="private_dns_mode_off" msgid="7065962499349997041">"Vypnuté"</string> <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Automaticky"</string> - <string name="private_dns_mode_provider" msgid="3619040641762557028">"Súkromný názov hostiteľa poskytovateľa DNS"</string> + <string name="private_dns_mode_provider" msgid="3619040641762557028">"Názov hostiteľa poskytovateľa súkromného DNS"</string> <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Zadajte názov hostiteľa poskytovateľa DNS"</string> <string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"Nepodarilo sa pripojiť"</string> <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Zobraziť možnosti certifikácie bezdrôtového zobrazenia"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Zvýšiť úroveň denníkov Wi‑Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi‑Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Znižuje používanie batérie a zlepšuje výkon siete"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"Merané"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Bez merania dát"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Vyrovnávacia pamäť nástroja denníkov"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Zobrazovať dialógové okno „Aplikácia nereaguje“ pre aplikácie na pozadí"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Zobraziť hlásenia kanála upozornení"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Zobrazuje varovné hlásenie na obrazovke, keď aplikácia zverejní upozornenie bez platného kanála"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Vynútiť skratky pre upozornenia na konverzácie"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Vyžadovať zastúpenie upozornení dlhodobou skratkou na zdieľanie, aby sa zobrazili v sekcii konverzácie"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Vynútiť povolenie aplikácií na externom úložisku"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Umožňuje zapísať akúkoľvek aplikáciu do externého úložiska bez ohľadu na hodnoty v manifeste"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Vynútiť možnosť zmeny veľkosti aktivít"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index 8e3782c1b11c..4ff27db97aaf 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -78,7 +78,7 @@ <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Povezano (brez telefona ali predstavnosti), raven napolnjenosti akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Aktivna, akumulator na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Aktivno, L: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> - <string name="bluetooth_battery_level" msgid="2893696778200201555">"Akumulator na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> + <string name="bluetooth_battery_level" msgid="2893696778200201555">"Baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: napolnjenost akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> <string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktivna"</string> <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvok predstavnosti"</string> @@ -86,7 +86,7 @@ <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Prenos datoteke"</string> <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Vnosna naprava"</string> <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Internetni dostop"</string> - <string name="bluetooth_profile_pbap" msgid="7064307749579335765">"Dajanje stikov v skupno rabo"</string> + <string name="bluetooth_profile_pbap" msgid="7064307749579335765">"Deljenje stikov"</string> <string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"Uporabi za dajanje stikov v skupno rabo"</string> <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Skupna raba internetne povezave"</string> <string name="bluetooth_profile_map" msgid="8907204701162107271">"Sporočila SMS"</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Brezžično odpravljanje napak"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Če si želite ogledati in uporabljati razpoložljive naprave, vklopite brezžično odpravljanje napak"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Seznanjanje naprave s kodo QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Seznanjanje novih naprav z optičnim bralnikom kod QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Seznanitev novih naprav z optičnim bralnikom kod QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Seznanjanje naprave s kodo za seznanjanje"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Seznanjanje novih naprav s šestmestno kodo"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Seznanjene naprave"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Seznanitev naprave ni uspela. Koda QR je nepravilna ali pa naprava ni povezana v isto omrežje."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Naslov IP in vrata"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Optično branje kode QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Seznanitev naprave prek Wi‑Fi-ja z optičnim branjem kode QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Seznanitev naprave prek Wi‑Fi-ja z optičnim branjem kode QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Vzpostavite povezavo z omrežjem Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, odpravljanje napak, razvoj"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Bližnjica za poročanje o napakah"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Potrdilo brezžičnega zaslona"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Omogoči podrobno zapisovanje dnevnika za Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Omejevanje iskanja omrežij Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Naključen naslov MAC s podporo Wi‑Fi‑ja"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Prenos podatkov v mobilnem omrežju je vedno aktiven"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Strojno pospeševanje za internetno povezavo prek mobilnega telefona"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži naprave Bluetooth brez imen"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Pokaži možnosti za potrdilo brezžičnega zaslona"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Povečaj raven zapisovanja dnevnika za Wi-Fi; v izbirniku Wi‑Fi-ja pokaži glede na SSID RSSI"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zmanjša porabo energije akumulatorja in izboljša delovanje omrežja"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"To stikalo vpliva na dodeljevanje naključnega naslova MAC samo v načinu odjemalca.\nKo je ta način aktiviran, se omrežjem, pri katerih je omogočeno naključno dodeljevanje naslova MAC, med povezovanjem morda dodeli nov naključen naslov MAC, kar je odvisno od tega, kdaj je odjemalec nazadnje prekinil povezavo z omrežjem. Dodelitev novega naključnega naslova se ne izvede, če naprava znova vzpostavi povezavo po največ štirih urah."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Omejen prenos podatkov"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Z neomejenim prenosom podatkov"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Velikosti medpomnilnikov zapisovalnika dnevnika"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Prikaz pogovornega okna za neodzivanje aplikacij v ozadju"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Pokaži opozorila kanala za obvestila"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Na zaslonu se pokaže opozorilo, ko aplikacija objavi obvestilo brez veljavnega kanala"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Uveljavitev bližnjic za obvestila pogovora"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Zahteva, da obvestila podpira dolgotrajna bližnjica za deljenje, da se prikažejo v razdelku s pogovorom"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Vsili omogočanje aplikacij v zunanji shrambi"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsako aplikacijo zapisati v zunanjo shrambo"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Vsili spremembo velikosti za aktivnosti"</string> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index 6d1e80a0f341..2a50f5854eac 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"Korrigjimi i USB-së"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Korrigjo gabimet e modalitetit kur UBS-ja është e lidhur"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Anulo autorizimet e korrigjimeve të gabimeve të USB-së"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Korrigjimi me valë"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Korrigjimi përmes Wi-Fi"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Regjimi i korrigjimit kur Wi‑Fi është i lidhur"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Gabim"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Korrigjimi me valë"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Për të parë dhe përdorur pajisjet e disponueshme, aktivizo korrigjimin me valë"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Korrigjimi përmes Wi-Fi"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Për të parë dhe përdorur pajisjet e disponueshme, aktivizo korrigjimin përmes Wi-Fi"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Çifto pajisjen me kod QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Çifto pajisjet e reja duke përdorur skanerin e kodeve QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Çifto pajisjet e reja duke përdorur skanerin e kodeve QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Çifto pajisjen me kodin e çiftimit"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Çifto pajisjet e reja duke përdorur kodin me gjashtë shifra"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Pajisjet e çiftuara"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Çiftimi i pajisjes dështoi. Ose kodi QR nuk ishte i saktë, ose pajisja nuk është e lidhur me të njëjtin rrjet."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adresa e IP-së dhe porta"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skano kodin QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Çifto pajisjen përmes Wi‑Fi duke skanuar një kod QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Çifto pajisjen përmes Wi‑Fi duke skanuar një kod QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Lidhu me një rrjet Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, korrigjimi, zhvilluesi"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Shkurtorja e raportit të defektit në kod"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certifikimi i ekranit valor"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktivizo hyrjen Wi-Fi Verbose"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Përshpejtimi i skanimit të Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Renditja e rastësishme e adresave MAC të përmirësuara me Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Të dhënat celulare gjithmonë aktive"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Përshpejtimi i harduerit për ndarjen e lidhjes (internet)"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Shfaq pajisjet me Bluetooth pa emra"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Shfaq opsionet për certifikimin e ekranit valor"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Rrit nivelin regjistrues të Wi‑Fi duke shfaqur SSID RSSI-në te Zgjedhësi i Wi‑Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Zvogëlon shkarkimin e baterisë dhe përmirëson cilësinë e funksionimit të rrjetit"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Ky ndryshim ndikon te sjellja e renditjes së rastësishme të adresave MAC vetëm për modalitetin e klientit.\nKur aktivizohet ky modalitet, çdo rrjet që ka të aktivizuar renditjen e rastësishme të adresave MAC mund t\'i rirendisë adresat e veta MAC gjatë shoqërimit, në varësi të kohës kur është shkëputur klienti për herë të fundit nga rrjeti. Rirenditja e rastësishme nuk ndodh nëse pajisja lidhet brenda 4 orëve ose më pak."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Me matje"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Pa matje"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Madhësitë e regjistruesit"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Përdor përshpejtimin e harduerit për ndarjen e lidhjes (internet) nëse është i disponueshëm"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Të lejohet korrigjimi i USB-së?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"Korrigjuesi i USB-së është vetëm për qëllime zhvillimore. Përdore për të kopjuar të dhëna mes kompjuterit dhe pajisjes tënde, për të instaluar aplikacione në pajisjen tënde pa asnjë njoftim si dhe për të lexuar të dhënat e ditarit."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Të lejohet korrigjimi me valë?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Korrigjimi me valë është vetëm për qëllime zhvillimore. Përdore për të kopjuar të dhëna mes kompjuterit dhe pajisjes sate, për të instaluar aplikacione në pajisjen tënde pa asnjë njoftim si dhe për të lexuar të dhënat e regjistrit."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Të lejohet korrigjimi përmes Wi-Fi?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Korrigjimin përmes Wi-Fi është vetëm për qëllime zhvillimore. Përdore për të kopjuar të dhëna mes kompjuterit dhe pajisjes sate, për të instaluar aplikacione në pajisjen tënde pa asnjë njoftim si dhe për të lexuar të dhënat e regjistrit."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Të bllokohet qasja për korrigjim të USB-së nga të gjithë kompjuterët që ke autorizuar më parë?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Të lejohen cilësimet e zhvillimit?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Këto cilësime janë të projektuara vetëm për përdorim në programim. Ato mund të shkaktojnë që pajisja dhe aplikacionet në të, të mos punojnë ose të veprojnë në mënyrë të gabuar."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Shfaq raportet ANR (Aplikacioni nuk përgjigjet) për aplikacionet në sfond"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Shfaq paralajmërimet e kanalit të njoftimeve"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Shfaq paralajmërimin në ekran kur një aplikacion poston një njoftim pa një kanal të vlefshëm"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Zbato shkurtoret për njoftimet e bisedave"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kërko që informacionet të mbështeten nga një shkurtore ndarjeje afatgjatë që ato të shfaqen në seksionin e bashkëbisedimit"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Detyro lejimin në hapësirën e jashtme"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Bën që çdo aplikacion të jetë i përshtatshëm për t\'u shkruar në hapësirën ruajtëse të jashtme, pavarësisht nga vlerat e manifestit"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Detyro madhësinë e ndryshueshme për aktivitetet"</string> @@ -443,7 +447,7 @@ <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"Tableti mund të fiket së shpejti (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"Pajisja mund të fiket së shpejti (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string> - <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> të mbetura për karikimin"</string> + <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> të mbetura deri në karikim"</string> <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> deri sa të karikohen"</string> <string name="battery_info_status_unknown" msgid="268625384868401114">"I panjohur"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"Po karikohet"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 775b7d504e1e..45dbd365ba6d 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Бежично отклањање грешака"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Да бисте видели и користили доступне уређаје, укључите бежично отклањање грешака"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Упарите уређај помоћу QR кода"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Упарите нове уређаје помоћу читача QR кода"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Упарите нове уређаје помоћу читача QR кода"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Упарите уређај помоћу кода за упаривање"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Упарите нове уређаје помоћу шестоцифреног кода"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Упарени уређаји"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Упаривање уређаја није успело. QR кôд је погрешан или уређај није повезан са истом мрежом."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP адреса и порт"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Скенирај QR кôд"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Упарите уређај помоћу Wi‑Fi мреже или тако што ћете скенирати QR кôд"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Упарите уређај помоћу Wi‑Fi мреже тако што ћете скенирати QR кôд"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Повежите се на Wi-Fi мрежу"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, отклањање грешака, програмер"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Пречица за извештај о грешкама"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Сертификација бежичног екрана"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Омогући детаљнију евиденцију за Wi‑Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Успоравање Wi-Fi скенирања"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Насумично MAC разврставање по Wi‑Fi‑ју"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Мобилни подаци су увек активни"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Хардверско убрзање привезивања"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажи Bluetooth уређаје без назива"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Приказ опција за сертификацију бежичног екрана"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Повећава ниво евидентирања за Wi‑Fi. Приказ по SSID RSSI-у у бирачу Wi‑Fi мреже"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Смањује потрошњу батерије и побољшава учинак мреже"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Овај прекидач утиче на понашање насумичног разврставања MAC адреса само за режим клијента.\nКада се овај режим активира, за мреже на којима је омогућено насумично разврставање MAC адреса може да дође до поновног насумичног разврставања MAC адреса током повезивања, у зависности од тога када се клијент пре тога искључио са мреже. До поновног насумичног разврставања не долази ако се уређај поново повеже за 4 сата или мање."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Са ограничењем"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Без ограничења"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Величине бафера података у програму за евидентирање"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Прикажи дијалог Апликација не реагује за апликације у позадини"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Приказуј упозорења због канала за обавештења"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Приказује упозорење на екрану када апликација постави обавештење без важећег канала"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Примењуј пречице за обавештења о конверзацијама"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Захтева да обавештења имају и дугорочну пречицу за дељење како би се појављивала у одељку за конверзације"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Принудно дозволи апликације у спољној"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Омогућава уписивање свих апликација у спољну меморију, без обзира на вредности манифеста"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Принудно омогући промену величине активности"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index e40ba29eadc1..92ec6369afbe 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Trådlös felsökning"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Aktivera trådlös felsökning om du vill se tillgängliga enheter"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Parkoppla enheten med en QR-kod"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Koppla nya enheter med QR-kodsläsare"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Parkoppla nya enheter med QR-kodsläsare"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Koppla enheten med en kopplingskod"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Koppla nya enheter med en sexsiffrig kod"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Kopplade enheter"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Det gick inte att parkoppla enheten. Antingen var det fel QR-kod eller är enheten inte ansluten till samma nätverk."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adress och port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skanna QR-kod"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Parkoppla enheten via Wi-Fi genom att skanna en QR-kod"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Parkoppla enheten via Wi-Fi genom att skanna en QR-kod"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Anslut till ett Wi-Fi-nätverk"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev, felsöka, felsökning"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Genväg till felrapport"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certifiering för Wi-Fi-skärmdelning"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktivera utförlig loggning för Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Begränsning av Wi-Fi-sökning"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi‑förstärkt MAC-slumpgenerering"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobildata alltid aktiverad"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Maskinvaruacceleration för internetdelning"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Visa namnlösa Bluetooth-enheter"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Visa certifieringsalternativ för Wi-Fi-skärmdelning"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Öka loggningsnivån för Wi-Fi, visa per SSID RSSI i Wi‑Fi Picker"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Sänker batteriförbrukningen och förbättrar nätverksprestandan"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Detta läge påverkar endast MAC-slumpgenereringens beteende för klientläget.\nNär läget aktiveras kan alla nätverk som har MAC-slumpgenerering aktiverat få sina adresser slumpgenererade på nytt under kopplingen, beroende på när klienten senast kopplade från nätverket. Det sker ingen ny slumpgenerering om enheten återansluter inom fyra timmar."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Med datapriser"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Utan datapriser"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Buffertstorlekar för logg"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Visa dialogrutan om att appen inte svarar för bakgrundsappar"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Visa varningar om aviseringskanal"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Visa varningar på skärmen när en app lägger upp en avisering utan en giltig kanal"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Kräv genvägar för konversationsaviseringar"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kräv att aviseringar har en långlivad delningsgenväg för att få visas i konversationsavsnittet"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Tillåt appar i externt lagringsutrymme"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Allar appar kan skrivas till extern lagring, oavsett manifestvärden"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Framtvinga storleksanpassning för aktiviteter"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index 815896df5512..2a093525b8a1 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Utatuzi usiotumia waya"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Ili kungalia na kutumia vifaa vinavyopatikana, washa utatuzi usiotumia waya"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Oanisha kifaa ukitumia msimbo wa QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Oanisha vifaa vipya ukitumia Kichanganuzi cha Msimbo wa QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Oanisha vifaa vipya ukitumia kichanganuzi cha Msimbo wa QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Oanisha kifaa ukitumia msimbo wa kuoanisha"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Oanisha vifaa vipya ukitumia msimbo wa tarakimu sita"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Vifaa vilivyooanishwa"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Imeshindwa kuoanisha kifaa. Huenda msimbo wa QR haukuwa sahihi au kifaa hakijaunganishwa kwenye mtandao mmoja."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Anwani ya IP na Mlango"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Changanua msimbo wa QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Oanisha kifaa kupitia Wi-Fi kwa kuchanganua Msimbo wa QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Oanisha kifaa kupitia Wi-Fi kwa kuchanganua msimbo wa QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Tafadhali unganisha kwenye mtandao wa Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, tatua, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Njia ya mkato ya kuripoti hitilafu"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Chaguo za cheti cha kuonyesha pasiwaya"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Washa Uwekaji kumbukumbu za WiFi kutumia Sauti"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Kudhibiti utafutaji wa Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Kuweka nasibu kwenye MAC iliyoimarishwa na Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Iendelee kutumia data ya simu"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Kuongeza kasi kwa kutumia maunzi ili kusambaza mtandao"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Onyesha vifaa vya Bluetooth visivyo na majina"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Onyesha chaguo za cheti cha kuonyesha pasiwaya"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Ongeza hatua ya uwekaji kumbukumbu ya Wi-Fi, onyesha kwa kila SSID RSSI kwenye Kichukuzi cha Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Hupunguza matumizi ya chaji ya betri na kuboresha utendaji wa mtandao"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Hali hii ya kugeuza huathiri utendaji wa kuweka nasibu kwenye anwani ya MAC katika hali ya kiteja pekee.\nWakati hali hii imewashwa, mitandao yoyote ambapo kipengele cha unasibu wa MAC kimewashwa inaweza kuruhusu anwani zao za MAC kuwekwa nasibu tena wakati wa ushirikiano, kulingana na mara ya mwisho kiteja kilipoacha kuunganisha kwenye mtandao. Tukio la kuweka unasibu tena halitokei ikiwa kifaa kitaunganisha tena baada ya muda usiozidi saa nne."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Mtandao unapima data"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Mtandao usiopima data"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Ukubwa wa kiweka bafa ya kumbukumbu"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Onyesha kidirisha cha Programu Kutorejesha Majibu kwa programu zinazotumika chinichini"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Onyesha arifa za maonyo ya kituo"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Huonyesha onyo kwenye skrini programu inapochapisha arifa bila kituo sahihi."</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Tekeleza njia za mkato za arifa za mazungumzo"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Weka mipangilio ili nakala za arifa zihifadhiwe kwa njia ya zamani ya mkato ya kushiriki ili zionekane katika sehemu ya mazungumzo"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Lazima uruhusu programu kwenye hifadhi ya nje"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Huruhusu programu yoyote iwekwe kwenye hifadhi ya nje, bila kujali thamani za faili ya maelezo"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Lazimisha shughuli ziweze kubadilishwa ukubwa"</string> @@ -443,8 +447,8 @@ <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"Huenda kompyuta kibao ikazima hivi karibuni (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"Huenda kifaa kikazima hivi karibuni (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string> - <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Zimesalia <xliff:g id="TIME">%1$s</xliff:g> hadi ijae chaji"</string> - <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> hadi ijae chaji"</string> + <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Imebakisha <xliff:g id="TIME">%1$s</xliff:g> ijae chaji"</string> + <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ijae chaji"</string> <string name="battery_info_status_unknown" msgid="268625384868401114">"Haijulikani"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"Inachaji"</string> <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Inachaji kwa kasi"</string> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 5080c31c27d7..16f5f12bf3ef 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -206,13 +206,14 @@ <string name="enable_adb" msgid="8072776357237289039">"USB பிழைதிருத்தம்"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"USB இணைக்கப்பட்டிருக்கும்போது பிழைத்திருத்தப் பயன்முறையை அமை"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB பிழைத்திருத்த அங்கீகரிப்புகளை நிராகரி"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"வயர்லெஸ் பிழைதிருத்தம்"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"வைஃபை பிழைதிருத்தம்"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"வைஃபையை இணைக்கும்போது பிழைதிருத்தப் பயன்முறை இயக்கப்படும்"</string> <string name="adb_wireless_error" msgid="721958772149779856">"பிழை"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"வயர்லெஸ் பிழைதிருத்தம்"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"கிடைக்கும் சாதனங்களைப் பார்க்கவும் பயன்படுத்தவும் வயர்லெஸ் பிழைதிருத்தத்தை ஆன் செய்யவும்"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"வைஃபை பிழைதிருத்தம்"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"கிடைக்கும் சாதனங்களைப் பார்க்கவும் பயன்படுத்தவும் வைஃபை பிழைதிருத்தத்தை ஆன் செய்யவும்"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR குறியீட்டின் மூலம் சாதனத்தை இணைத்தல்"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR குறியீடு ஸ்கேனரைப் பயன்படுத்தி புதிய சாதனங்களை இணைக்கலாம்"</string> + <!-- no translation found for adb_pair_method_qrcode_summary (7130694277228970888) --> + <skip /> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"இணைத்தல் குறியீட்டின் மூலம் சாதனத்தை இணைத்தல்"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ஆறு இலக்கக் குறியீட்டைப் பயன்படுத்தி புதிய சாதனங்களை இணைக்கலாம்"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"இணைக்கப்பட்ட சாதனங்கள்"</string> @@ -231,9 +232,9 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"சாதனத்துடன் இணைக்க முடியவில்லை. தவறான QR குறியீடாகவோ சாதனம் அதே நெர்வொர்க்குடன் இணைக்கப்படாமலோ இருக்கலாம்."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP முகவரி & போர்ட்"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR குறியீட்டை ஸ்கேன் செய்தல்"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR குறியீட்டை ஸ்கேன் செய்வதன் மூலம் சாதனத்தை வைஃபை மூலம் இணைக்கலாம்"</string> - <!-- no translation found for adb_wireless_no_network_msg (2365795244718494658) --> + <!-- no translation found for adb_wireless_qrcode_pairing_description (6014121407143607851) --> <skip /> + <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"வைஃபை நெட்வொர்க்குடன் இணைக்கவும்"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"பிழைப் புகாருக்கான ஷார்ட்கட்"</string> <string name="bugreport_in_power_summary" msgid="1885529649381831775">"பிழை அறிக்கையைப் பெற பவர் மெனுவில் விருப்பத்தைக் காட்டு"</string> @@ -252,6 +253,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"வயர்லெஸ் காட்சிக்கான சான்றிதழ்"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"வைஃபை அதிவிவர நுழைவை இயக்கு"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"வைஃபை ஸ்கேனிங்கை வரம்பிடுதல்"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"மொபைல் டேட்டாவை எப்போதும் இயக்கத்திலேயே வை"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"வன்பொருள் விரைவுப்படுத்துதல் இணைப்பு முறை"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"பெயர்கள் இல்லாத புளூடூத் சாதனங்களைக் காட்டு"</string> @@ -284,6 +287,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"வயர்லெஸ் காட்சி சான்றுக்கான விருப்பங்களைக் காட்டு"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"வைஃபை நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வுக் கருவியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"பேட்டரி தீர்ந்துபோவதைக் குறைத்து நெட்வொர்க்கின் செயல்திறனை மேம்படுத்தும்"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"கட்டண நெட்வொர்க்"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"கட்டணமில்லா நெட்வொர்க்"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"லாகர் பஃபர் அளவுகள்"</string> @@ -301,8 +306,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"வன்பொருள் விரைவுப்படுத்துதல் இணைப்பு முறை கிடைக்கும் போது, அதைப் பயன்படுத்தும்"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB பிழைதிருத்தத்தை அனுமதிக்கவா?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB பிழைதிருத்தம் மேம்படுத்தல் நோக்கங்களுக்காக மட்டுமே. அதை உங்கள் கணினி மற்றும் சாதனத்திற்கு இடையில் தரவை நகலெடுக்கவும், அறிவிப்பு இல்லாமல் உங்கள் சாதனத்தில் ஆப்ஸை நிறுவவும், பதிவு தரவைப் படிக்கவும் பயன்படுத்தவும்."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"வயர்லெஸ் பிழைதிருத்தத்தை அனுமதிக்கவா?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"\'வயர்லெஸ் பிழைதிருத்தம்\' டெவெலப்மெண்ட் நோக்கங்களுக்காக மட்டுமே. அதை உங்கள் கம்ப்யூட்டருக்கும் சாதனத்திற்கும் இடையே தரவை நகலெடுக்கவும், உங்கள் சாதனத்தில் அறிவிப்பின்றி ஆப்ஸை நிறுவவும், பதிவுத் தரவைப் படிக்கவும் பயன்படுத்தவும்."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"வைஃபை பிழைதிருத்தத்தை அனுமதிக்கவா?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"\'வைஃபை பிழைதிருத்தம்\' டெவெலப்மெண்ட் நோக்கங்களுக்காக மட்டுமே. அதை உங்கள் கம்ப்யூட்டருக்கும் சாதனத்திற்கும் இடையே தரவை நகலெடுக்கவும், உங்கள் சாதனத்தில் அறிவிப்பின்றி ஆப்ஸை நிறுவவும், பதிவுத் தரவைப் படிக்கவும் பயன்படுத்தவும்."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"நீங்கள் ஏற்கனவே அனுமதித்த எல்லா கணினிகளிலிருந்தும் USB பிழைத்திருத்தத்திற்கான அணுகலைத் திரும்பப்பெற வேண்டுமா?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"மேம்பட்ட அமைப்புகளை அனுமதிக்கவா?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"இந்த அமைப்பு மேம்பட்டப் பயன்பாட்டிற்காக மட்டுமே. உங்கள் சாதனம் மற்றும் அதில் உள்ள பயன்பாடுகளைச் சிதைக்கும் அல்லது தவறாகச் செயல்படும் வகையில் பாதிப்பை ஏற்படுத்தும்."</string> @@ -372,6 +377,10 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"பின்புல ஆப்ஸுக்கு, ஆப்ஸ் பதிலளிக்கவில்லை என்ற செய்தியைக் காட்டும்"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"அறிவிப்புச் சேனல் எச்சரிக்கைகளைக் காட்டு"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"ஆப்ஸானது சரியான சேனல் இல்லாமல் அறிவிப்பை இடுகையிடும் போது, திரையில் எச்சரிக்கையைக் காட்டும்"</string> + <!-- no translation found for enforce_shortcuts_for_conversations (7040735163945040763) --> + <skip /> + <!-- no translation found for enforce_shortcuts_for_conversations_summary (1860168037282467862) --> + <skip /> <string name="force_allow_on_external" msgid="9187902444231637880">"ஆப்ஸை வெளிப்புறச் சேமிப்பிடத்தில் அனுமதி"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், எல்லா ஆப்ஸையும் வெளிப்புறச் சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"செயல்பாடுகளை அளவுமாறக்கூடியதாக அமை"</string> @@ -418,7 +427,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="1284746051652993443">"வண்ணத் திருத்தத்தைப் பயன்படுத்தி உங்கள் சாதனத்தில் வண்ணம் காண்பிக்கப்படும் விதத்தைச் சரிசெய்யலாம்"</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> @@ -432,8 +441,7 @@ <string name="power_discharge_by" msgid="4113180890060388350">"<xliff:g id="TIME">%1$s</xliff:g> வரை பயன்படுத்த முடியும் (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="92545648425937000">"<xliff:g id="TIME">%1$s</xliff:g> வரை பயன்படுத்த முடியும்"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> வரை"</string> - <!-- no translation found for power_suggestion_battery_run_out (6332089307827787087) --> - <skip /> + <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"<xliff:g id="TIME">%1$s</xliff:g>க்கு பேட்டரி காலியாகிவிடக்கூடும்"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g>க்கும் குறைவாகவே பயன்படுத்த முடியும்"</string> <string name="power_remaining_less_than_duration" msgid="1812668275239801236">"<xliff:g id="THRESHOLD">%1$s</xliff:g>க்கும் குறைவாகவே பயன்படுத்த முடியும் (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>க்கும் மேல் பயன்படுத்த முடியும் (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -511,32 +519,21 @@ <string name="media_transfer_this_device_name" msgid="2716555073132169240">"மொபைல் ஸ்பீக்கர்"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"இணைப்பதில் சிக்கல். சாதனத்தை ஆஃப் செய்து மீண்டும் ஆன் செய்யவும்"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"வயருடன்கூடிய ஆடியோ சாதனம்"</string> - <!-- no translation found for help_label (3528360748637781274) --> - <skip /> - <!-- no translation found for storage_category (2287342585424631813) --> - <skip /> - <!-- no translation found for shared_data_title (1017034836800864953) --> - <skip /> - <!-- no translation found for shared_data_summary (5516326713822885652) --> - <skip /> + <string name="help_label" msgid="3528360748637781274">"உதவியும் கருத்தும்"</string> + <string name="storage_category" msgid="2287342585424631813">"சேமிப்பகம்"</string> + <string name="shared_data_title" msgid="1017034836800864953">"பகிரப்பட்ட தரவு"</string> + <string name="shared_data_summary" msgid="5516326713822885652">"பகிரப்பட்ட தரவைப் பார்க்கலாம், மாற்றலாம்"</string> <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"இந்தப் பயனருடன் பகிரப்பட்ட தரவு எதுவும் இல்லை."</string> <string name="shared_data_query_failure_text" msgid="3489828881998773687">"பகிரப்பட்ட தரவைப் பெறுவதில் பிழை. மீண்டும் முயலவும்."</string> - <!-- no translation found for blob_id_text (8680078988996308061) --> - <skip /> - <!-- no translation found for blob_expires_text (7882727111491739331) --> - <skip /> + <string name="blob_id_text" msgid="8680078988996308061">"பகிர்ந்த தரவு ஐடி: <xliff:g id="BLOB_ID">%d</xliff:g>"</string> + <string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g> அன்று காலாவதியாகும்"</string> <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"பகிரப்பட்ட தரவை நீக்குவதில் பிழை."</string> <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"இந்தப் பகிரப்பட்ட தரவிற்காகப் பெறப்பட்ட ஒப்பந்தங்கள் எதுவும் இல்லை. இதை நீக்க விரும்புகிறீர்களா?"</string> - <!-- no translation found for accessor_info_title (8289823651512477787) --> - <skip /> - <!-- no translation found for accessor_no_description_text (7510967452505591456) --> - <skip /> - <!-- no translation found for accessor_expires_text (4625619273236786252) --> - <skip /> - <!-- no translation found for delete_blob_text (2819192607255625697) --> - <skip /> - <!-- no translation found for delete_blob_confirmation_text (7807446938920827280) --> - <skip /> + <string name="accessor_info_title" msgid="8289823651512477787">"தரவைப் பகிர்ந்துகொள்ளும் ஆப்ஸ்"</string> + <string name="accessor_no_description_text" msgid="7510967452505591456">"ஆப்ஸ் எந்த விளக்கத்தையும் வழங்கவில்லை."</string> + <string name="accessor_expires_text" msgid="4625619273236786252">"<xliff:g id="DATE">%s</xliff:g> அன்று குத்தகை காலாவதியாகும்"</string> + <string name="delete_blob_text" msgid="2819192607255625697">"பகிரப்பட்ட தரவை நீக்கு"</string> + <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"பகிரப்பட்ட இந்தத் தரவை நிச்சயமாக நீக்க வேண்டுமா?"</string> <string name="user_add_user_item_summary" msgid="5748424612724703400">"பயனர்கள் தங்களுக்குச் சொந்தமான ஆப்ஸ் மற்றும் உள்ளடக்கத்தை வைத்திருக்க வேண்டும்"</string> <string name="user_add_profile_item_summary" msgid="5418602404308968028">"உங்கள் கணக்கிலிருந்து ஆப்ஸ் மற்றும் உள்ளடக்கத்திற்கான அணுகலை நீங்கள் வரையறுக்கலாம்"</string> <string name="user_add_user_item_title" msgid="2394272381086965029">"பயனர்"</string> @@ -556,12 +553,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"சுயவிவரத் தகவல்"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"நீங்கள் வரையறுக்கப்பட்டச் சுயவிவரத்தை உருவாக்குவதற்கு முன்பு, உங்கள் ஆப்ஸ் மற்றும் தனிப்பட்ட தரவைப் பாதுகாக்கும் வகையில் நீங்கள் திரைப் பூட்டை அமைக்க வேண்டும்."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"பூட்டை அமை"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>க்கு மாறு"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"கெஸ்ட்டைச் சேர்"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"கெஸ்ட்டை அகற்று"</string> + <string name="guest_nickname" msgid="6332276931583337261">"கெஸ்ட்"</string> </resources> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index 0e763ddc7207..cead9dfc53a7 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"వైర్లెస్ డీబగ్గింగ్"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"అందుబాటులో వున్న పరికరాలను చూడటానికి, ఉపయోగించడానికి, వైర్లెస్ డీబగ్గింగ్ను ఆన్ చేయండి"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR కోడ్తో పరికరాన్ని పెయిర్ చేయండి"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR కోడ్ స్కానర్ను ఉపయోగించి కొత్త పరికరాలను పెయిర్ చేయండి"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR కోడ్ స్కానర్ను ఉపయోగించి కొత్త పరికరాలను పెయిర్ చేయండి"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"పెయిరింగ్ కోడ్తో పరికరాన్ని పెయిర్ చేయండి"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ఆరు అంకెల కోడ్ను ఉపయోగించి కొత్త పరికరాలను పెయిర్ చేయండి"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"పెయిర్ చేయబడిన పరికరాలు"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"పరికరాన్ని పెయిర్ చేయడం విఫలమైంది. QR కోడ్ తప్పుగా ఉండడం గాని, లేదా పరికరం అదే నెట్వర్క్కు కనెక్ట్ అయి లేకపోవడం గాని జరిగింది."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP చిరునామా & పోర్ట్"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR కోడ్ను స్కాన్ చేయండి"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"పరికరాన్ని Wi-Fi ద్వారా పెయిర్ చేయడానికి QR కోడ్ను స్కాన్ చేయండి"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR కోడ్ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చెయ్యండి"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"దయచేసి Wi-Fi నెట్వర్క్కు కనెక్ట్ చేయండి"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, డీబగ్, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"బగ్ నివేదిక షార్ట్కట్"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"వైర్లెస్ ప్రదర్శన ప్రామాణీకరణ"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi విశదీకృత లాగింగ్ను ప్రారంభించండి"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi స్కాన్ కుదింపు"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"మొబైల్ డేటాని ఎల్లప్పుడూ యాక్టివ్గా ఉంచు"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"టెథెరింగ్ హార్డ్వేర్ వేగవృద్ధి"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"పేర్లు లేని బ్లూటూత్ పరికరాలు చూపించు"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"వైర్లెస్ ప్రదర్శన సర్టిఫికెట్ కోసం ఎంపికలను చూపు"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ఎంపికలో SSID RSSI ప్రకారం చూపబడే Wi‑Fi లాగింగ్ స్థాయిని పెంచండి"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"బ్యాటరీ శక్తి వినియోగాన్ని తగ్గించి & నెట్వర్క్ పనితీరును మెరుగుపరుస్తుంది"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"గణించబడుతోంది"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"గణించబడటం లేదు"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"లాగర్ బఫర్ పరిమాణాలు"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"నేపథ్య యాప్ల కోసం యాప్ ప్రతిస్పందించడం లేదు అనే డైలాగ్ను చూపు"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"ఛానెల్ హెచ్చరికల నోటిఫికేషన్ను చూపు"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"చెల్లుబాటు అయ్యే ఛానెల్ లేకుండా యాప్ నోటిఫికేషన్ను పోస్ట్ చేస్తున్నప్పుడు స్క్రీన్పై హెచ్చరికను చూపిస్తుంది"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"సంభాషణ నోటిఫికేషన్లకు షార్ట్కట్ల అమలు"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"సంభాషణల విభాగంలో కనిపించడానికి చిరకాలం నిలిచిపోయే భాగస్వామ్య సత్వరమార్గం ద్వారా నోటిఫికేషన్లకు మద్దతు ఉండాలి."</string> <string name="force_allow_on_external" msgid="9187902444231637880">"యాప్లను బాహ్య నిల్వలో తప్పనిసరిగా అనుమతించు"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"ఏ యాప్ని అయినా మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా బాహ్య నిల్వలో సేవ్ చేయడానికి అనుమతిస్తుంది"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"కార్యకలాపాల విండోల పరిమాణం మార్చగలిగేలా నిర్బంధించు"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index b24f006ddbe6..64fa9fb68c7d 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -23,7 +23,7 @@ <string name="wifi_fail_to_scan" msgid="2333336097603822490">"ไม่สามารถสแกนหาเครือข่าย"</string> <string name="wifi_security_none" msgid="7392696451280611452">"ไม่มี"</string> <string name="wifi_remembered" msgid="3266709779723179188">"บันทึกแล้ว"</string> - <string name="wifi_disconnected" msgid="7054450256284661757">"เลิกเชื่อมต่อแล้ว"</string> + <string name="wifi_disconnected" msgid="7054450256284661757">"ยกเลิกการเชื่อมต่อแล้ว"</string> <string name="wifi_disabled_generic" msgid="2651916945380294607">"ปิดอยู่"</string> <string name="wifi_disabled_network_failure" msgid="2660396183242399585">"การกำหนดค่า IP ล้มเหลว"</string> <string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"ไม่ได้เชื่อมต่อเนื่องจากเครือข่ายคุณภาพต่ำ"</string> @@ -35,7 +35,7 @@ <string name="wifi_not_in_range" msgid="1541760821805777772">"ไม่อยู่ในพื้นที่ให้บริการ"</string> <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"จะไม่เชื่อมต่อโดยอัตโนมัติ"</string> <string name="wifi_no_internet" msgid="1774198889176926299">"เข้าถึงอินเทอร์เน็ตไม่ได้"</string> - <string name="saved_network" msgid="7143698034077223645">"บันทึกโดย <xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string> + <string name="saved_network" msgid="7143698034077223645">"บันทึกโดย<xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string> <string name="connected_via_network_scorer" msgid="7665725527352893558">"เชื่อมต่ออัตโนมัติผ่าน %1$s แล้ว"</string> <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"เชื่อมต่ออัตโนมัติผ่านผู้ให้บริการการจัดอันดับเครือข่าย"</string> <string name="connected_via_passpoint" msgid="7735442932429075684">"เชื่อมต่อผ่าน %1$s แล้ว"</string> @@ -155,7 +155,7 @@ <string name="launch_defaults_some" msgid="3631650616557252926">"ตั้งค่าเริ่มต้นไว้บางส่วน"</string> <string name="launch_defaults_none" msgid="8049374306261262709">"ไม่ได้ตั้งค่าเริ่มต้น"</string> <string name="tts_settings" msgid="8130616705989351312">"การตั้งค่าการอ่านออกเสียงข้อความ"</string> - <string name="tts_settings_title" msgid="7602210956640483039">"เอาต์พุตการอ่านออกเสียง"</string> + <string name="tts_settings_title" msgid="7602210956640483039">"เอาต์พุตการอ่านออกเสียงข้อความ"</string> <string name="tts_default_rate_title" msgid="3964187817364304022">"ความเร็วของคำพูด"</string> <string name="tts_default_rate_summary" msgid="3781937042151716987">"ความเร็วในการพูดข้อความ"</string> <string name="tts_default_pitch_title" msgid="6988592215554485479">"ความสูง-ต่ำของเสียง"</string> @@ -196,7 +196,7 @@ <string name="choose_profile" msgid="343803890897657450">"เลือกโปรไฟล์"</string> <string name="category_personal" msgid="6236798763159385225">"ส่วนตัว"</string> <string name="category_work" msgid="4014193632325996115">"ที่ทำงาน"</string> - <string name="development_settings_title" msgid="140296922921597393">"สำหรับนักพัฒนาซอฟต์แวร์"</string> + <string name="development_settings_title" msgid="140296922921597393">"ตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์"</string> <string name="development_settings_enable" msgid="4285094651288242183">"เปิดใช้ตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์"</string> <string name="development_settings_summary" msgid="8718917813868735095">"ตั้งค่าตัวเลือกสำหรับการพัฒนาแอปพลิเคชัน"</string> <string name="development_settings_not_available" msgid="355070198089140951">"ตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์ไม่สามารถใช้ได้สำหรับผู้ใช้นี้"</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"การแก้ไขข้อบกพร่องผ่าน Wi-Fi"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"หากต้องการดูและใช้อุปกรณ์ที่มีอยู่ ให้เปิดการแก้ไขข้อบกพร่องผ่าน Wi-Fi"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"จับคู่อุปกรณ์ด้วยคิวอาร์โค้ด"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"จับคู่อุปกรณ์เครื่องใหม่โดยใช้เครื่องมือสแกนคิวอาร์โค้ด"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"จับคู่อุปกรณ์เครื่องใหม่โดยใช้เครื่องมือสแกนคิวอาร์โค้ด"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"จับคู่อุปกรณ์ด้วยรหัสการจับคู่"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"จับคู่อุปกรณ์เครื่องใหม่โดยใช้รหัสตัวเลข 6 หลัก"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"อุปกรณ์ที่จับคู่"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"จับคู่อุปกรณ์ไม่สำเร็จ คิวอาร์โค้ดไม่ถูกต้อง หรืออุปกรณ์ไม่ได้เชื่อมต่อกับเครือข่ายเดียวกัน"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"ที่อยู่ IP และพอร์ต"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"สแกนคิวอาร์โค้ด"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"จับคู่อุปกรณ์ผ่าน Wi‑Fi ด้วยการสแกนคิวอาร์โค้ด"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"จับคู่อุปกรณ์ผ่าน Wi‑Fi ด้วยการสแกนคิวอาร์โค้ด"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"โปรดเชื่อมต่อกับเครือข่าย Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, แก้ไขข้อบกพร่อง, พัฒนา"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ทางลัดรายงานข้อบกพร่อง"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"การรับรองการแสดงผลแบบไร้สาย"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"เปิดใช้การบันทึกรายละเอียด Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"การควบคุมการสแกนหา Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"การสุ่ม MAC เพื่อเพิ่มความปลอดภัย Wi-Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"เปิดใช้เน็ตมือถือเสมอ"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"การเร่งฮาร์ดแวร์การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"แสดงอุปกรณ์บลูทูธที่ไม่มีชื่อ"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"แสดงตัวเลือกสำหรับการรับรองการแสดงผล แบบไร้สาย"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ลดการเปลืองแบตเตอรี่และเพิ่มประสิทธิภาพเครือข่าย"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"การตั้งค่านี้ส่งผลต่อลักษณะการสุ่ม MAC ในโหมดไคลเอ็นต์เท่านั้น\nเมื่อเปิดใช้งานโหมดนี้ ทุกเครือข่ายที่มีการเปิดใช้การสุ่ม MAC อาจสุ่มที่อยู่ MAC ซ้ำในระหว่างการเชื่อมโยง ทั้งนี้ขึ้นอยู่กับว่าไคลเอ็นต์ยกเลิกการเชื่อมต่อกับเครือข่ายครั้งสุดท้ายเมื่อใด การสุ่มซ้ำจะไม่เกิดขึ้นหากอุปกรณ์เชื่อมต่ออีกครั้งภายในไม่เกิน 4 ชั่วโมง"</string> <string name="wifi_metered_label" msgid="8737187690304098638">"มีการวัดปริมาณอินเทอร์เน็ต"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"ไม่มีการวัดปริมาณอินเทอร์เน็ต"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"ขนาดบัฟเฟอร์ของตัวบันทึก"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"แสดงกล่องโต้ตอบ \"แอปไม่ตอบสนอง\" สำหรับแอปพื้นหลัง"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"แสดงคำเตือนจากช่องทางการแจ้งเตือน"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"แสดงคำเตือนบนหน้าจอเมื่อแอปโพสต์การแจ้งเตือนโดยไม่มีช่องทางที่ถูกต้อง"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"บังคับใช้ทางลัดสำหรับการแจ้งเตือนการสนทนา"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"ต้องทำให้การแจ้งเตือนปรากฏในส่วนการสนทนาได้อีกถ้ามีการปิดไปโดยใช้ทางลัดการแชร์ที่แสดงอยู่ตลอด"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"บังคับให้แอปสามารถใช้ที่เก็บภายนอก"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"เขียนแอปในพื้นที่เก็บข้อมูลภายนอกได้ โดยไม่คำนึงถึงค่าไฟล์ Manifest"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"บังคับให้กิจกรรมปรับขนาดได้"</string> @@ -443,11 +447,11 @@ <string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"แท็บเล็ตอาจปิดเครื่องในไม่ช้า (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"อุปกรณ์อาจปิดเครื่องในไม่ช้า (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string> <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string> - <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"เหลือ <xliff:g id="TIME">%1$s</xliff:g> จนกว่าจะชาร์จ"</string> + <string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"เหลือ <xliff:g id="TIME">%1$s</xliff:g> จนกว่าจะชาร์จเต็ม"</string> <string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะชาร์จ"</string> <string name="battery_info_status_unknown" msgid="268625384868401114">"ไม่ทราบ"</string> <string name="battery_info_status_charging" msgid="4279958015430387405">"กำลังชาร์จ"</string> - <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"กำลังชาร์จเร็ว"</string> + <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"กำลังชาร์จอย่างเร็ว"</string> <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"กำลังชาร์จอย่างช้าๆ"</string> <string name="battery_info_status_discharging" msgid="6962689305413556485">"ไม่ได้ชาร์จ"</string> <string name="battery_info_status_not_charging" msgid="8330015078868707899">"เสียบอยู่ ไม่สามารถชาร์จได้ในขณะนี้"</string> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index 8d70718c98c3..d3af3984789f 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -112,7 +112,7 @@ <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Ginagamit para sa paglilipat ng file"</string> <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Gamitin para sa input"</string> <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Gamitin para sa Mga Hearing Aid"</string> - <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Pares"</string> + <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Ipares"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"IPARES"</string> <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Kanselahin"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Nagbibigay ang pagpapares ng access sa iyong mga contact at history ng tawag kapag nakakonekta."</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Wireless na pag-debug"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para makita at magamit ang mga available na device, i-on ang wireless na pag-debug"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Magpares ng device gamit ang QR code"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Magpares ng mga bagong device gamit ang QR code Scanner"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Magpares ng mga bagong device gamit ang pang-scan ng QR code"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Pinapares ang device gamit ang code ng pagpapares"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Magpares ng mga bagong device gamit ang six digit na code"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Mga nakapares na device"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Hindi nagawang ipares ang device. Hindi tama ang QR code, o hindi nakakonekta ang device sa parehong network."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP address at Port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"I-scan ang QR code"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Ipares ang device gamit ang Wi‑Fi sa pamamagitan ng pag-scan ng isang QR Code"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Magpares ng device gamit ang Wi‑Fi sa pamamagitan ng pag-scan ng isang QR code"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Kumonekta sa Wi-Fi network"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Shortcut ng ulat sa bug"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Certification ng wireless display"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"I-enable ang Pagla-log sa Wi‑Fi Verbose"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Pag-throttle ng pag-scan ng Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"MAC randomization na pinahusay ng Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Palaging aktibo ang mobile data"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Hardware acceleration para sa pag-tether"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ipakita ang mga Bluetooth device na walang pangalan"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Ipakita ang mga opsyon para sa certification ng wireless display"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Pataasin ang antas ng Wi‑Fi logging, ipakita sa bawat SSID RSSI sa Wi‑Fi Picker"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Binabawasan ang pagkaubos ng baterya at pinapahusay ang performance ng network"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Nakakaapekto ang toggle na ito sa pag-kilos ng pag-randomize ng MAC para lang sa client mode.\nKapag na-activate ang mode na ito, baka ma-randomize ulit ang MAC address ng anumang network na naka-enable ang pag-randomize sa MAC habang nagaganap ang pag-uugnay, depende kung kailan huling nadiskonekta ang client sa network. Hindi nangyayari ang pag-randomize ulit kung kumonekta ulit ang device sa loob ng 4 na oras o mas maaga."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Nakametro"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Hindi Nakametro"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Mga laki ng buffer ng Logger"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Ipakita ang dialog na Hindi Tumutugon ang App para sa mga app sa background"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Ipakita ang mga babala sa notification channel"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Nagpapakita ng babala sa screen kapag nag-post ang app ng notification nang walang wastong channel"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Magpatupad ng mga shortcut para sa mga notification ng pag-uusap"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Ipa-back up ang mga notification gamit ang long-lived na shortcut sa pagbabahagi para lumabas sa seksyong pag-uusap"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Puwersahang payagan ang mga app sa external"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Ginagawang kwalipikado ang anumang app na mailagay sa external na storage, anuman ang mga value ng manifest"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Sapilitang gawing resizable ang mga aktibidad"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 3579957fc00c..44238da73e30 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Kablosuz hata ayıklama"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Mevcut cihazları görmek ve kullanmak için kablosuz hata ayıklamayı açın"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Cihazı QR kodu ile eşle"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Yeni cihazları QR kodu Tarayıcıyı kullanarak eşleyin"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Yeni cihazları QR kodu tarayıcıyı kullanarak eşleyin"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Eşleme kodu ile cihaz eşleme"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Yeni cihazları altı basamaklı kodu kullanarak eşleyin"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Eşlenen cihazlar"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Cihaz eşlenemedi. QR kodu hatalı ya da cihaz aynı ağa bağlı değil."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP adresi ve Bağlantı noktası"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR kodunu tara"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR kodu tarayarak kablosuz ağ üzerinden cihaz eşleyin"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR kodu tarayarak kablosuz ağ üzerinden cihaz eşleyin"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Lütfen Kablosuz bir ağa bağlanın"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, hata ayıklama, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Hata raporu kısayolu"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Kablosuz ekran sertifikası"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Kablosuz Ayrıntılı Günlük Kaydını etkinleştir"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Kablosuz ağ taramasını kısma"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Kablosuz için geliştirilmiş MAC rastgele seçimi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobil veri her zaman etkin"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tethering donanım hızlandırıcısı"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Adsız Bluetooth cihazlarını göster"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Kablosuz ekran sertifikası seçeneklerini göster"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Kablosuz günlük kaydı seviyesini artır. Kablosuz Seçici\'de her bir SSID RSSI için göster."</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Pili daha az harcar ve ağ performansını iyileştirir"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Bu geçiş, yalnızca istemci modu için MAC rastgele hale getirme davranışını etkiler.\nBu mod etkinleştirildiğinde, MAC rastgele seçimi etkin olan tüm ağların MAC adresleri, istemcinin ağla bağlantısının en son kesildiği zamana bağlı olarak ilişkilendirme sırasında yeniden rastgele seçilebilir. Cihaz 4 saat veya daha kısa süre içinde tekrar bağlanırsa yeniden rastgele hale getirme gerçekleşmez."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Sayaçlı"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Sayaçsız"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Günlük Kaydedici arabellek boyutları"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Arka plan uygulamalar için Uygulama Yanıt Vermiyor mesajını göster"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Bildirim kanalı uyarılarını göster"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Bir uygulama geçerli kanal olmadan bildirim yayınladığında ekranda uyarı gösterir"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Görüşme bildirimleri için kısayolları zorunlu kıl"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Bildirimlerin, görüşme bölümünde görünebilmesi için uzun ömürlü paylaşma kısayolu ile desteklenmesini gerektir"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Harici birimdeki uygulamalara izin vermeye zorla"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Manifest değerlerinden bağımsız olarak uygulamaları harici depolamaya yazmak için uygun hale getirir"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Etkinlikleri yeniden boyutlandırılabilmeye zorla"</string> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index 5dae4f0a63c6..60aa1a9abaaa 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"Налагодження USB"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Вмикати налагодження, коли телефон підключено через USB"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Скасувати доступ до налагодження USB"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Бездротове налагодження"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Налагодження через Wi-Fi"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Вмикати режим налагодження, коли пристрій підключено до мережі Wi-Fi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Помилка"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Бездротове налагодження"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Щоб переглядати та використовувати доступні пристрої, увімкніть бездротове налагодження"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Налагодження через Wi-Fi"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Щоб переглядати та використовувати доступні пристрої, увімкніть налагодження через Wi-Fi"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Підключати пристрій за допомогою QR-коду"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Підключати нові пристрої за допомогою сканера QR-кодів"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Підключати нові пристрої за допомогою сканера QR-кодів"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Підключати пристрій за допомогою коду підключення"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Підключати нові пристрої за допомогою шестизначного коду"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Підключені пристрої"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Не вдалося підключитися до пристрою. Надано неправильний QR-код або пристрій не підключено до тієї ж мережі."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-адреса та порт"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Сканувати QR-код"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Підключати пристрій через Wi‑Fi за допомогою QR-коду"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Підключати пристрій через Wi‑Fi за допомогою QR-коду"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Підключіть пристрій до мережі Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, налагодження, розробка"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Ярлик звіту про помилки"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Сертифікація бездрот. екрана"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Докладний запис у журнал Wi-Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Зменшити радіус пошуку мереж Wi‑Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Довільний вибір MAC-адрес із Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Не вимикати мобільне передавання даних"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Апаратне прискорення під час використання телефона в режимі модема"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показувати пристрої Bluetooth без назв"</string> @@ -273,16 +274,17 @@ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"Кодек для аудіо Bluetooth LDAC: якість відтворення"</string> <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"Активувати LDAC для аудіо Bluetooth\nВибір кодека: якість відтворення"</string> <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"Трансляція: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string> - <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"Приватна DNS"</string> - <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Режим приватної системи DNS"</string> + <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"Приватний DNS-сервер"</string> + <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Режим приватного DNS-сервера"</string> <string name="private_dns_mode_off" msgid="7065962499349997041">"Вимкнено"</string> <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Автоматично"</string> - <string name="private_dns_mode_provider" msgid="3619040641762557028">"Ім’я хосту приватного постачальника послуг DNS"</string> + <string name="private_dns_mode_provider" msgid="3619040641762557028">"Ім’я хосту постачальника приватного DNS-сервера"</string> <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Введіть ім’я хосту постачальника послуг DNS"</string> <string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"Не вдалося під’єднатися"</string> <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показати параметри сертифікації бездротового екрана"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Показувати в журналі RSSI для кожного SSID під час вибору Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Зменшує споживання заряду акумулятора й підвищує ефективність роботи мережі"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Цей перемикач впливає на поведінку довільного вибору MAC-адрес лише для клієнтського режиму.\nКоли цей режим активовано, MAC-адреси мереж із довільним вибором цих адрес переназначаються під час зв\'язування залежно від часу останнього відключення клієнта від мережі. Повторний довільний вибір адрес не відбувається, якщо пристрій знову підключається протягом 4 годин."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"З тарифікацією трафіку"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Без тарифікації трафіку"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Розміри буфера журналу"</string> @@ -300,8 +302,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Якщо доступно, вмикати апаратне прискорення під час використання телефона в режимі модема"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Дозвол. налагодж. USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"Налагодження USB застосовується лише з метою розробки. Його можна використовувати для копіювання даних між комп’ютером і пристроєм, встановлення програм на вашому пристрої без сповіщення та читання даних журналу."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Дозволити бездротове налагодження?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Бездротове налагодження застосовується лише з метою розробки. Його можна використовувати, щоб копіювати дані між комп\'ютером і пристроєм, встановлювати додатки на пристрої без сповіщення та переглядати дані журналу."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Дозволити налагодження через Wi-Fi?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Налагодження через Wi-Fi застосовується лише з метою розробки. Його можна використовувати, щоб копіювати дані між комп\'ютером і пристроєм, встановлювати додатки на пристрої без сповіщення та переглядати дані журналу."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Скасувати доступ до налагодження USB для всіх комп’ютерів, які раніше отримали таке право?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Дозволити налаштування розробки?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Ці налаштування застосовуються лише з метою розробки. Вони можуть спричиняти вихід з ладу або неправильне функціонування вашого пристрою чи програм у ньому."</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Показувати вікно \"Додаток не відповідає\" для додатків у фоновому режимі"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Показувати застереження про канал"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"З’являється застереження, коли додаток надсилає сповіщення через недійсний канал"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Використовувати ярлики для сповіщень про чати"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Вимагати для сповіщень постійних ярликів доступу, щоб показувати їх у розділі чатів"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Примусово записувати додатки в зовнішню пам’ять"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Можна записувати додатки в зовнішню пам’ять, незалежно від значень у маніфесті"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Примусово масштабувати активність"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index ce25f2f83af4..ac56cf7dae13 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"وائرلیس ڈیبگنگ"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"دستیاب آلات کو دیکھنے اور استعمال کرنے کے لیے، وائرلیس ڈیبگنگ آن کریں"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR کوڈ کے ذریعے آلہ کا جوڑا بنائیں"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR کوڈ اسکینر کا استعمال کر کے نئے آلہ کا جوڑا بنائیں"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR کوڈ اسکینر کا استعمال کر کے نئے آلات کا جوڑا بنائیں"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"جوڑا بنانے کے کوڈ کے ذریعے آلہ کا جوڑا بنائیں"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"چھ ہندسوں کا کوڈ استعمال کر کے نئے آلات کا جوڑا بنائیں"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"جوڑا بنائے گئے آلات"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"آلہ کا جوڑا بنانے میں ناکام۔ یا تو QR کوڈ غلط تھا، یا آلہ اسی نیٹ ورک سے منسلک نہیں ہے۔"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP پتہ اور پورٹ"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR کوڈ اسکین کریں"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR کوڈ اسکین کر کے Wi-Fi پر آلہ کا جوڑا بنائیں"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR کوڈ اسکین کر کے Wi-Fi پر آلہ کا جوڑا بنائیں"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"براہ کرم ایک Wi-Fi نیٹ ورک سے منسلک ہوں"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb، ڈیبگ، dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"بگ رپورٹ کا شارٹ کٹ"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"وائرلیس ڈسپلے سرٹیفیکیشن"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi وربوس لاگنگ فعال کریں"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi اسکین کو زبردستی روکا جا رہا ہے"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"بہتر Wi-Fi MAC رینڈمائزیشن"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"موبائل ڈیٹا ہمیشہ فعال رکھیں"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"ٹیدرنگ ہارڈویئر سرعت کاری"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"بغیر نام والے بلوٹوتھ آلات دکھائیں"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"وائرلیس ڈسپلے سرٹیفیکیشن کیلئے اختیارات دکھائیں"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi لاگنگ لیول میں اضافہ کریں، Wi‑Fi منتخب کنندہ میں فی SSID RSSI دکھائیں"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"بیٹری ڈرین کم کرتا ہے اور نیٹ ورک کارکردگی کو بہتر بناتا ہے"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"یہ ٹوگل صرف کلائنٹ وضع کے لئے MAC کی رینڈمائزیشن کو متاثر کرتا ہے۔\nجب یہ وضع فعال کی جاتی ہے، تو کسی بھی نیٹ ورکس میں جو MAC رینڈمائزیشن کو فعال کرتا ہے ان کے MAC ایڈریسز ایسوسی ایشن کے دوران دوبارہ رینڈمائز ہو سکتے ہیں، اس پر منحصر ہے کہ کلائنٹ کب آخری بار نیٹ ورک سے غیر منسلک ہوا۔ اگر آلہ 4 گھنٹوں یا اس سے کم وقت میں دوبارہ منسلک ہو، تو پھر دوبارہ رینڈمائزیشن کا امکان نہیں ہوتا ہے۔"</string> <string name="wifi_metered_label" msgid="8737187690304098638">"میٹرڈ"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"غیر میٹر شدہ"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"لاگر بفر کے سائز"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"پس منظر کی ایپس کیلئے \'ایپ جواب نہیں دے رہی ہے\' ڈائلاگ ڈسپلے کریں"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"چینل کی اطلاعی تنبیہات دکھائیں"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"کسی ایپ کی طرف سے درست چینل کے بغیر اطلاع پوسٹ ہونے پر آن اسکرین تنبیہ ڈسپلے کرتا ہے"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"بات چیت کی اطلاعات کے لیے شارٹ کٹس نافذ کریں"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"بات چیت کے سیکشن میں ظاہر ہونے کے لئے اطلاعات کو طویل مدت والے شیئرنگ شارٹ کٹ کے ذریعے حمایت کی ضرورت ہے"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"بیرونی پر ایپس کو زبردستی اجازت دیں"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"manifest اقدار سے قطع نظر، کسی بھی ایپ کو بیرونی اسٹوریج پر لکھے جانے کا اہل بناتا ہے"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"سرگرمیوں کو ری سائز ایبل بنائیں"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index 07f3a6e9c5ba..ef5ae787a1e6 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -206,13 +206,13 @@ <string name="enable_adb" msgid="8072776357237289039">"USB orqali nosozliklarni aniqlash"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"USB orqali kompyuterga ulanganda tuzatish rejimi yoqilsin"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB orqali nosozliklarni tuzatishni taqiqlash"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Simsiz nosozliklarni aniqlash"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Wi-Fi orqali debagging"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi tarmoqqa ulanganda nosozliklarni aniqlash rejimi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Xato"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Simsiz nosozliklarni aniqlash"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Mavjud qurilmalarni koʻrish va ulardan foydalanish uchun simsiz nosozliklarni aniqlash funksiyasini yoqing"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Wi-Fi orqali debagging"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Mavjud qurilmalarni koʻrish va ulardan foydalanish uchun Wi-Fi orqali debagging funksiyasini yoqing"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR kod yordamida qurilmani ulang"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"QR kod skaneri yordamida yangi qurilmalarni ulash mumkin"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR kod skaneri yordamida yangi qurilmalarni ulash mumkin"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Ulanish kodi yordamida qurilmani ulang"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Olti xonali kod yordamida yangi qurilmalarni ulash mumkin"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Ulangan qurilmalar"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Qurilma ulanmadi. QR kod xato yoki qurilma bir xil tarmoqqa ulanmagan."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP manzil va port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR kodni skanerlash"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR kodni skanerlab, Wi-Fi orqali qurilmani ulang"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR kodni skanerlab, Wi-Fi orqali qurilmani ulang"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Wi-Fi tarmoqqa ulaning"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debag, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Xatoliklar hisoboti"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Simsiz monitor sertifikatlari"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Batafsil Wi-Fi jurnali"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi tarmoqni taqsimlab skanlash"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobil internet doim yoniq tursin"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"Modem rejimida apparatli tezlashtirish"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth qurilmalarini nomlarisiz ko‘rsatish"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Simsiz monitorlarni sertifikatlash parametrini ko‘rsatish"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi-Fi ulanishini tanlashda har bir SSID uchun jurnalda ko‘rsatilsin"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Batareya sarfini tejaydi va tarmoq samaradorligini oshiradi"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"Trafik hisoblanadigan tarmoq"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Trafik hisobi yuritilmaydigan tarmoq"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Jurnal buferi hajmi"</string> @@ -300,8 +304,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Modem rejimida apparatli tezlashtirishdan foydalanish (agar mavjud bo‘lsa)"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB orqali nosozliklarni tuzatishga ruxsat berilsinmi?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB orqali nosozliklarni aniqlash faqat dasturlash maqsadlarida yoqiladi. Undan maʼlumotlarni qurilmangiz va kompyuter o‘rtasida ko‘chirish, ilovalarni xabarnomasiz o‘rnatish va jurnal maʼlumotlarini o‘qish uchun foydalaniladi."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Simsiz nosozliklarni aniqlashga ruxsat berilsinmi?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Simsiz nosozliklarni aniqlash faqat dasturlash maqsadlarida yoqiladi. Undan maʼlumotlarni qurilmangiz va kompyuter oʻrtasida koʻchirish, ilovalarni bildirishnomasiz oʻrnatish va jurnal maʼlumotlarini oʻqish uchun foydalaniladi."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Wi-Fi orqali debagging uchun ruxsat berilsinmi?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Wi-Fi orqali debagging faqat dasturlash maqsadlarida yoqiladi. Undan maʼlumotlarni qurilmangiz va kompyuter oʻrtasida koʻchirish, ilovalarni bildirishnomasiz oʻrnatish va jurnal maʼlumotlarini oʻqish uchun foydalaniladi."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"USB orqali nosozliklarni tuzatishga berilgan ruxsat siz hisobingizga kirgan barcha kompyuterlar uchun bekor qilinsinmi?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Dasturlash sozlamalariga ruxsat berilsinmi?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Bu sozlamalar faqat dasturlash maqsadlariga mo‘ljallangan. Shuning uchun, ular qurilmangizga va undagi ilovalariga shikast yetkazib, noto‘g‘ri ishlashiga sabab bo‘lishi mumkin."</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Ilova javob bermayotgani haqida xabar qilish"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Xabarlar kanali ogohlantirishlarini ko‘rsatish"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Yaroqli kanalsiz yuborilgan yangi ilova xabarnomalari haqida ogohlantirishlarni ko‘rsatish"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Suhbat bildirishnomalari uchun yorliqlardan majburiy foydalanish"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Bildirishnoma suhbat qismida chiqishi uchun uzoq koʻrinadigan belgilar yordamida ularni nusxalash kerak"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Tashqi xotira qurilmasidagi ilova dasturlariga majburiy ruxsat berish"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Manifest qiymatidan qat’i nazar istalgan ilovani tashqi xotiraga saqlash imkonini beradi"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Harakatlarni moslashuvchan o‘lchamga keltirish"</string> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index 10ac60df77c0..b3e73fe41c00 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -99,7 +99,7 @@ <string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Đã kết nối với âm thanh điện thoại"</string> <string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Đã kết nối với máy chủ chuyển tệp"</string> <string name="bluetooth_map_profile_summary_connected" msgid="4141725591784669181">"Đã kết nối với bản đồ"</string> - <string name="bluetooth_sap_profile_summary_connected" msgid="1280297388033001037">"Được kết nối với SAP"</string> + <string name="bluetooth_sap_profile_summary_connected" msgid="1280297388033001037">"Đã kết nối với SAP"</string> <string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"Chưa kết nối với máy chủ chuyển tệp"</string> <string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"Đã kết nối với thiết bị nhập"</string> <string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"Đã kết nối với thiết bị để truy cập Internet"</string> @@ -143,11 +143,11 @@ <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Ứng dụng đã xóa"</string> <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Ứng dụng và người dùng bị xóa"</string> <string name="data_usage_ota" msgid="7984667793701597001">"Bản cập nhật hệ thống"</string> - <string name="tether_settings_title_usb" msgid="3728686573430917722">"Chia sẻ kết nối Internet qua USB"</string> + <string name="tether_settings_title_usb" msgid="3728686573430917722">"Chia sẻ Internet qua USB"</string> <string name="tether_settings_title_wifi" msgid="4803402057533895526">"Điểm phát sóng di động"</string> - <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Chia sẻ kết nối Internet qua Bluetooth"</string> - <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Đang dùng làm điểm truy cập Internet"</string> - <string name="tether_settings_title_all" msgid="8910259483383010470">"USB Internet & điểm truy cập di động"</string> + <string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Chia sẻ Internet qua Bluetooth"</string> + <string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Chia sẻ Internet"</string> + <string name="tether_settings_title_all" msgid="8910259483383010470">"Chia sẻ Internet và điểm phát sóng di động"</string> <string name="managed_user_title" msgid="449081789742645723">"Tất cả ứng dụng làm việc"</string> <string name="user_guest" msgid="6939192779649870792">"Khách"</string> <string name="unknown" msgid="3544487229740637809">"Không xác định"</string> @@ -201,7 +201,7 @@ <string name="development_settings_summary" msgid="8718917813868735095">"Đặt tùy chọn cho phát triển ứng dụng"</string> <string name="development_settings_not_available" msgid="355070198089140951">"Tùy chọn dành cho nhà phát triển không khả dụng cho người dùng này"</string> <string name="vpn_settings_not_available" msgid="2894137119965668920">"Cài đặt VPN không khả dụng cho người dùng này"</string> - <string name="tethering_settings_not_available" msgid="266821736434699780">"Cài đặt cách chia sẻ kết nối không khả dụng cho người dùng này"</string> + <string name="tethering_settings_not_available" msgid="266821736434699780">"Các tùy chọn cài đặt của tính năng chia sẻ Internet không có sẵn cho người dùng này"</string> <string name="apn_settings_not_available" msgid="1147111671403342300">"Cài đặt tên điểm truy cập không khả dụng cho người dùng này"</string> <string name="enable_adb" msgid="8072776357237289039">"Gỡ lỗi qua USB"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Bật chế độ gỡ lỗi khi kết nối USB"</string> @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Gỡ lỗi qua Wi-Fi"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Để xem và sử dụng các thiết bị có sẵn, hãy bật tính năng gỡ lỗi qua Wi-Fi"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Ghép nối thiết bị bằng mã QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Ghép nối các thiết bị mới bằng Trình quét mã QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Ghép nối các thiết bị mới bằng trình quét mã QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Ghép nối thiết bị bằng mã ghép nối"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Ghép nối các thiết bị mới bằng mã gồm 6 chữ số"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Thiết bị được ghép nối"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Không ghép nối được thiết bị. Mã QR không chính xác hoặc bạn không kết nối thiết bị với cùng một mạng."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Địa chỉ IP và cổng"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Quét mã QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Ghép nối thiết bị qua Wi-Fi bằng cách quét mã QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Ghép nối thiết bị qua Wi-Fi bằng cách quét mã QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Hãy kết nối mạng Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, gỡ lỗi, nhà phát triển"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Phím tắt báo cáo lỗi"</string> @@ -251,8 +251,9 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Chứng nhận hiển thị không dây"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Bật ghi nhật ký chi tiết Wi‑Fi"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Hạn chế quét tìm Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Sắp xếp ngẫu nhiên địa chỉ MAC tăng cường Wi‑Fi"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Dữ liệu di động luôn hoạt động"</string> - <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tăng tốc phần cứng khi chia sẻ kết nối"</string> + <string name="tethering_hardware_offload" msgid="4116053719006939161">"Tăng tốc phần cứng khi chia sẻ Internet"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Hiển thị các thiết bị Bluetooth không có tên"</string> <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Vô hiệu hóa âm lượng tuyệt đối"</string> <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Bật tính năng Gabeldorsche"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Hiển thị tùy chọn chứng nhận hiển thị không dây"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Tăng mức ghi nhật ký Wi‑Fi, hiển thị mỗi SSID RSSI trong bộ chọn Wi‑Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Giảm hao pin và cải thiện hiệu suất mạng"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Thao tác bật/tắt này chỉ ảnh hưởng đến hành vi sắp xếp ngẫu nhiên địa chỉ MAC ở chế độ máy khách.\nKhi bạn kích hoạt chế độ này, tất cả các mạng đã bật tính năng sắp xếp ngẫu nhiên địa chỉ MAC có thể sắp xếp ngẫu nhiên lại địa chỉ MAC của họ trong quá trình liên kết, tùy thuộc vào lần gần đây nhất máy khách ngắt kết nối với mạng. Các mạng này sẽ không thể sắp xếp ngẫu nhiên lại nếu thiết bị kết nối lại trong vòng 4 giờ."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Đo lượng dữ liệu"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Không đo lượng dữ liệu"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Kích thước bộ đệm của trình ghi nhật ký"</string> @@ -297,7 +299,7 @@ <string name="allow_mock_location_summary" msgid="179780881081354579">"Cho phép vị trí mô phỏng"</string> <string name="debug_view_attributes" msgid="3539609843984208216">"Cho phép kiểm tra thuộc tính của chế độ xem"</string> <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Luôn bật dữ liệu di động ngay cả khi Wi-Fi đang hoạt động (để chuyển đổi mạng nhanh)."</string> - <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Sử dụng tính năng tăng tốc phần cứng khi chia sẻ kết nối nếu có"</string> + <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Sử dụng tính năng tăng tốc phần cứng khi chia sẻ Internet nếu có"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Cho phép gỡ lỗi qua USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"Gỡ lỗi USB chỉ dành cho mục đích phát triển. Hãy sử dụng tính năng này để sao chép dữ liệu giữa máy tính và thiết bị của bạn, cài đặt ứng dụng trên thiết bị của bạn mà không thông báo và đọc dữ liệu nhật ký."</string> <string name="adbwifi_warning_title" msgid="727104571653031865">"Bật tính năng gỡ lỗi qua Wi-Fi?"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Hiện hộp thoại Ứng dụng không phản hồi cho các ứng dụng nền"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Hiện cảnh báo kênh thông báo"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Hiện cảnh báo trên màn hình khi ứng dụng đăng thông báo mà không có kênh hợp lệ"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Áp dụng lối tắt cho thông báo của cuộc trò chuyện"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Để xuất hiện trong phần cuộc trò chuyện, thông báo phải có sự hỗ trợ của lối tắt chia sẻ lâu dài"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Buộc cho phép các ứng dụng trên bộ nhớ ngoài"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Cho phép ghi mọi ứng dụng đủ điều kiện vào bộ nhớ ngoài, bất kể giá trị tệp kê khai là gì"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Buộc các hoạt động có thể thay đổi kích thước"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index c24f72dbc072..d972cba8864c 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"无线调试"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"要查看和使用可用的设备,请开启无线调试"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"使用二维码配对设备"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"使用二维码扫描器配对新设备"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"使用二维码扫描器配对新设备"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"使用配对码配对设备"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"使用六位数验证码配对新设备"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"已配对的设备"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"无法配对设备。可能是因为二维码不正确,或者设备未连接到同一网络。"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP 地址和端口"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"扫描二维码"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"扫描二维码即可通过 WLAN 配对设备"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"扫描二维码即可通过 WLAN 配对设备"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"请连接到 WLAN 网络"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, 调试, debug, 开发, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"错误报告快捷方式"</string> @@ -251,6 +251,8 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"无线显示认证"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"启用 WLAN 详细日志记录功能"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"WLAN 扫描调节"</string> + <!-- no translation found for wifi_enhanced_mac_randomization (5437378364995776979) --> + <skip /> <string name="mobile_data_always_on" msgid="8275958101875563572">"始终开启移动数据网络"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"网络共享硬件加速"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"显示没有名称的蓝牙设备"</string> @@ -283,6 +285,8 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"显示无线显示认证选项"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"提升 WLAN 日志记录级别(在 WLAN 选择器中显示每个 SSID 的 RSSI)"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"降低耗电量以及改善网络性能"</string> + <!-- no translation found for wifi_enhanced_mac_randomization_summary (7925425746373704991) --> + <skip /> <string name="wifi_metered_label" msgid="8737187690304098638">"按流量计费"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"不按流量计费"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"日志记录器缓冲区大小"</string> @@ -371,6 +375,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"为后台应用显示“应用无响应”对话框"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"显示通知渠道警告"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"当应用未经有效渠道发布通知时,在屏幕上显示警告"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"强制执行会话通知快捷方式"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"要求通知必须有长期共享快捷方式支持,才能显示在会话部分中"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"强制允许将应用写入外部存储设备"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"允许将任何应用写入外部存储设备(无论清单值是什么)"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"强制将活动设为可调整大小"</string> @@ -464,7 +470,7 @@ <item msgid="7529124349186240216">"100%"</item> </string-array> <string name="charge_length_format" msgid="6941645744588690932">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string> - <string name="remaining_length_format" msgid="4310625772926171089">"还剩 <xliff:g id="ID_1">%1$s</xliff:g>"</string> + <string name="remaining_length_format" msgid="4310625772926171089">"还需 <xliff:g id="ID_1">%1$s</xliff:g>"</string> <string name="screen_zoom_summary_small" msgid="6050633151263074260">"小"</string> <string name="screen_zoom_summary_default" msgid="1888865694033865408">"默认"</string> <string name="screen_zoom_summary_large" msgid="4706951482598978984">"大"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index a4c2336d6a02..74e3498bfe7e 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"無線偵錯"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"如要查看並使用可用的裝置,請開啟無線偵錯"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"使用二維條碼配對裝置"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"使用二維條碼掃瞄器配對新裝置"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"使用二維條碼掃瞄器配對新裝置"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"使用配對碼配對裝置"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"使用六位數的配對碼配對新裝置"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"已配對的裝置"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"無法配對裝置,可能是二維條碼錯誤,或裝置未連線至相同的網絡。"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP 位址和連接埠"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"掃瞄二維條碼"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"掃瞄二維條碼即可透過 Wi-Fi 配對裝置"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"掃瞄二維條碼即可透過 Wi-Fi 配對裝置"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"請連線至 Wi-Fi 網絡"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"ADB, 偵錯, 開發"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"錯誤舉報捷徑"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"無線螢幕分享認證"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"啟用 Wi‑Fi 詳細記錄"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi 掃瞄限流"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi-Fi 強化 MAC 隨機處理"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"一律保持啟用流動數據"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"網絡共享硬件加速"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"顯示無線螢幕分享認證的選項"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"減低耗電量並改善網絡表現"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"此切換只會影響用戶端模式的 MAC 隨機處理。\n啟動此模式後,視乎用戶端上次中斷網絡連線的時間,系統可能會重新為任何已啟用 MAC 隨機處理的網絡在關聯期間隨機處理其 MAC 地址。如裝置在 4 小時或以內重新連線,系統便不會重新進行隨機處理。"</string> <string name="wifi_metered_label" msgid="8737187690304098638">"按用量收費"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"不限數據用量收費"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"記錄器緩衝區空間"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"為背景應用程式顯示「應用程式無回應」對話框"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"顯示通知渠道警告"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"當應用程式未經有效渠道發佈通知時,在螢幕上顯示警告"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"執行對話通知捷徑"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"通知必須採用永久共用捷徑,以便在對話部分中顯示"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"強制允許應用程式寫入到外部儲存空間"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"在任何資訊清單值下,允許將所有符合資格的應用程式寫入到外部儲存完間"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"強制將活動設為可調整尺寸"</string> @@ -429,7 +433,7 @@ <string name="power_discharge_by_enhanced" msgid="563438403581662942">"根據您的使用情況 (<xliff:g id="LEVEL">%2$s</xliff:g>),電量剩餘約 <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"根據您的使用情況,電量剩餘約 <xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="4113180890060388350">"電量剩餘約 <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> - <string name="power_discharge_by_only" msgid="92545648425937000">"電量剩餘約 <xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only" msgid="92545648425937000">"電量大約可用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"還可用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"電池電量可能將於<xliff:g id="TIME">%1$s</xliff:g>耗盡"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"剩餘電量時間少於 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 5183df3011e5..9337b59c258e 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"無線偵錯"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"如要查看並使用可用的裝置,請開啟無線偵錯"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"使用 QR 圖碼配對裝置"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"使用 QR 圖碼掃描器配對新裝置"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"使用 QR 圖碼掃描器配對新裝置"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"使用配對碼配對裝置"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"使用六位數的配對碼配對新裝置"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"已配對的裝置"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"無法配對裝置。可能是QR 圖碼錯誤,或是裝置未連上相同的網路。"</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP 位址和通訊埠"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"掃描 QR 圖碼"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"掃描 QR 圖碼即可透過 Wi-Fi 配對裝置"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"掃描 QR 圖碼即可透過 Wi-Fi 配對裝置"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"請連上 Wi-Fi 網路"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"ADB, 偵錯, 開發"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"錯誤回報捷徑"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"無線螢幕分享認證"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"啟用 Wi‑Fi 詳細記錄設定"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi-Fi 掃描調節"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Wi‑Fi 加強型 MAC 隨機化"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"行動數據連線一律保持啟用狀態"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"數據連線硬體加速"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"顯示無線螢幕分享認證的選項"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細記錄"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"降低耗電量以及改善網路效能"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"這個切換鈕只會影響用戶端模式的 MAC 隨機化行為。\n這個模式開啟時,任何已啟用 MAC 隨機化的網路可能會在建立關聯時重新將 MAC 位址隨機化 (取決於用戶端上次中斷連線的時間)。如果裝置在 4 個小時內重新連線,就不會進行重新隨機化作業。"</string> <string name="wifi_metered_label" msgid="8737187690304098638">"計量付費"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"非計量付費"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"記錄器緩衝區空間"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"為背景應用程式顯示「應用程式無回應」對話方塊"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"顯示通知管道警告"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"當應用程式未經有效管道發布通知時,在畫面上顯示警告"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"強制執行對話通知捷徑"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"要求通知必須有永久分享捷徑支援,才能顯示在對話部分中"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"強制允許將應用程式寫入外部儲存空間"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"允許將任何應用程式寫入外部儲存空間 (無論資訊清單值為何)"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"將活動強制設為可調整大小"</string> @@ -429,7 +433,7 @@ <string name="power_discharge_by_enhanced" msgid="563438403581662942">"根據你的使用情形,目前電量為 <xliff:g id="LEVEL">%2$s</xliff:g>,預估可持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"根據你的使用情形,預估可持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by" msgid="4113180890060388350">"目前電量 <xliff:g id="LEVEL">%2$s</xliff:g>,預估還能持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string> - <string name="power_discharge_by_only" msgid="92545648425937000">"預估還能持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string> + <string name="power_discharge_by_only" msgid="92545648425937000">"預估電力大約可使用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"還能持續使用到<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"電池電力可能於<xliff:g id="TIME">%1$s</xliff:g> 前耗盡"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"電池可用時間不到 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index eb4ace633bcb..a552446e6acf 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -212,7 +212,7 @@ <string name="adb_wireless_settings" msgid="2295017847215680229">"Ukulungisa amaphutha okungenantambo"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Ukubona futhi usebenzise amadivayisi atholakalayo, vula ukulungisa amaphutha okungenantambo"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Bhangqa idivayisi ngekhodi ye-QR"</string> - <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Bhangqa amadivayisi amasha usebenzisa iskena sekhodi ye-QR"</string> + <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Bhangqa amadivayisi amasha usebenzisa isiphequluli sekhodi ye-QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Bhangqa idivayisi ngekhodi yokumatanisa"</string> <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Bhangqa amadivayisi amasha usebenzisa ikhodi yamadijithi ayisithupha"</string> <string name="adb_paired_devices_title" msgid="5268997341526217362">"Amadivaysi abhangqene"</string> @@ -231,7 +231,7 @@ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Yehlulekile ukubhangqa idivayisi. Kungenzeka ukuthi ikhodi ye-QR kade ingalungile, noma idivayisi ayixhunyiwe kunethiwekhi efanayo."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Ikheli le-IP nembobo"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skena ikhodi ye-QR"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"Bhangqa idivayisi nge-Wi‑Fi ngokuskena ikhodi ye-QR"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Bhangqa idivayisi nge-Wi‑Fi ngokuskena ikhodi ye-QR"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Sicela uxhume kunethiwekhi ye-Wi-Fi"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"i-adb, ukulungisa amaphutha, i-dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Isinqamuleli sombiko wesiphazamisi"</string> @@ -251,6 +251,7 @@ <string name="wifi_display_certification" msgid="1805579519992520381">"Ukunikezwa isitifiketi sokubukeka okungenantambo"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Nika amandlaukungena kwe-Wi-Fi Verbose"</string> <string name="wifi_scan_throttling" msgid="2985624788509913617">"I-throttling yokuskena kwe-Wi-Fi"</string> + <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Okungahleliwe kwe-Wi-Fi ethuthukisiwe ye-MAC"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Idatha yeselula ihlala isebenza"</string> <string name="tethering_hardware_offload" msgid="4116053719006939161">"I-Tethering hardware acceleration"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bonisa amadivayisi e-Bluetooth ngaphandle kwamagama"</string> @@ -283,6 +284,7 @@ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Bonisa izinketho zokunikeza isitifiketi ukubukeka okungenantambo"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"khuphula izinga lokungena le-Wi-Fi, bonisa nge-SSID RSSI engayodwana kusikhethi se-Wi-Fi"</string> <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Yehlisa ukuphela kwebhethri futhi ithuthukise ukusebenza kwenethiwekhi"</string> + <string name="wifi_enhanced_mac_randomization_summary" msgid="7925425746373704991">"Lokhu kuguqula kuthinta ukuziphatha kokungahleliwe kwe-MAC kwemodi yeklayenti kuphela.\nLapho le modi yenziwe yasebenza, noma yimaphi amanethiwekhi anokungahleliwe kwe-MAC okunikwe amandla angase abe nekheli lawo le-MAC libe okungahleliwe kabusha phakathi nokuhlobana, kuya ngokuthi iklayenti igcine nini ukunqamula kusuka kunethiwekhi. Ukwenza kube okungahleliwe kabusha akuveli uma idivayisi ixhuma kabusha emahoreni angu-4 noma ngaphansi."</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Kulinganisiwe"</string> <string name="wifi_unmetered_label" msgid="6174142840934095093">"Akulinganiselwa"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Amasayizi weloga ngebhafa"</string> @@ -371,6 +373,8 @@ <string name="show_all_anrs_summary" msgid="8562788834431971392">"Uhlelo lokusebenza lwesibonisi aluphenduli kungxoxo yezinhlelo zokusebenza zangemuva"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Bonisa izexwayiso zesiteshi sesaziso"</string> <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Ibonisa isexwayiso esikusikrini uma uhlelo lokusebenza luthumela isaziso ngaphandle kwesiteshi esivumelekile"</string> + <string name="enforce_shortcuts_for_conversations" msgid="7040735163945040763">"Phoqelela izinqamuleli zezaziso zengxoxo"</string> + <string name="enforce_shortcuts_for_conversations_summary" msgid="1860168037282467862">"Kudinga ukuba izaziso zisekelwe yisinqamuleli sokwabelana sesikhathi eside ukuze zivele esigabeni sengxoxo"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"Phoqelela ukuvumela izinhlelo zokusebenza ngaphandle"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Yenza noma uluphi uhlelo lokusebenza lifaneleke ukuthi libhalwe kusitoreji sangaphandle, ngaphandle kwamavelu we-manifest"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"Imisebenzi yamandla izonikezwa usayizi omusha"</string> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 07f4a9a799ad..1007d8379b8e 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -566,7 +566,7 @@ <!-- [CHAR LIMIT=50] Title for adb wireless pair by QR code preference --> <string name="adb_pair_method_qrcode_title">Pair device with QR code</string> <!-- [CHAR LIMIT=NONE] Summary for adb wireless pair by QR code preference --> - <string name="adb_pair_method_qrcode_summary">Pair new devices using QR code Scanner</string> + <string name="adb_pair_method_qrcode_summary">Pair new devices using QR code scanner</string> <!-- [CHAR LIMIT=50] Title for adb wireless pair by pairing code preference --> <string name="adb_pair_method_code_title">Pair device with pairing code</string> <!-- [CHAR LIMIT=NONE] Summary for adb wireless pair by pairing code preference --> @@ -604,7 +604,7 @@ <!-- [CHAR LIMIT=NONE] Adb Wireless QR code pairing scanner title --> <string name="adb_wireless_qrcode_pairing_title">Scan QR code</string> <!-- [CHAR LIMIT=NONE] Adb Wireless QR code pairing description --> - <string name="adb_wireless_qrcode_pairing_description">Pair device over Wi\u2011Fi by scanning a QR Code</string> + <string name="adb_wireless_qrcode_pairing_description">Pair device over Wi\u2011Fi by scanning a QR code</string> <!-- [CHAR LIMIT=NONE] Toast message when trying to enable Wi-Fi debugging and no Wi-Fi network connected --> <string name="adb_wireless_no_network_msg">Please connect to a Wi\u2011Fi network</string> <!--Adb wireless search Keywords [CHAR LIMIT=NONE]--> @@ -646,6 +646,8 @@ <string name="wifi_verbose_logging">Enable Wi\u2011Fi Verbose Logging</string> <!-- Setting Checkbox title whether to disable WiFi Scan Throttling. [CHAR LIMIT=40] --> <string name="wifi_scan_throttling">Wi\u2011Fi scan throttling</string> + <!-- Setting Checkbox title whether to enable WiFi enhanced mac randomization. [CHAR LIMIT=40] --> + <string name="wifi_enhanced_mac_randomization">Wi\u2011Fi\u2011enhanced MAC randomization</string> <!-- Setting Checkbox title whether to always keep mobile data active. [CHAR LIMIT=80] --> <string name="mobile_data_always_on">Mobile data always active</string> <!-- Setting Checkbox title whether to enable hardware acceleration for tethering. [CHAR LIMIT=80] --> @@ -716,6 +718,8 @@ <string name="wifi_verbose_logging_summary">Increase Wi\u2011Fi logging level, show per SSID RSSI in Wi\u2011Fi Picker</string> <!-- Setting Checkbox summary whether to disable Wifi scan throttling [CHAR LIMIT=NONE] --> <string name="wifi_scan_throttling_summary">Reduces battery drain & improves network performance</string> + <!-- Setting Checkbox title whether to enable WiFi enhanced mac randomization. [CHAR LIMIT=NONE] --> + <string name="wifi_enhanced_mac_randomization_summary">This toggle affects MAC randomization behavior for client mode only.\nWhen this mode is activated, any networks that have MAC randomization enabled may have their MAC addresses re\u2011randomized during association, depending on when the client last disconnected from the network. Re\u2011randomization does not occur if the device reconnects in 4 hours or less.</string> <!-- Label indicating network has been manually marked as metered --> <string name="wifi_metered_label">Metered</string> <!-- Label indicating network has been manually marked as unmetered --> diff --git a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java index ff40d8e00603..450bdb161933 100644 --- a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java +++ b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java @@ -202,6 +202,12 @@ public class SettingsInjector { } /** + * Gives descendants a chance to log Preference click event + */ + protected void logPreferenceClick(Intent intent) { + } + + /** * Returns the settings parsed from the attributes of the * {@link SettingInjectorService#META_DATA_NAME} tag, or null. * @@ -315,6 +321,7 @@ public class SettingsInjector { // Settings > Location. Intent settingIntent = new Intent(); settingIntent.setClassName(mInfo.packageName, mInfo.settingsActivity); + logPreferenceClick(settingIntent); // Sometimes the user may navigate back to "Settings" and launch another different // injected setting after one injected setting has been launched. // diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index 3024b842c2be..a62d76f732da 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -401,6 +401,11 @@ public class LocalMediaManager implements BluetoothCallback { } private List<MediaDevice> buildDisconnectedBluetoothDevice() { + if (mBluetoothAdapter == null) { + Log.w(TAG, "buildDisconnectedBluetoothDevice() BluetoothAdapter is null"); + return new ArrayList<>(); + } + final List<BluetoothDevice> bluetoothDevices = mBluetoothAdapter.getMostRecentlyConnectedDevices(); final CachedBluetoothDeviceManager cachedDeviceManager = diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java index 9d7e2c821297..b1234f291b74 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java @@ -18,11 +18,15 @@ package com.android.settingslib.net; import android.content.Context; import android.net.NetworkTemplate; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.util.ArrayUtils; + +import java.util.List; + /** * Utils class for data usage */ @@ -33,26 +37,42 @@ public class DataUsageUtils { * Return mobile NetworkTemplate based on {@code subId} */ public static NetworkTemplate getMobileTemplate(Context context, int subId) { - final TelephonyManager telephonyManager = context.getSystemService( - TelephonyManager.class); - final SubscriptionManager subscriptionManager = context.getSystemService( - SubscriptionManager.class); - final NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll( - telephonyManager.getSubscriberId()); - - if (!subscriptionManager.isActiveSubscriptionId(subId)) { - Log.i(TAG, "Subscription is not active: " + subId); - return mobileAll; + final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); + final int mobileDefaultSubId = telephonyManager.getSubscriptionId(); + + final SubscriptionManager subscriptionManager = + context.getSystemService(SubscriptionManager.class); + final List<SubscriptionInfo> subInfoList = + subscriptionManager.getAvailableSubscriptionInfoList(); + if (subInfoList == null) { + Log.i(TAG, "Subscription is not inited: " + subId); + return getMobileTemplateForSubId(telephonyManager, mobileDefaultSubId); } - final String[] mergedSubscriberIds = telephonyManager.createForSubscriptionId(subId) - .getMergedImsisFromGroup(); + for (SubscriptionInfo subInfo : subInfoList) { + if ((subInfo != null) && (subInfo.getSubscriptionId() == subId)) { + return getNormalizedMobileTemplate(telephonyManager, subId); + } + } + Log.i(TAG, "Subscription is not active: " + subId); + return getMobileTemplateForSubId(telephonyManager, mobileDefaultSubId); + } + private static NetworkTemplate getNormalizedMobileTemplate( + TelephonyManager telephonyManager, int subId) { + final NetworkTemplate mobileTemplate = getMobileTemplateForSubId(telephonyManager, subId); + final String[] mergedSubscriberIds = telephonyManager + .createForSubscriptionId(subId).getMergedImsisFromGroup(); if (ArrayUtils.isEmpty(mergedSubscriberIds)) { Log.i(TAG, "mergedSubscriberIds is null."); - return mobileAll; + return mobileTemplate; } - return NetworkTemplate.normalize(mobileAll, mergedSubscriberIds); + return NetworkTemplate.normalize(mobileTemplate, mergedSubscriberIds); + } + + private static NetworkTemplate getMobileTemplateForSubId( + TelephonyManager telephonyManager, int subId) { + return NetworkTemplate.buildTemplateMobileAll(telephonyManager.getSubscriberId(subId)); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java index 8aa0aec28fb8..a53bc9f966d2 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java @@ -102,12 +102,11 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt // Turn off divider view.findViewById(R.id.two_target_divider).setVisibility(View.INVISIBLE); - // Enable the icon button when this Entry is a canManageSubscription entry. + // Enable the icon button when the help string in this WifiEntry is not null. final ImageButton imageButton = (ImageButton) view.findViewById(R.id.icon_button); final ImageView frictionImageView = (ImageView) view.findViewById( R.id.friction_icon); - if (mWifiEntry.canManageSubscription() && !mWifiEntry.isSaved() - && !mWifiEntry.isSubscription() + if (mWifiEntry.getHelpUriString() != null && mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED) { final Drawable drawablehelp = getDrawable(R.drawable.ic_help); drawablehelp.setTintList( diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiSavedConfigUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiSavedConfigUtils.java index 19e38081fcad..65c7786235bf 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiSavedConfigUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiSavedConfigUtils.java @@ -65,5 +65,17 @@ public class WifiSavedConfigUtils { } return savedConfigs; } + + /** + * Returns the count of the saved configurations on the device, including both Wi-Fi networks + * and Passpoint profiles. + * + * @param context The application context + * @param wifiManager An instance of {@link WifiManager} + * @return count of saved Wi-Fi networks + */ + public static int getAllConfigsCount(Context context, WifiManager wifiManager) { + return getAllConfigs(context, wifiManager).size(); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java index 7ddd64c15876..206c8590a952 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java @@ -691,4 +691,28 @@ public class LocalMediaManagerTest { assertThat(mLocalMediaManager.mMediaDevices).hasSize(7); verify(mCallback).onDeviceListUpdate(any()); } + + @Test + public void onDeviceListAdded_bluetoothAdapterIsNull_noDisconnectedDeviceAdded() { + final List<MediaDevice> devices = new ArrayList<>(); + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + final MediaDevice device3 = mock(MediaDevice.class); + mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class); + devices.add(device1); + devices.add(device2); + mLocalMediaManager.mMediaDevices.add(device3); + mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice); + + mShadowBluetoothAdapter = null; + + when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id"); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices); + + assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); + verify(mCallback).onDeviceListUpdate(any()); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java index a9f31ce12b42..46e699d3bed5 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java @@ -64,7 +64,7 @@ public class WifiEntryPreferenceTest { private static final String MOCK_TITLE = "title"; private static final String MOCK_SUMMARY = "summary"; - + private static final String FAKE_URI_STRING = "fakeuri"; @Before public void setUp() { @@ -155,22 +155,23 @@ public class WifiEntryPreferenceTest { } @Test - public void canManageSubscription_shouldSetImageButtonVisible() { - when(mMockWifiEntry.canManageSubscription()).thenReturn(true); + public void notNull_whenGetHelpUriString_shouldSetImageButtonVisible() { + when(mMockWifiEntry.getHelpUriString()).thenReturn(FAKE_URI_STRING); final WifiEntryPreference pref = new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector); final LayoutInflater inflater = LayoutInflater.from(mContext); final View view = inflater.inflate(pref.getLayoutResource(), new LinearLayout(mContext), false); final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view); + pref.onBindViewHolder(holder); assertThat(view.findViewById(R.id.icon_button).getVisibility()).isEqualTo(View.VISIBLE); } @Test - public void helpButton_whenCanManageSubscription_shouldSetCorrectContentDescription() { - when(mMockWifiEntry.canManageSubscription()).thenReturn(true); + public void helpButton_whenGetHelpUriStringNotNull_shouldSetCorrectContentDescription() { + when(mMockWifiEntry.getHelpUriString()).thenReturn(FAKE_URI_STRING); final WifiEntryPreference pref = new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector); final LayoutInflater inflater = LayoutInflater.from(mContext); diff --git a/packages/SettingsProvider/res/values-ky/strings.xml b/packages/SettingsProvider/res/values-ky/strings.xml index e5b82c69a81e..8058b4da5634 100644 --- a/packages/SettingsProvider/res/values-ky/strings.xml +++ b/packages/SettingsProvider/res/values-ky/strings.xml @@ -20,6 +20,6 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Жөндөөлөрдү сактоо"</string> - <string name="wifi_softap_config_change" msgid="5688373762357941645">"Хотспот жөндөөлөрү өзгөрдү"</string> + <string name="wifi_softap_config_change" msgid="5688373762357941645">"Байланыш түйүнү жөндөөлөрү өзгөрдү"</string> <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"Чоо-жайын билүү үчүн басыңыз"</string> </resources> diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 01a2b6952f2a..03f6df0d5d2d 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -101,7 +101,8 @@ public class SettingsBackupTest { Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities Settings.System.SCREEN_BRIGHTNESS_FLOAT, - Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT + Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT, + Settings.System.MULTI_AUDIO_FOCUS_ENABLED // form-factor/OEM specific ); private static final Set<String> BACKUP_BLACKLISTED_GLOBAL_SETTINGS = diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 68bd4071de05..c2015ed41b00 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -363,6 +363,7 @@ public class BugreportProgressService extends Service { public void onError(@BugreportErrorCode int errorCode) { synchronized (mLock) { stopProgressLocked(mInfo.id); + mInfo.deleteEmptyFiles(); } Log.e(TAG, "Bugreport API callback onError() errorCode = " + errorCode); return; @@ -1980,6 +1981,22 @@ public class BugreportProgressService extends Service { } /** + * Deletes empty files for a given bugreport. + */ + private void deleteEmptyFiles() { + if (bugreportFile.length() == 0) { + Log.i(TAG, "Deleting empty bugreport file: " + bugreportFile); + bugreportFile.delete(); + } + for (File file : screenshotFiles) { + if (file.length() == 0) { + Log.i(TAG, "Deleting empty screenshot file: " + file); + file.delete(); + } + } + } + + /** * Rename all screenshots files so that they contain the new {@code name} instead of the * {@code initialName} if user has changed it. */ diff --git a/packages/SoundPicker/res/values-af/strings.xml b/packages/SoundPicker/res/values-af/strings.xml new file mode 100644 index 000000000000..cf6414659f6e --- /dev/null +++ b/packages/SoundPicker/res/values-af/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Verstekluitoon"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Verstekwekkerklank"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Voeg luitoon by"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Voeg wekker by"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Voeg kennisgewing by"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Vee uit"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Kan nie gepasmaakte luitoon byvoeg nie"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Kan nie gepasmaakte luitoon uitvee nie"</string> +</resources> diff --git a/packages/SoundPicker/res/values-am/strings.xml b/packages/SoundPicker/res/values-am/strings.xml new file mode 100644 index 000000000000..9026d3629180 --- /dev/null +++ b/packages/SoundPicker/res/values-am/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"ነባሪ የስልክ ላይ ጥሪ"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"ነባሪ የማንቂያ ድምፅ"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"የጥሪ ቅላጼ አክል"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"የማንቂያ ደውል አክል"</string> + <string name="add_notification_text" msgid="4431129543300614788">"ማሳወቂያን አክል"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"ሰርዝ"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"ብጁ የጥሪ ቅላጼን ማከል አልተቻለም"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"ብጁ የጥሪ ቅላጼን መሰረዝ አልተቻለም"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ar/strings.xml b/packages/SoundPicker/res/values-ar/strings.xml new file mode 100644 index 000000000000..0af7ff52a928 --- /dev/null +++ b/packages/SoundPicker/res/values-ar/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"نغمة الرنين التلقائية"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"الصوت التلقائي للمنبّه"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"إضافة نغمة رنين"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"إضافة منبه"</string> + <string name="add_notification_text" msgid="4431129543300614788">"إضافة إشعار"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"حذف"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"يتعذر إضافة نغمة رنين مخصصة"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"يتعذر حذف نغمة الرنين المخصصة"</string> +</resources> diff --git a/packages/SoundPicker/res/values-as/strings.xml b/packages/SoundPicker/res/values-as/strings.xml new file mode 100644 index 000000000000..6cbea0797696 --- /dev/null +++ b/packages/SoundPicker/res/values-as/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"পূর্বনিধার্ৰিত ৰিংট\'ন"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"এলাৰ্মৰ ডিফ\'ল্ট ধ্বনি"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"ৰিংট\'ন যোগ কৰক"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"এলাৰ্ম যোগ কৰক"</string> + <string name="add_notification_text" msgid="4431129543300614788">"জাননী যোগ কৰক"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"মচক"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"নিজৰ উপযোগিতা অনুযায়ী তৈয়াৰ কৰা ৰিংট\'ন যোগ কৰিব পৰা নগ\'ল"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"নিজৰ উপযোগিতা অনুযায়ী তৈয়াৰ কৰা ৰিংট\'ন মচিব পৰা নগ\'ল"</string> +</resources> diff --git a/packages/SoundPicker/res/values-az/strings.xml b/packages/SoundPicker/res/values-az/strings.xml new file mode 100644 index 000000000000..16f739d32346 --- /dev/null +++ b/packages/SoundPicker/res/values-az/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Defolt rinqton"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Defolt siqnal səsi"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Zəng səsi daxil edin"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Siqnal əlavə edin"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Bildiriş əlavə edin"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Silin"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Fərdi zəng səsi əlavə etmək mümkün deyil"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Fərdi zəng səsini silmək mümkün deyil"</string> +</resources> diff --git a/packages/SoundPicker/res/values-b+sr+Latn/strings.xml b/packages/SoundPicker/res/values-b+sr+Latn/strings.xml new file mode 100644 index 000000000000..03fd58a4cd69 --- /dev/null +++ b/packages/SoundPicker/res/values-b+sr+Latn/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Podrazumevani zvuk zvona"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Podrazumevani zvuk alarma"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Dodaj melodiju zvona"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Dodajte alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Dodajte obaveštenje"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Izbriši"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Dodavanje prilagođene melodije zvona nije uspelo"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Brisanje prilagođene melodije zvona nije uspelo"</string> +</resources> diff --git a/packages/SoundPicker/res/values-be/strings.xml b/packages/SoundPicker/res/values-be/strings.xml new file mode 100644 index 000000000000..55f6ab3e875e --- /dev/null +++ b/packages/SoundPicker/res/values-be/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Стандартны рынгтон"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Стандартны сігнал будзільніка"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Дадаць рынгтон"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Дадаць будзільнік"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Дадаць апавяшчэнне"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Выдаліць"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Немагчыма дадаць карыстальніцкі рынгтон"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Немагчыма выдаліць карыстальніцкі рынгтон"</string> +</resources> diff --git a/packages/SoundPicker/res/values-bg/strings.xml b/packages/SoundPicker/res/values-bg/strings.xml new file mode 100644 index 000000000000..c31f35f9e4d4 --- /dev/null +++ b/packages/SoundPicker/res/values-bg/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Стандартна мелодия"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Стандартен звук за будилника"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Добавяне на мелодия"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Добавяне на будилник"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Добавяне на известие"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Изтриване"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Персонализираната мелодия не може да се добави"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Персонализираната мелодия не може да се изтрие"</string> +</resources> diff --git a/packages/SoundPicker/res/values-bn/strings.xml b/packages/SoundPicker/res/values-bn/strings.xml new file mode 100644 index 000000000000..ebbed152833d --- /dev/null +++ b/packages/SoundPicker/res/values-bn/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"ডিফল্ট রিংটোন"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"ডিফল্ট অ্যালার্মের সাউন্ড"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"রিংটোন যোগ করুন"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"অ্যালার্ম যোগ করুন"</string> + <string name="add_notification_text" msgid="4431129543300614788">"বিজ্ঞপ্তি যোগ করুন"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"মুছুন"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"কাস্টম রিংটোন যোগ করা গেল না"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"কাস্টম রিংটোন মোছা গেল না"</string> +</resources> diff --git a/packages/SoundPicker/res/values-bs/strings.xml b/packages/SoundPicker/res/values-bs/strings.xml new file mode 100644 index 000000000000..ad4fe573090d --- /dev/null +++ b/packages/SoundPicker/res/values-bs/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Zadana melodija zvona"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Zadani zvuk alarma"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Dodaj melodiju zvona"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Dodajte alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Dodajte obavještenje"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Izbriši"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nije moguće dodati prilagođenu melodiju zvona"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nije moguće izbrisati prilagođenu melodiju zvona"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ca/strings.xml b/packages/SoundPicker/res/values-ca/strings.xml new file mode 100644 index 000000000000..5b324292c485 --- /dev/null +++ b/packages/SoundPicker/res/values-ca/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"So predeterminat"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"So d\'alarma predeterminat"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Afegeix un so de trucada"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Afegeix una alarma"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Afegeix una notificació"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Suprimeix"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"No es pot afegir el so de trucada personalitzat"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"No es pot suprimir el so de trucada personalitzat"</string> +</resources> diff --git a/packages/SoundPicker/res/values-cs/strings.xml b/packages/SoundPicker/res/values-cs/strings.xml new file mode 100644 index 000000000000..d60e217508c0 --- /dev/null +++ b/packages/SoundPicker/res/values-cs/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Výchozí vyzváněcí tón"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Výchozí zvuk budíku"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Přidat vyzváněcí tón"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Přidat budík"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Přidat oznámení"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Smazat"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Vlastní vyzváněcí tón se nepodařilo přidat"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Vlastní vyzváněcí tón se nepodařilo smazat"</string> +</resources> diff --git a/packages/SoundPicker/res/values-da/strings.xml b/packages/SoundPicker/res/values-da/strings.xml new file mode 100644 index 000000000000..c4ba8ee7b6dd --- /dev/null +++ b/packages/SoundPicker/res/values-da/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Standardringetone"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Standardlyd for alarmer"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Tilføj ringetone"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Tilføj alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Tilføj notifikation"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Slet"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Den tilpassede ringetone kunne ikke tilføjes"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Den tilpassede ringetone kunne ikke slettes"</string> +</resources> diff --git a/packages/SoundPicker/res/values-de/strings.xml b/packages/SoundPicker/res/values-de/strings.xml new file mode 100644 index 000000000000..ca7e498934ff --- /dev/null +++ b/packages/SoundPicker/res/values-de/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Standard-Klingelton"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Standard-Weckton"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Klingelton hinzufügen"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Weckruf hinzufügen"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Benachrichtigung hinzufügen"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Löschen"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Benutzerdefinierter Klingelton konnte nicht hinzugefügt werden"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Benutzerdefinierter Klingelton konnte nicht gelöscht werden"</string> +</resources> diff --git a/packages/SoundPicker/res/values-el/strings.xml b/packages/SoundPicker/res/values-el/strings.xml new file mode 100644 index 000000000000..b600e8801026 --- /dev/null +++ b/packages/SoundPicker/res/values-el/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Προεπιλεγμένος ήχος κλήσης"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Προεπιλεγμένος ήχος ειδοποίησης"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Προσθήκη ήχου κλήσης"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Προσθήκη ξυπνητηριού"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Προσθήκη ειδοποίησης"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Διαγραφή"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Δεν είναι δυνατή η προσθήκη προσαρμοσμένου ήχου κλήσης"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Δεν είναι δυνατή η διαγραφή προσαρμοσμένου ήχου κλήσης"</string> +</resources> diff --git a/packages/SoundPicker/res/values-en-rAU/strings.xml b/packages/SoundPicker/res/values-en-rAU/strings.xml new file mode 100644 index 000000000000..7e4a8b695f13 --- /dev/null +++ b/packages/SoundPicker/res/values-en-rAU/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Default ringtone"</string> + <string name="notification_sound_default" msgid="8133121186242636840">"Default notification sound"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Default alarm sound"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Add ringtone"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Add alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Add notification"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Delete"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add customised ringtone"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete customised ringtone"</string> +</resources> diff --git a/packages/SoundPicker/res/values-en-rCA/strings.xml b/packages/SoundPicker/res/values-en-rCA/strings.xml new file mode 100644 index 000000000000..7e4a8b695f13 --- /dev/null +++ b/packages/SoundPicker/res/values-en-rCA/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Default ringtone"</string> + <string name="notification_sound_default" msgid="8133121186242636840">"Default notification sound"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Default alarm sound"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Add ringtone"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Add alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Add notification"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Delete"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add customised ringtone"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete customised ringtone"</string> +</resources> diff --git a/packages/SoundPicker/res/values-en-rGB/strings.xml b/packages/SoundPicker/res/values-en-rGB/strings.xml new file mode 100644 index 000000000000..7e4a8b695f13 --- /dev/null +++ b/packages/SoundPicker/res/values-en-rGB/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Default ringtone"</string> + <string name="notification_sound_default" msgid="8133121186242636840">"Default notification sound"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Default alarm sound"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Add ringtone"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Add alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Add notification"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Delete"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add customised ringtone"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete customised ringtone"</string> +</resources> diff --git a/packages/SoundPicker/res/values-en-rIN/strings.xml b/packages/SoundPicker/res/values-en-rIN/strings.xml new file mode 100644 index 000000000000..7e4a8b695f13 --- /dev/null +++ b/packages/SoundPicker/res/values-en-rIN/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Default ringtone"</string> + <string name="notification_sound_default" msgid="8133121186242636840">"Default notification sound"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Default alarm sound"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Add ringtone"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Add alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Add notification"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Delete"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add customised ringtone"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete customised ringtone"</string> +</resources> diff --git a/packages/SoundPicker/res/values-en-rXC/strings.xml b/packages/SoundPicker/res/values-en-rXC/strings.xml new file mode 100644 index 000000000000..04b2662c8caa --- /dev/null +++ b/packages/SoundPicker/res/values-en-rXC/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Default ringtone"</string> + <string name="notification_sound_default" msgid="8133121186242636840">"Default notification sound"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Default alarm sound"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Add ringtone"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Add alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Add notification"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Delete"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add custom ringtone"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete custom ringtone"</string> +</resources> diff --git a/packages/SoundPicker/res/values-es-rUS/strings.xml b/packages/SoundPicker/res/values-es-rUS/strings.xml new file mode 100644 index 000000000000..e6cb5ff1c423 --- /dev/null +++ b/packages/SoundPicker/res/values-es-rUS/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Tono predeterminado"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Sonido de alarma predeterminado"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Agregar tono"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Agregar alarma"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Agregar notificación"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Borrar"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"No se puede agregar el tono personalizado"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"No se puede borrar el tono personalizado"</string> +</resources> diff --git a/packages/SoundPicker/res/values-es/strings.xml b/packages/SoundPicker/res/values-es/strings.xml new file mode 100644 index 000000000000..c7e8be2000d6 --- /dev/null +++ b/packages/SoundPicker/res/values-es/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Tono por defecto"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Sonido de alarma predeterminado"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Añadir tono de llamada"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Añadir alarma"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Añadir notificación"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Eliminar"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"No se ha podido añadir un tono de llamada personalizado"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"No se ha podido eliminar un tono de llamada personalizado"</string> +</resources> diff --git a/packages/SoundPicker/res/values-et/strings.xml b/packages/SoundPicker/res/values-et/strings.xml new file mode 100644 index 000000000000..1eb5ca275b94 --- /dev/null +++ b/packages/SoundPicker/res/values-et/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Vaikehelin"</string> + <string name="notification_sound_default" msgid="8133121186242636840">"Märguande vaikeheli"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Äratuse vaikeheli"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Lisa helin"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Lisa äratus"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Lisa märguanne"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Kustuta"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Kohandatud helinat ei õnnestu lisada"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Kohandatud helinat ei õnnestu kustutada"</string> +</resources> diff --git a/packages/SoundPicker/res/values-eu/strings.xml b/packages/SoundPicker/res/values-eu/strings.xml new file mode 100644 index 000000000000..33133b03943c --- /dev/null +++ b/packages/SoundPicker/res/values-eu/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Tonu lehenetsia"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Alarmaren soinu lehenetsia"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Gehitu tonua"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Gehitu alarma"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Gehitu jakinarazpena"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Ezabatu"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Ezin da gehitu tonu pertsonalizatua"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Ezin da ezabatu tonu pertsonalizatua"</string> +</resources> diff --git a/packages/SoundPicker/res/values-fa/strings.xml b/packages/SoundPicker/res/values-fa/strings.xml new file mode 100644 index 000000000000..908efaf675c2 --- /dev/null +++ b/packages/SoundPicker/res/values-fa/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"آهنگ زنگ پیشفرض"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"صدای زنگ پیشفرض"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"افزودن آهنگ زنگ"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"افزودن زنگ"</string> + <string name="add_notification_text" msgid="4431129543300614788">"افزودن اعلان"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"حذف"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"افزودن آهنگ زنگ سفارشی ممکن نیست"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"حذف آهنگ زنگ سفارشی ممکن نیست"</string> +</resources> diff --git a/packages/SoundPicker/res/values-fi/strings.xml b/packages/SoundPicker/res/values-fi/strings.xml new file mode 100644 index 000000000000..812e0ecb249e --- /dev/null +++ b/packages/SoundPicker/res/values-fi/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Oletussoittoääni"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Herätyksen oletusääni"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Lisää soittoääni"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Lisää hälytys"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Lisää ilmoitus"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Poista"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Muokatun soittoäänen lisääminen epäonnistui."</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Muokatun soittoäänen poistaminen epäonnistui."</string> +</resources> diff --git a/packages/SoundPicker/res/values-fr-rCA/strings.xml b/packages/SoundPicker/res/values-fr-rCA/strings.xml new file mode 100644 index 000000000000..63182df7992f --- /dev/null +++ b/packages/SoundPicker/res/values-fr-rCA/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Sonnerie par défaut"</string> + <string name="notification_sound_default" msgid="8133121186242636840">"Son de notification par défaut"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Son de l\'alarme par défaut"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Ajouter une sonnerie"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Ajouter une alarme"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Ajouter une notification"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Supprimer"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Impossible d\'ajouter une sonnerie personnalisée"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Impossible de supprimer la sonnerie personnalisée"</string> +</resources> diff --git a/packages/SoundPicker/res/values-fr/strings.xml b/packages/SoundPicker/res/values-fr/strings.xml new file mode 100644 index 000000000000..ece6a137dac9 --- /dev/null +++ b/packages/SoundPicker/res/values-fr/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Sonnerie par défaut"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Son de l\'alarme par défaut"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Ajouter une sonnerie"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Ajouter une alarme"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Ajouter une notification"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Supprimer"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Impossible d\'ajouter une sonnerie personnalisée"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Impossible de supprimer la sonnerie personnalisée"</string> +</resources> diff --git a/packages/SoundPicker/res/values-gl/strings.xml b/packages/SoundPicker/res/values-gl/strings.xml new file mode 100644 index 000000000000..2d75f224106f --- /dev/null +++ b/packages/SoundPicker/res/values-gl/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Ton de chamada predeterminado"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Son de alarma predeterminado"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Engadir ton de chamada"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Engadir alarma"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Engadir notificación"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Eliminar"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Non se pode engadir un ton de chamada personalizado"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Non se pode eliminar un ton de chamada personalizado"</string> +</resources> diff --git a/packages/SoundPicker/res/values-gu/strings.xml b/packages/SoundPicker/res/values-gu/strings.xml new file mode 100644 index 000000000000..0505b46351f2 --- /dev/null +++ b/packages/SoundPicker/res/values-gu/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"ડિફોલ્ટ રિંગટોન"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"ડિફૉલ્ટ એલાર્મ સાઉન્ડ"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"રિંગટોન ઉમેરો"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"અલાર્મ ઉમેરો"</string> + <string name="add_notification_text" msgid="4431129543300614788">"નોટિફિકેશન ઉમેરો"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"ડિલીટ કરો"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"કસ્ટમ રિંગટોન ઉમેરવામાં અસમર્થ"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"કસ્ટમ રિંગટોન કાઢી નાખવામાં અસમર્થ"</string> +</resources> diff --git a/packages/SoundPicker/res/values-hi/strings.xml b/packages/SoundPicker/res/values-hi/strings.xml new file mode 100644 index 000000000000..1d18da21d778 --- /dev/null +++ b/packages/SoundPicker/res/values-hi/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"डिफ़ॉल्ट रिंगटोन"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"डिफ़ॉल्ट अलार्म आवाज़"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"रिंगटोन जोड़ेंं"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"अलार्म जोड़ें"</string> + <string name="add_notification_text" msgid="4431129543300614788">"सूचना जोड़ें"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"मिटाएं"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"आपके मुताबिक रिंगटोन नहीं जोड़ी जा सकी"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"आपके मुताबिक रिंगटोन नहीं हटाई जा सकी"</string> +</resources> diff --git a/packages/SoundPicker/res/values-hr/strings.xml b/packages/SoundPicker/res/values-hr/strings.xml new file mode 100644 index 000000000000..1a398175a85e --- /dev/null +++ b/packages/SoundPicker/res/values-hr/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Zadana melodija zvona"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Zadani zvuk alarma"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Dodaj melodiju zvona"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Dodaj alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Dodaj obavijest"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Izbriši"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Dodavanje prilagođene melodije zvona nije moguće"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Brisanje prilagođene melodije zvona nije moguće"</string> +</resources> diff --git a/packages/SoundPicker/res/values-hu/strings.xml b/packages/SoundPicker/res/values-hu/strings.xml new file mode 100644 index 000000000000..6b83509d5058 --- /dev/null +++ b/packages/SoundPicker/res/values-hu/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Alapértelmezett csengőhang"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Alapértelmezett ébresztési hang"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Csengőhang hozzáadása"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Ébresztés hozzáadása"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Értesítés felvétele"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Törlés"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nem sikerült hozzáadni az egyéni csengőhangot"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nem sikerült törölni az egyéni csengőhangot"</string> +</resources> diff --git a/packages/SoundPicker/res/values-hy/strings.xml b/packages/SoundPicker/res/values-hy/strings.xml new file mode 100644 index 000000000000..f422ff861d84 --- /dev/null +++ b/packages/SoundPicker/res/values-hy/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Կանխադրված զանգերանգ"</string> + <string name="notification_sound_default" msgid="8133121186242636840">"Ծանուցման կանխադրված ձայնը"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Զարթուցիչի կանխադրված ձայնը"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Ավելացնել զանգերանգ"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Ավելացնել զարթուցիչ"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Ավելացնել ծանուցում"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Ջնջել"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Հնարավոր չէ հատուկ զանգերանգ ավելացնել"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Հնարավոր չէ ջնջել հատուկ զանգերանգը"</string> +</resources> diff --git a/packages/SoundPicker/res/values-in/strings.xml b/packages/SoundPicker/res/values-in/strings.xml new file mode 100644 index 000000000000..fe2d4a2c35c0 --- /dev/null +++ b/packages/SoundPicker/res/values-in/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Nada dering default"</string> + <string name="notification_sound_default" msgid="8133121186242636840">"Suara notifikasi default"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Suara alarm default"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Tambahkan nada dering"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Tambahkan alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Tambahkan notifikasi"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Hapus"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Tidak dapat menambahkan nada dering khusus"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Tidak dapat menghapus nada dering khusus"</string> +</resources> diff --git a/packages/SoundPicker/res/values-is/strings.xml b/packages/SoundPicker/res/values-is/strings.xml new file mode 100644 index 000000000000..68994aa2b2d9 --- /dev/null +++ b/packages/SoundPicker/res/values-is/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Sjálfgefinn hringitónn"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Sjálfgefið hljóð í vekjara"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Bæta hringitóni við"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Bæta vekjara við"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Bæta tilkynningu við"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Eyða"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Get ekki bætt sérsniðnum hringitóni við"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Get ekki eytt sérsniðnum hringitóni"</string> +</resources> diff --git a/packages/SoundPicker/res/values-it/strings.xml b/packages/SoundPicker/res/values-it/strings.xml new file mode 100644 index 000000000000..e9302c1b5b2e --- /dev/null +++ b/packages/SoundPicker/res/values-it/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Suoneria predefinita"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Suono sveglia predefinito"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Aggiungi suoneria"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Aggiungi sveglia"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Aggiungi notifica"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Elimina"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Impossibile aggiungere suoneria personalizzata"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Impossibile eliminare suoneria personalizzata"</string> +</resources> diff --git a/packages/SoundPicker/res/values-iw/strings.xml b/packages/SoundPicker/res/values-iw/strings.xml new file mode 100644 index 000000000000..2bed8e05aac5 --- /dev/null +++ b/packages/SoundPicker/res/values-iw/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"רינגטון ברירת מחדל"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"צליל לשעון מעורר"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"רינגטון חדש"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"הוספת התראה"</string> + <string name="add_notification_text" msgid="4431129543300614788">"הוספת התראה"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"מחיקה"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"לא ניתן להוסיף רינגטון מותאם אישית"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"לא ניתן למחוק רינגטון מותאם אישית"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ja/strings.xml b/packages/SoundPicker/res/values-ja/strings.xml new file mode 100644 index 000000000000..d3ebcccc3eb5 --- /dev/null +++ b/packages/SoundPicker/res/values-ja/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"プリセット着信音"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"デフォルトの警告音"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"着信音を追加"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"アラームの追加"</string> + <string name="add_notification_text" msgid="4431129543300614788">"通知の追加"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"削除"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"カスタム着信音を追加できません"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"カスタム着信音を削除できません"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ka/strings.xml b/packages/SoundPicker/res/values-ka/strings.xml new file mode 100644 index 000000000000..c097d91a90bd --- /dev/null +++ b/packages/SoundPicker/res/values-ka/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"ნაგულისხმევი ზარი"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"მაღვიძარას ნაგულისხმევი ხმა"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"ზარის დამატება"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"მაღვიძარას დამატება"</string> + <string name="add_notification_text" msgid="4431129543300614788">"შეტყობინების დამატება"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"წაშლა"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"მორგებული ზარის დამატება შეუძლებელია"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"მორგებული ზარის წაშლა შეუძლებელია"</string> +</resources> diff --git a/packages/SoundPicker/res/values-kk/strings.xml b/packages/SoundPicker/res/values-kk/strings.xml new file mode 100644 index 000000000000..a2ddf5ed05ce --- /dev/null +++ b/packages/SoundPicker/res/values-kk/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Әдепкі рингтон"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Әдепкі дабыл дыбысы"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Рингтон енгізу"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Оятқыш енгізу"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Хабарландыру енгізу"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Жою"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Арнаулы рингтонды енгізу мүмкін емес"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Арнаулы рингтонды жою мүмкін емес"</string> +</resources> diff --git a/packages/SoundPicker/res/values-km/strings.xml b/packages/SoundPicker/res/values-km/strings.xml new file mode 100644 index 000000000000..dcc202a8e22b --- /dev/null +++ b/packages/SoundPicker/res/values-km/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"សំឡេងរោទ៍លំនាំដើម"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"សំឡេងម៉ោងរោទិ៍លំនាំដើម"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"បន្ថែមសំឡេងរោទ៍"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"បញ្ចូលម៉ោងរោទ៍"</string> + <string name="add_notification_text" msgid="4431129543300614788">"បញ្ចូលការជូនដំណឹង"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"លុប"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"មិនអាចបន្ថែមសំឡេងរោទ៍ផ្ទាល់ខ្លួនបាន"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"មិនអាចលុបសំឡេងរោទ៍ផ្ទាល់ខ្លួនបានទេ"</string> +</resources> diff --git a/packages/SoundPicker/res/values-kn/strings.xml b/packages/SoundPicker/res/values-kn/strings.xml new file mode 100644 index 000000000000..705dd0d0fed3 --- /dev/null +++ b/packages/SoundPicker/res/values-kn/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"ಡಿಫಾಲ್ಟ್ ರಿಂಗ್ಟೋನ್"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"ಡೀಫಾಲ್ಟ್ ಅಲಾರಾಂ ಧ್ವನಿ"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"ರಿಂಗ್ಟೋನ್ ಸೇರಿಸಿ"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"ಅಲಾರಾಂ ಸೇರಿಸಿ"</string> + <string name="add_notification_text" msgid="4431129543300614788">"ಅಧಿಸೂಚನೆಯನ್ನು ಸೇರಿಸಿ"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"ಅಳಿಸಿ"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"ಕಸ್ಟಮ್ ರಿಂಗ್ಟೋನ್ ಸೇರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"ಕಸ್ಟಮ್ ರಿಂಗ್ಟೋನ್ ಅಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ko/strings.xml b/packages/SoundPicker/res/values-ko/strings.xml new file mode 100644 index 000000000000..6d59034f11da --- /dev/null +++ b/packages/SoundPicker/res/values-ko/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"기본 벨소리"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"기본 알람 소리"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"벨소리 추가"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"알람 추가"</string> + <string name="add_notification_text" msgid="4431129543300614788">"알림 추가"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"삭제"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"맞춤 벨소리를 추가할 수 없습니다."</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"맞춤 벨소리를 삭제할 수 없습니다."</string> +</resources> diff --git a/packages/SoundPicker/res/values-ky/strings.xml b/packages/SoundPicker/res/values-ky/strings.xml new file mode 100644 index 000000000000..bd6c17d00130 --- /dev/null +++ b/packages/SoundPicker/res/values-ky/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Демейки шыңгыр"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Ойготкучтун демейки үнү"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Шыңгыр кошуу"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Ойготкуч кошуу"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Билдирме кошуу"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Жок кылуу"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Жеке рингтон кошулбай жатат"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Жеке рингтон жок кылынбай жатат"</string> +</resources> diff --git a/packages/SoundPicker/res/values-lo/strings.xml b/packages/SoundPicker/res/values-lo/strings.xml new file mode 100644 index 000000000000..f225a6ce1032 --- /dev/null +++ b/packages/SoundPicker/res/values-lo/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"ຣິງໂທນເລີ່ມຕົ້ນ"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"ສຽງໂມງປຸກຕາມຄ່າເລີ່ມຕົ້ນ"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"ເພີ່ມຣິງໂທນ"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"ເພີ່ມໂມງປຸກ"</string> + <string name="add_notification_text" msgid="4431129543300614788">"ເພີ່ມການແຈ້ງເຕືອນ"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"ລຶບ"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add custom ringtone"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete custom ringtone"</string> +</resources> diff --git a/packages/SoundPicker/res/values-lt/strings.xml b/packages/SoundPicker/res/values-lt/strings.xml new file mode 100644 index 000000000000..cc1b0e67fd48 --- /dev/null +++ b/packages/SoundPicker/res/values-lt/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Numatytasis skambėjimo tonas"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Numatytasis signalo garsas"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Pridėti skambėjimo toną"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Pridėti signalą"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Pridėti pranešimą"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Ištrinti"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nepavyksta pridėti tinkinto skambėjimo tono"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nepavyksta ištrinti tinkinto skambėjimo tono"</string> +</resources> diff --git a/packages/SoundPicker/res/values-lv/strings.xml b/packages/SoundPicker/res/values-lv/strings.xml new file mode 100644 index 000000000000..421ad0b5c4f3 --- /dev/null +++ b/packages/SoundPicker/res/values-lv/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Noklusējuma zvana signāls"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Signāla noklusējuma skaņa"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Pievienot zvana signālu"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Pievienot signālu"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Pievienot paziņojumu"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Dzēst"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nevar pievienot pielāgotu zvana signālu"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nevar izdzēst pielāgotu zvana signālu"</string> +</resources> diff --git a/packages/SoundPicker/res/values-mk/strings.xml b/packages/SoundPicker/res/values-mk/strings.xml new file mode 100644 index 000000000000..b5008ce036dc --- /dev/null +++ b/packages/SoundPicker/res/values-mk/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Стандардна мелодија"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Стандарден звук за аларм"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Додај мелодија"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Додајте аларм"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Додајте известување"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Избриши"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Не може да се додаде приспособена мелодија"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Не може да се избрише приспособена мелодија"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ml/strings.xml b/packages/SoundPicker/res/values-ml/strings.xml new file mode 100644 index 000000000000..f2d51f53e51e --- /dev/null +++ b/packages/SoundPicker/res/values-ml/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"ഡിഫോൾട്ട് റിംഗ്ടോൺ"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"ഡിഫോൾട്ട് അലാറം ശബ്ദം"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"റിംഗ്ടോൺ ചേർക്കുക"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"അലാറം ചേർക്കുക"</string> + <string name="add_notification_text" msgid="4431129543300614788">"അറിയിപ്പ് ചേർക്കുക"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"ഇല്ലാതാക്കുക"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"ഇഷ്ടാനുസൃത റിംഗ്ടോൺ ചേർക്കാനാവില്ല"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"ഇഷ്ടാനുസൃത റിംഗ്ടോൺ ഇല്ലാതാക്കാനാവില്ല"</string> +</resources> diff --git a/packages/SoundPicker/res/values-mn/strings.xml b/packages/SoundPicker/res/values-mn/strings.xml new file mode 100644 index 000000000000..e996d19c1a00 --- /dev/null +++ b/packages/SoundPicker/res/values-mn/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Үндсэн хонхны ая"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Сэрүүлгийн өгөгдмөл дуу"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Хонхны ая нэмэх"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Сэрүүлэг нэмэх"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Мэдэгдэл нэмэх"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Устгах"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Захиалгат хонхны ая нэмэх боломжгүй"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Захиалгат хонхны ая устгах боломжгүй"</string> +</resources> diff --git a/packages/SoundPicker/res/values-mr/strings.xml b/packages/SoundPicker/res/values-mr/strings.xml new file mode 100644 index 000000000000..19ab294a792e --- /dev/null +++ b/packages/SoundPicker/res/values-mr/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"डीफॉल्ट रिंगटोन"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"डीफॉल्ट अलार्म ध्वनी"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"रिंगटोन जोडा"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"अलार्म जोडा"</string> + <string name="add_notification_text" msgid="4431129543300614788">"सूचना जोडा"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"हटवा"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"कस्टम रिंगटोन जोडण्यात अक्षम"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"कस्टम रिंगटोन हटविण्यात अक्षम"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ms/strings.xml b/packages/SoundPicker/res/values-ms/strings.xml new file mode 100644 index 000000000000..bda0bdeab9f2 --- /dev/null +++ b/packages/SoundPicker/res/values-ms/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Nada dering lalai"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Bunyi penggera lalai"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Tambah nada dering"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Tambah penggera"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Tambah pemberitahuan"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Padam"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Tidak dapat menambah nada dering tersuai"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Tidak dapat memadamkan nada dering tersuai"</string> +</resources> diff --git a/packages/SoundPicker/res/values-my/strings.xml b/packages/SoundPicker/res/values-my/strings.xml new file mode 100644 index 000000000000..36225d72d74a --- /dev/null +++ b/packages/SoundPicker/res/values-my/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"မူရင်းမြည်သံ"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"မူရင်းနှိုးစက်သံ"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"ဖုန်းမြည်သံကို ထည့်ရန်"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"နှိုးစက်ထည့်ရန်"</string> + <string name="add_notification_text" msgid="4431129543300614788">"အကြောင်းကြားချက် ထည့်ရန်"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"ဖျက်ရန်"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"စိတ်ကြိုက်ဖုန်းမြည်သံကို ထည့်သွင်း၍မရပါ"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"စိတ်ကြိုက်ဖုန်းမြည်သံကို ဖျက်၍မရပါ"</string> +</resources> diff --git a/packages/SoundPicker/res/values-nb/strings.xml b/packages/SoundPicker/res/values-nb/strings.xml new file mode 100644 index 000000000000..726e716d73fe --- /dev/null +++ b/packages/SoundPicker/res/values-nb/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Standard ringetone"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Standard alarmlyd"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Legg til ringelyd"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Legg til en alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Legg til et varsel"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Slett"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Kan ikke legge til egendefinert ringelyd"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Kan ikke slette egendefinert ringelyd"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ne/strings.xml b/packages/SoundPicker/res/values-ne/strings.xml new file mode 100644 index 000000000000..d5f0bf6076c3 --- /dev/null +++ b/packages/SoundPicker/res/values-ne/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"पूर्वनिर्धारित रिङटोन"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"अलार्मका लागि पूर्वनिर्धारित ध्वनि"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"रिङटोन थप्नुहोस्"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"अलार्म थप्नुहोस्"</string> + <string name="add_notification_text" msgid="4431129543300614788">"सूचना थप्नुहोस्"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"मेट्नुहोस्"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"आफू अनुकूल रिङटोन थप्न सकिएन"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"आफू अनुकूल रिङटोनलाई मेट्न सकिएन"</string> +</resources> diff --git a/packages/SoundPicker/res/values-nl/strings.xml b/packages/SoundPicker/res/values-nl/strings.xml new file mode 100644 index 000000000000..998f908f2fad --- /dev/null +++ b/packages/SoundPicker/res/values-nl/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Standaardbeltoon"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Standaard alarmgeluid"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Ringtone toevoegen"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Wekker toevoegen"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Melding toevoegen"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Verwijderen"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Toevoegen van aangepaste ringtone is mislukt"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Verwijderen van aangepaste ringtone is mislukt"</string> +</resources> diff --git a/packages/SoundPicker/res/values-or/strings.xml b/packages/SoundPicker/res/values-or/strings.xml new file mode 100644 index 000000000000..d06f70bd26be --- /dev/null +++ b/packages/SoundPicker/res/values-or/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"ଡିଫଲ୍ଟ ରିଙ୍ଗଟୋନ୍"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"ଡିଫଲ୍ଟ ଆଲାର୍ମ ଶବ୍ଦ"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"ରିଙ୍ଗଟୋନ୍ ଯୋଡ଼ନ୍ତୁ"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"ଆଲାର୍ମ ଯୋଗ କରନ୍ତୁ"</string> + <string name="add_notification_text" msgid="4431129543300614788">"ବିଜ୍ଞପ୍ତି ଯୋଗ କରନ୍ତୁ"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"ଡିଲିଟ୍ କରନ୍ତୁ"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"କଷ୍ଟମ୍ ରିଙ୍ଗଟୋନ୍ ଯୋଡ଼ିପାରିବ ନାହିଁ"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"କଷ୍ଟମ୍ ରିଙ୍ଗଟୋନ୍ ଡିଲିଟ୍ କରିପାରିବ ନାହିଁ"</string> +</resources> diff --git a/packages/SoundPicker/res/values-pa/strings.xml b/packages/SoundPicker/res/values-pa/strings.xml new file mode 100644 index 000000000000..bdd66ed7019d --- /dev/null +++ b/packages/SoundPicker/res/values-pa/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਰਿੰਗਟੋਨ"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਅਲਾਰਮ ਧੁਨੀ"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"ਰਿੰਗਟੋਨ ਸ਼ਾਮਲ ਕਰੋ"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"ਅਲਾਰਮ ਸ਼ਾਮਲ ਕਰੋ"</string> + <string name="add_notification_text" msgid="4431129543300614788">"ਸੂਚਨਾ ਸ਼ਾਮਲ ਕਰੋ"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"ਮਿਟਾਓ"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"ਵਿਉਂਤੀ ਰਿੰਗਟੋਨ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਦੇ ਅਯੋਗ"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"ਵਿਉਂਤੀ ਰਿੰਗਟੋਨ ਨੂੰ ਮਿਟਾਉਣ ਦੇ ਅਯੋਗ"</string> +</resources> diff --git a/packages/SoundPicker/res/values-pl/strings.xml b/packages/SoundPicker/res/values-pl/strings.xml new file mode 100644 index 000000000000..0a5b0e61d661 --- /dev/null +++ b/packages/SoundPicker/res/values-pl/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Dzwonek domyślny"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Domyślny dźwięk alarmu"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Dodaj dzwonek"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Dodaj alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Dodaj powiadomienie"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Usuń"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nie można dodać dzwonka niestandardowego"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nie można usunąć dzwonka niestandardowego"</string> +</resources> diff --git a/packages/SoundPicker/res/values-pt-rBR/strings.xml b/packages/SoundPicker/res/values-pt-rBR/strings.xml new file mode 100644 index 000000000000..ab7184250238 --- /dev/null +++ b/packages/SoundPicker/res/values-pt-rBR/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Toque padrão"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Som de alarme padrão"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Adicionar toque"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Adicionar alarme"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Adicionar notificação"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Excluir"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Não foi possível adicionar o toque personalizado"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Não foi possível excluir o toque personalizado"</string> +</resources> diff --git a/packages/SoundPicker/res/values-pt-rPT/strings.xml b/packages/SoundPicker/res/values-pt-rPT/strings.xml new file mode 100644 index 000000000000..59d35a7341a1 --- /dev/null +++ b/packages/SoundPicker/res/values-pt-rPT/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Toque predefinido"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Som de alarme predefinido"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Adicionar toque"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Adicionar alarme"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Adicionar notificação"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Eliminar"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Não foi possível adicionar o toque personalizado"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Não foi possível eliminar o toque personalizado"</string> +</resources> diff --git a/packages/SoundPicker/res/values-pt/strings.xml b/packages/SoundPicker/res/values-pt/strings.xml new file mode 100644 index 000000000000..ab7184250238 --- /dev/null +++ b/packages/SoundPicker/res/values-pt/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Toque padrão"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Som de alarme padrão"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Adicionar toque"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Adicionar alarme"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Adicionar notificação"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Excluir"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Não foi possível adicionar o toque personalizado"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Não foi possível excluir o toque personalizado"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ro/strings.xml b/packages/SoundPicker/res/values-ro/strings.xml new file mode 100644 index 000000000000..e072880a0dcf --- /dev/null +++ b/packages/SoundPicker/res/values-ro/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Ton de apel prestabilit"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Sunet de alarmă prestabilit"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Adăugați un ton de sonerie"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Adăugați o alarmă"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Adăugați o notificare"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Ștergeți"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nu se poate adăuga tonul de sonerie personalizat"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nu se poate șterge tonul de sonerie personalizat"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ru/strings.xml b/packages/SoundPicker/res/values-ru/strings.xml new file mode 100644 index 000000000000..92668aea6259 --- /dev/null +++ b/packages/SoundPicker/res/values-ru/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Мелодия по умолчанию"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Звук будильника по умолчанию"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Добавить рингтон"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Добавить будильник"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Добавить уведомление"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Удалить"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Не удалось добавить рингтон"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Не удалось удалить рингтон"</string> +</resources> diff --git a/packages/SoundPicker/res/values-si/strings.xml b/packages/SoundPicker/res/values-si/strings.xml new file mode 100644 index 000000000000..b375091b2870 --- /dev/null +++ b/packages/SoundPicker/res/values-si/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"සුපුරුදු රින්ටෝනය සකසන්න"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"පෙරනිමි එලාම හඬ"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"නාද රිද්මය එක් කරන්න"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"ඇඟවීමක් එක් කරන්න"</string> + <string name="add_notification_text" msgid="4431129543300614788">"දැනුම්දීම එක් කරන්න"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"මකන්න"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"අභිරුචි නාද රිද්මය එක් කළ නොහැකිය"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"අභිරුචි නාද රිද්මය මැකිය නොහැකිය"</string> +</resources> diff --git a/packages/SoundPicker/res/values-sk/strings.xml b/packages/SoundPicker/res/values-sk/strings.xml new file mode 100644 index 000000000000..6838af0d2e3f --- /dev/null +++ b/packages/SoundPicker/res/values-sk/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Predvolený tón zvonenia"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Predvolený zvuk budíkov"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Pridať tón zvonenia"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Pridať budík"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Pridať upozornenie"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Odstrániť"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nepodarilo sa pridať vlastný tón zvonenia"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nepodarilo sa odstrániť vlastný tón zvonenia"</string> +</resources> diff --git a/packages/SoundPicker/res/values-sl/strings.xml b/packages/SoundPicker/res/values-sl/strings.xml new file mode 100644 index 000000000000..a050787d72cb --- /dev/null +++ b/packages/SoundPicker/res/values-sl/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Privzeta melodija zvonjenja"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Privzeti zvok alarma"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Dodaj ton zvonjenja"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Dodaj alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Dodaj obvestilo"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Izbriši"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Tona zvonjenja po meri ni mogoče dodati"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Tona zvonjenja po meri ni mogoče izbrisati"</string> +</resources> diff --git a/packages/SoundPicker/res/values-sq/strings.xml b/packages/SoundPicker/res/values-sq/strings.xml new file mode 100644 index 000000000000..7acdfa7efdd0 --- /dev/null +++ b/packages/SoundPicker/res/values-sq/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Zile e paracaktuar."</string> + <string name="notification_sound_default" msgid="8133121186242636840">"Tingulli i parazgjedhur i njoftimit"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Tingulli i parazgjedhur i alarmit"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Shto zile"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Shto një alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Shto një njoftim"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Fshi"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nuk mund të shtojë ton zileje të personalizuar"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nuk mund të fshijë ton zileje të personalizuar"</string> +</resources> diff --git a/packages/SoundPicker/res/values-sr/strings.xml b/packages/SoundPicker/res/values-sr/strings.xml new file mode 100644 index 000000000000..01db396ff628 --- /dev/null +++ b/packages/SoundPicker/res/values-sr/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Подразумевани звук звона"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Подразумевани звук аларма"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Додај мелодију звона"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Додајте аларм"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Додајте обавештење"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Избриши"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Додавање прилагођене мелодије звона није успело"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Брисање прилагођене мелодије звона није успело"</string> +</resources> diff --git a/packages/SoundPicker/res/values-sv/strings.xml b/packages/SoundPicker/res/values-sv/strings.xml new file mode 100644 index 000000000000..f6acdd48617f --- /dev/null +++ b/packages/SoundPicker/res/values-sv/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Standardringsignal"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Standardljud för alarm"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Lägg till ringsignal"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Lägg till alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Lägg till avisering"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Radera"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Det gick inte att lägga till en egen ringsignal"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Det gick inte att radera den egna ringsignalen"</string> +</resources> diff --git a/packages/SoundPicker/res/values-sw/strings.xml b/packages/SoundPicker/res/values-sw/strings.xml new file mode 100644 index 000000000000..beb8780e9d15 --- /dev/null +++ b/packages/SoundPicker/res/values-sw/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Mlio chaguomsingi"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Sauti chaguomsingi ya kengele"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Ongeza mlio wa simu"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Ongeza kengele"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Ongeza arifa"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Futa"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Imeshindwa kuongeza mlio maalum wa simu"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Imeshindwa kufuta mlio maalum wa simu"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ta/strings.xml b/packages/SoundPicker/res/values-ta/strings.xml new file mode 100644 index 000000000000..3c9cc5449f3e --- /dev/null +++ b/packages/SoundPicker/res/values-ta/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"இயல்புநிலை ரிங்டோன்"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"இயல்பு அலார ஒலி"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"ரிங்டோனைச் சேர்"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"அலாரத்தைச் சேர்"</string> + <string name="add_notification_text" msgid="4431129543300614788">"அறிவிப்பைச் சேர்"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"நீக்கு"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"பிரத்தியேக ரிங்டோனைச் சேர்க்க முடியவில்லை"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"பிரத்தியேக ரிங்டோனை நீக்க முடியவில்லை"</string> +</resources> diff --git a/packages/SoundPicker/res/values-te/strings.xml b/packages/SoundPicker/res/values-te/strings.xml new file mode 100644 index 000000000000..e0baa593e61a --- /dev/null +++ b/packages/SoundPicker/res/values-te/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"డిఫాల్ట్ రింగ్టోన్"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"డిఫాల్ట్ అలారం ధ్వని"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"రింగ్టోన్ను జోడించు"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"అలారాన్ని జోడించు"</string> + <string name="add_notification_text" msgid="4431129543300614788">"నోటిఫికేషన్ని జోడించు"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"తొలగించు"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"అనుకూల రింగ్టోన్ను జోడించలేకపోయింది"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"అనుకూల రింగ్టోన్ను తొలగించలేకపోయింది"</string> +</resources> diff --git a/packages/SoundPicker/res/values-th/strings.xml b/packages/SoundPicker/res/values-th/strings.xml new file mode 100644 index 000000000000..098e4dd23e6d --- /dev/null +++ b/packages/SoundPicker/res/values-th/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"เสียงเรียกเข้าเริ่มต้น"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"เสียงปลุกเริ่มต้น"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"เพิ่มเสียงเรียกเข้า"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"เพิ่มการปลุก"</string> + <string name="add_notification_text" msgid="4431129543300614788">"เพิ่มการแจ้งเตือน"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"ลบ"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"ไม่สามารถเพิ่มเสียงเรียกเข้าที่กำหนดเอง"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"ไม่สามารถลบเสียงเรียกเข้าที่กำหนดเอง"</string> +</resources> diff --git a/packages/SoundPicker/res/values-tl/strings.xml b/packages/SoundPicker/res/values-tl/strings.xml new file mode 100644 index 000000000000..80b93de9a788 --- /dev/null +++ b/packages/SoundPicker/res/values-tl/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Default na ringtone"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Default na tunog ng alarm"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Magdagdag ng ringtone"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Magdagdag ng alarm"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Magdagdag ng notification"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"I-delete"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Hindi maidagdag ang custom na ringtone"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Hindi ma-delete ang custom na ringtone"</string> +</resources> diff --git a/packages/SoundPicker/res/values-tr/strings.xml b/packages/SoundPicker/res/values-tr/strings.xml new file mode 100644 index 000000000000..3c634d8c356f --- /dev/null +++ b/packages/SoundPicker/res/values-tr/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Varsayılan zil sesi"</string> + <string name="notification_sound_default" msgid="8133121186242636840">"Varsayılan bildirim sesi"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Varsayılan alarm sesi"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Zil sesi ekle"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Alarm ekle"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Bildirim ekle"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Sil"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Özel zil sesi eklenemiyor"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Özel zil sesi silinemiyor"</string> +</resources> diff --git a/packages/SoundPicker/res/values-uk/strings.xml b/packages/SoundPicker/res/values-uk/strings.xml new file mode 100644 index 000000000000..4ec70c09bc93 --- /dev/null +++ b/packages/SoundPicker/res/values-uk/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Мелодія за умовчанням"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Сигнал будильника за умовчанням"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Додати сигнал"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Додати сигнал"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Додати сповіщення"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Видалити"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Не вдалося додати користувацький сигнал дзвінка"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Не вдалося видалити користувацький сигнал дзвінка"</string> +</resources> diff --git a/packages/SoundPicker/res/values-ur/strings.xml b/packages/SoundPicker/res/values-ur/strings.xml new file mode 100644 index 000000000000..0c2dc7af4010 --- /dev/null +++ b/packages/SoundPicker/res/values-ur/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"ڈیفالٹ رنگ ٹون"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"الارم کی ڈیفالٹ آواز"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"رنگ ٹون شامل کریں"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"الارم شامل کریں"</string> + <string name="add_notification_text" msgid="4431129543300614788">"اطلاع شامل کریں"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"حذف کریں"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"حسب ضرورت رنگ ٹون شامل کرنے سے قاصر ہے"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"حسب ضرورت رنگ ٹون حذف کرنے سے قاصر ہے"</string> +</resources> diff --git a/packages/SoundPicker/res/values-uz/strings.xml b/packages/SoundPicker/res/values-uz/strings.xml new file mode 100644 index 000000000000..3c7693bd02a0 --- /dev/null +++ b/packages/SoundPicker/res/values-uz/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Standart rington"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Standart signal tovushi"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Rington qo‘shish"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Signal qo‘shish"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Bildirishnoma qo‘shish"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"O‘chirish"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Maxsus rington qo‘shib bo‘lmadi"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Maxsus ringtonni o‘chirib bo‘lmadi"</string> +</resources> diff --git a/packages/SoundPicker/res/values-vi/strings.xml b/packages/SoundPicker/res/values-vi/strings.xml new file mode 100644 index 000000000000..e27b6928ff76 --- /dev/null +++ b/packages/SoundPicker/res/values-vi/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Nhạc chuông mặc định"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Âm thanh báo thức mặc định"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Thêm nhạc chuông"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Thêm báo thức"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Thêm thông báo"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Xóa"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Không thể thêm nhạc chuông tùy chỉnh"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Không thể xóa nhạc chuông tùy chỉnh"</string> +</resources> diff --git a/packages/SoundPicker/res/values-zh-rCN/strings.xml b/packages/SoundPicker/res/values-zh-rCN/strings.xml new file mode 100644 index 000000000000..3199803fe7a8 --- /dev/null +++ b/packages/SoundPicker/res/values-zh-rCN/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"默认铃声"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"默认闹钟铃声"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"添加铃声"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"添加闹钟"</string> + <string name="add_notification_text" msgid="4431129543300614788">"添加通知"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"删除"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"无法添加自定义铃声"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"无法删除自定义铃声"</string> +</resources> diff --git a/packages/SoundPicker/res/values-zh-rHK/strings.xml b/packages/SoundPicker/res/values-zh-rHK/strings.xml new file mode 100644 index 000000000000..6c3b2f83b738 --- /dev/null +++ b/packages/SoundPicker/res/values-zh-rHK/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"預設鈴聲"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"預設鬧鐘音效"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"加入鈴聲"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"新增鬧鐘"</string> + <string name="add_notification_text" msgid="4431129543300614788">"新增通知"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"刪除"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"無法加入自訂鈴聲"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"無法刪除自訂鈴聲"</string> +</resources> diff --git a/packages/SoundPicker/res/values-zh-rTW/strings.xml b/packages/SoundPicker/res/values-zh-rTW/strings.xml new file mode 100644 index 000000000000..379c1d5d2e88 --- /dev/null +++ b/packages/SoundPicker/res/values-zh-rTW/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"預設鈴聲"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"預設鬧鐘音效"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"新增鈴聲"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"新增鬧鐘"</string> + <string name="add_notification_text" msgid="4431129543300614788">"新增通知"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"刪除"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"無法新增自訂鈴聲"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"無法刪除自訂鈴聲"</string> +</resources> diff --git a/packages/SoundPicker/res/values-zu/strings.xml b/packages/SoundPicker/res/values-zu/strings.xml new file mode 100644 index 000000000000..6c11dc591f3c --- /dev/null +++ b/packages/SoundPicker/res/values-zu/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="ringtone_default" msgid="798836092118824500">"Iringithoni emisiwe"</string> + <!-- no translation found for notification_sound_default (8133121186242636840) --> + <skip /> + <string name="alarm_sound_default" msgid="4787646764557462649">"Umsindo we-alamu ozenzakalelayo"</string> + <string name="add_ringtone_text" msgid="6642389991738337529">"Engeza ithoni yokukhala"</string> + <string name="add_alarm_text" msgid="3545497316166999225">"Engeza i-alamu"</string> + <string name="add_notification_text" msgid="4431129543300614788">"Engeza isaziso"</string> + <string name="delete_ringtone_text" msgid="201443984070732499">"Susa"</string> + <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Ayikwazi ukwengeza ithoni yokukhala yangokwezifiso"</string> + <string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Ayikwazi ukususa ithoni yokukhala yangokwezifiso"</string> +</resources> diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 0eadcc741747..f63365bcd369 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -45,6 +45,7 @@ android_library { "WindowManager-Shell", "SystemUIPluginLib", "SystemUISharedLib", + "SystemUI-statsd", "SettingsLib", "androidx.viewpager2_viewpager2", "androidx.legacy_legacy-support-v4", @@ -81,6 +82,8 @@ filegroup { "tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java", "tests/src/com/android/systemui/statusbar/RankingBuilder.java", "tests/src/com/android/systemui/statusbar/SbnBuilder.java", + "tests/src/com/android/systemui/util/concurrency/FakeExecutor.java", + "tests/src/com/android/systemui/util/time/FakeSystemClock.java", ], path: "tests/src", } @@ -106,6 +109,7 @@ android_library { static_libs: [ "SystemUIPluginLib", "SystemUISharedLib", + "SystemUI-statsd", "SettingsLib", "androidx.viewpager2_viewpager2", "androidx.legacy_legacy-support-v4", diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index c6f03271f931..133d375b8c6e 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -670,7 +670,7 @@ </activity> <activity android:name=".controls.management.ControlsProviderSelectorActivity" - android:label="Controls Providers" + android:label="@string/controls_providers_title" android:theme="@style/Theme.ControlsManagement" android:showForAllUsers="true" android:clearTaskOnLaunch="true" @@ -679,6 +679,15 @@ android:visibleToInstantApps="true"> </activity> + <activity android:name=".controls.management.ControlsEditingActivity" + android:theme="@style/Theme.ControlsManagement" + android:excludeFromRecents="true" + android:showForAllUsers="true" + android:finishOnTaskLaunch="true" + android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden" + android:visibleToInstantApps="true"> + </activity> + <activity android:name=".controls.management.ControlsFavoritingActivity" android:theme="@style/Theme.ControlsManagement" android:excludeFromRecents="true" diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml index 37b2a60ba2de..a1e6d62234e9 100644 --- a/packages/SystemUI/res-keyguard/values-ne/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml @@ -60,7 +60,7 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"कुनै त्रुटिका कारण यो eSIM लाई असक्षम पार्न सकिएन।"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"प्रविष्टि गर्नुहोस्"</string> <string name="kg_forgot_pattern_button_text" msgid="3304688032024541260">"ढाँचा बिर्सनुभयो"</string> - <string name="kg_wrong_pattern" msgid="5907301342430102842">"गलत ढाँचा"</string> + <string name="kg_wrong_pattern" msgid="5907301342430102842">"प्याटर्न मिलेन"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"गलत पासवर्ड"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"गलत PIN"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="991400408675793914"> diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml index cfb156424f35..de642f3cc27c 100644 --- a/packages/SystemUI/res-keyguard/values-vi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml @@ -60,7 +60,7 @@ <string name="error_disable_esim_msg" msgid="2441188596467999327">"Không thể tắt eSIM do lỗi."</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Nhập"</string> <string name="kg_forgot_pattern_button_text" msgid="3304688032024541260">"Đã quên hình mở khóa"</string> - <string name="kg_wrong_pattern" msgid="5907301342430102842">"Hình không chính xác"</string> + <string name="kg_wrong_pattern" msgid="5907301342430102842">"Hình mở khóa không chính xác"</string> <string name="kg_wrong_password" msgid="4143127991071670512">"Mật khẩu sai"</string> <string name="kg_wrong_pin" msgid="4160978845968732624">"Mã PIN sai"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="991400408675793914"> diff --git a/packages/SystemUI/res-product/values-ca/strings.xml b/packages/SystemUI/res-product/values-ca/strings.xml index a1444bbe9f26..6da5f12bc049 100644 --- a/packages/SystemUI/res-product/values-ca/strings.xml +++ b/packages/SystemUI/res-product/values-ca/strings.xml @@ -25,7 +25,7 @@ <string name="inattentive_sleep_warning_message" product="default" msgid="5693904520452332224">"El dispositiu s\'apagarà aviat; prem per mantenir-lo encès."</string> <string name="keyguard_missing_sim_message" product="tablet" msgid="5018086454277963787">"No hi ha cap targeta SIM a la tauleta."</string> <string name="keyguard_missing_sim_message" product="default" msgid="7053347843877341391">"No hi ha cap targeta SIM al telèfon."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="6278551068943958651">"Els codis PIN no coincideixen"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="6278551068943958651">"Els PIN no coincideixen"</string> <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="302165994845009232">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, la tauleta es restablirà i se\'n suprimiran totes les dades."</string> <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="2594813176164266847">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, el telèfon es restablirà i se\'n suprimiran totes les dades."</string> <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="8710104080409538587">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. La tauleta es restablirà i se\'n suprimiran totes les dades."</string> diff --git a/packages/SystemUI/res/anim/bottomsheet_in.xml b/packages/SystemUI/res/anim/bottomsheet_in.xml new file mode 100644 index 000000000000..0d5efeb2be1e --- /dev/null +++ b/packages/SystemUI/res/anim/bottomsheet_in.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@*android:anim/accelerate_decelerate_interpolator" + android:zAdjustment="top"> + + <translate android:fromYDelta="100%" + android:toYDelta="0" + android:startOffset="@android:integer/config_shortAnimTime" + android:duration="@*android:integer/config_mediumAnimTime"/> +</set> diff --git a/packages/SystemUI/res/anim/bottomsheet_out.xml b/packages/SystemUI/res/anim/bottomsheet_out.xml new file mode 100644 index 000000000000..01f8d2d6b2a3 --- /dev/null +++ b/packages/SystemUI/res/anim/bottomsheet_out.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@*android:anim/accelerate_interpolator" + android:zAdjustment="top"> + + <translate xmlns:android="http://schemas.android.com/apk/res/android" + android:fromYDelta="0" + android:toYDelta="100%" + android:duration="@*android:integer/config_shortAnimTime" /> +</set> diff --git a/packages/SystemUI/res/anim/control_state_list_animator.xml b/packages/SystemUI/res/anim/control_state_list_animator.xml new file mode 100644 index 000000000000..7940b8874ece --- /dev/null +++ b/packages/SystemUI/res/anim/control_state_list_animator.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true"> + <set> + <objectAnimator + android:duration="50" + android:propertyName="scaleX" + android:valueTo="0.97" + android:valueType="floatType" /> + <objectAnimator + android:duration="50" + android:propertyName="scaleY" + android:valueTo="0.97" + android:valueType="floatType" /> + + </set> + </item> + <item> + <set> + <objectAnimator + android:duration="250" + android:propertyName="scaleX" + android:valueTo="1" + android:valueType="floatType" /> + <objectAnimator + android:duration="250" + android:propertyName="scaleY" + android:valueTo="1" + android:valueType="floatType" /> + </set> + </item> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/kg_user_switcher_rounded_background_color.xml b/packages/SystemUI/res/color/kg_user_switcher_rounded_background_color.xml new file mode 100644 index 000000000000..b16d038f68f2 --- /dev/null +++ b/packages/SystemUI/res/color/kg_user_switcher_rounded_background_color.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2016 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_activated="true" android:color="@color/kg_user_switcher_activated_background_color" /> + <item android:color="@android:color/transparent" /> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_frame.xml b/packages/SystemUI/res/color/qs_user_avatar_frame.xml index 344859c27e34..0c816b4feffc 100644 --- a/packages/SystemUI/res/color/qs_user_detail_avatar_frame.xml +++ b/packages/SystemUI/res/color/qs_user_avatar_frame.xml @@ -18,5 +18,5 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_activated="true" android:color="?android:attr/colorAccent" /> - <item android:color="@android:color/transparent" /> + <item android:color="@color/qs_user_switcher_avatar_background" /> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/bg_avatar_selected.xml b/packages/SystemUI/res/drawable/bg_avatar_selected.xml new file mode 100644 index 000000000000..84d3416b7885 --- /dev/null +++ b/packages/SystemUI/res/drawable/bg_avatar_selected.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportWidth="100" + android:viewportHeight="100"> + + <path + android:fillColor="?android:attr/colorAccent" + android:pathData="M50,50m-50,0a50,50 0,1 1,100 0a50,50 0,1 1,-100 0"/> + +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_add_circle.xml b/packages/SystemUI/res/drawable/ic_add_circle.xml new file mode 100644 index 000000000000..79ea70704ec9 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_add_circle.xml @@ -0,0 +1,27 @@ +<!-- + ~ 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48"> + + <path + android:pathData="M23.9998,10.667C16.6398,10.667 10.6665,16.6403 10.6665,24.0003C10.6665,31.3603 16.6398,37.3337 23.9998,37.3337C31.3598,37.3337 37.3332,31.3603 37.3332,24.0003C37.3332,16.6403 31.3598,10.667 23.9998,10.667ZM22.6665,17.3337V22.667H17.3332V25.3337H22.6665V30.667H25.3332V25.3337H30.6665V22.667H25.3332V17.3337H22.6665ZM13.3332,24.0003C13.3332,29.8803 18.1198,34.667 23.9998,34.667C29.8798,34.667 34.6665,29.8803 34.6665,24.0003C34.6665,18.1203 29.8798,13.3337 23.9998,13.3337C18.1198,13.3337 13.3332,18.1203 13.3332,24.0003Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + +</vector> diff --git a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml b/packages/SystemUI/res/drawable/ic_add_circle_qs.xml deleted file mode 100644 index 8e933445be0b..000000000000 --- a/packages/SystemUI/res/drawable/ic_add_circle_qs.xml +++ /dev/null @@ -1,31 +0,0 @@ -<!-- -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. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="48.0dp" - android:height="48.0dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0" - android:tint="?android:attr/colorForeground"> - <group - android:scaleX="1.2" - android:scaleY="1.2" - android:pivotX="12.0" - android:pivotY="12.0"> - <path - android:fillColor="#FFFFFFFF" - android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM17.000000,13.000000l-4.000000,0.000000l0.000000,4.000000l-2.000000,0.000000l0.000000,-4.000000L7.000000,13.000000l0.000000,-2.000000l4.000000,0.000000L11.000000,7.000000l2.000000,0.000000l0.000000,4.000000l4.000000,0.000000L17.000000,13.000000z"/> - </group> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_avatar_guest_user.xml b/packages/SystemUI/res/drawable/ic_avatar_guest_user.xml new file mode 100644 index 000000000000..e3a83a29b764 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_avatar_guest_user.xml @@ -0,0 +1,27 @@ +<!-- + ~ 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48"> + + <path + android:pathData="M23.9998,10.667C16.6398,10.667 10.6665,16.6403 10.6665,24.0003C10.6665,31.3603 16.6398,37.3337 23.9998,37.3337C31.3598,37.3337 37.3332,31.3603 37.3332,24.0003C37.3332,16.6403 31.3598,10.667 23.9998,10.667ZM17.4265,32.3737C17.9998,31.1737 21.4932,30.0003 23.9998,30.0003C26.5065,30.0003 30.0132,31.1737 30.5732,32.3737C28.7598,33.8137 26.4798,34.667 23.9998,34.667C21.5198,34.667 19.2398,33.8137 17.4265,32.3737ZM23.9998,27.3337C25.9465,27.3337 30.5732,28.1203 32.4798,30.4403C33.8398,28.6537 34.6665,26.427 34.6665,24.0003C34.6665,18.1203 29.8798,13.3337 23.9998,13.3337C18.1198,13.3337 13.3332,18.1203 13.3332,24.0003C13.3332,26.427 14.1598,28.6537 15.5198,30.4403C17.4265,28.1203 22.0532,27.3337 23.9998,27.3337ZM23.9998,16.0003C21.4132,16.0003 19.3332,18.0803 19.3332,20.667C19.3332,23.2537 21.4132,25.3337 23.9998,25.3337C26.5865,25.3337 28.6665,23.2537 28.6665,20.667C28.6665,18.0803 26.5865,16.0003 23.9998,16.0003ZM21.9998,20.667C21.9998,21.7737 22.8932,22.667 23.9998,22.667C25.1065,22.667 25.9998,21.7737 25.9998,20.667C25.9998,19.5603 25.1065,18.667 23.9998,18.667C22.8932,18.667 21.9998,19.5603 21.9998,20.667Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + +</vector> diff --git a/packages/SystemUI/res/drawable/ic_avatar_user.xml b/packages/SystemUI/res/drawable/ic_avatar_user.xml new file mode 100644 index 000000000000..b4a4a88bf155 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_avatar_user.xml @@ -0,0 +1,27 @@ +<!-- + ~ 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. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48"> + + <path + android:pathData="M23.9998,10.667C16.6398,10.667 10.6665,16.6403 10.6665,24.0003C10.6665,31.3603 16.6398,37.3337 23.9998,37.3337C31.3598,37.3337 37.3332,31.3603 37.3332,24.0003C37.3332,16.6403 31.3598,10.667 23.9998,10.667ZM32.4798,30.4403C30.5732,28.1203 25.9465,27.3337 23.9998,27.3337C22.0532,27.3337 17.4265,28.1203 15.5198,30.4403C14.1598,28.6537 13.3332,26.427 13.3332,24.0003C13.3332,18.1203 18.1198,13.3337 23.9998,13.3337C29.8798,13.3337 34.6665,18.1203 34.6665,24.0003C34.6665,26.427 33.8398,28.6537 32.4798,30.4403ZM19.3332,20.667C19.3332,18.0803 21.4132,16.0003 23.9998,16.0003C26.5865,16.0003 28.6665,18.0803 28.6665,20.667C28.6665,23.2537 26.5865,25.3337 23.9998,25.3337C21.4132,25.3337 19.3332,23.2537 19.3332,20.667Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> + +</vector> diff --git a/packages/SystemUI/res/drawable/ic_create_bubble.xml b/packages/SystemUI/res/drawable/ic_create_bubble.xml index 1947f58f8f5e..d58e9a347a2f 100644 --- a/packages/SystemUI/res/drawable/ic_create_bubble.xml +++ b/packages/SystemUI/res/drawable/ic_create_bubble.xml @@ -14,16 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:pathData="M12,3c-4.97,0 -9,4.03 -9,9c0,1.39 0.32,2.69 0.88,3.86l1.53,-1.53C5.15,13.6 5,12.82 5,12c0,-3.86 3.14,-7 7,-7s7,3.14 7,7s-3.14,7 -7,7c-0.83,0 -1.62,-0.15 -2.35,-0.42l-1.53,1.53C9.3,20.67 10.61,21 12,21c4.97,0 9,-4.03 9,-9C21,7.03 16.97,3 12,3z" - android:fillColor="#000000"/> - <path - android:pathData="M12.99,15.99l2,0l0,-7l-7,0l0,2l3.59,0l-8.79,8.8l1.41,1.41l8.79,-8.79z" - android:fillColor="#000000"/> -</vector> + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M22,12C22,12 22,12 22,12C22,12 22,12 22,12c0,0.56 -0.06,1.1 -0.15,1.64l-1.97,-0.33c0.15,-0.91 0.15,-1.84 -0.02,-2.75c-0.01,-0.03 -0.01,-0.07 -0.02,-0.1c-0.03,-0.18 -0.08,-0.36 -0.13,-0.54c-0.02,-0.08 -0.04,-0.16 -0.06,-0.24c-0.04,-0.14 -0.09,-0.27 -0.14,-0.41c-0.04,-0.12 -0.08,-0.24 -0.13,-0.35c-0.04,-0.09 -0.08,-0.18 -0.13,-0.27c-0.07,-0.15 -0.14,-0.3 -0.22,-0.45c-0.03,-0.05 -0.06,-0.09 -0.08,-0.14c-0.72,-1.26 -1.77,-2.31 -3.03,-3.03c-0.05,-0.03 -0.09,-0.06 -0.14,-0.08c-0.15,-0.08 -0.3,-0.15 -0.45,-0.22c-0.09,-0.04 -0.18,-0.09 -0.27,-0.13c-0.11,-0.05 -0.23,-0.09 -0.35,-0.13c-0.14,-0.05 -0.27,-0.1 -0.41,-0.14c-0.08,-0.02 -0.16,-0.04 -0.23,-0.06c-0.18,-0.05 -0.36,-0.1 -0.54,-0.13c-0.03,-0.01 -0.07,-0.01 -0.1,-0.01c-0.95,-0.17 -1.93,-0.17 -2.88,0c-0.03,0.01 -0.07,0.01 -0.1,0.01c-0.18,0.04 -0.36,0.08 -0.54,0.13C9.85,4.3 9.77,4.32 9.69,4.34C9.55,4.38 9.42,4.44 9.28,4.49C9.17,4.53 9.05,4.57 8.93,4.61C8.84,4.65 8.75,4.7 8.66,4.74c-0.15,0.07 -0.3,0.14 -0.45,0.22C8.16,4.98 8.12,5.01 8.07,5.04C5.64,6.42 4,9.02 4,12c0,2.74 1.39,5.16 3.49,6.6c0.01,0.01 0.03,0.02 0.04,0.03c0.16,0.11 0.33,0.2 0.49,0.3c0.06,0.04 0.12,0.08 0.19,0.11c0.13,0.07 0.27,0.13 0.4,0.19c0.11,0.05 0.21,0.1 0.32,0.15c0.1,0.04 0.2,0.07 0.29,0.11c0.15,0.06 0.31,0.11 0.46,0.16c0.05,0.02 0.11,0.03 0.17,0.04c1.11,0.31 2.27,0.35 3.4,0.18l0.35,1.98c-0.54,0.09 -1.08,0.14 -1.62,0.14V22c-0.65,0 -1.28,-0.07 -1.9,-0.19c-0.01,0 -0.01,0 -0.02,0c-0.25,-0.05 -0.49,-0.11 -0.73,-0.18c-0.08,-0.02 -0.16,-0.04 -0.23,-0.06c-0.19,-0.06 -0.37,-0.13 -0.55,-0.19c-0.13,-0.05 -0.26,-0.09 -0.39,-0.14c-0.13,-0.05 -0.25,-0.12 -0.38,-0.18c-0.18,-0.08 -0.35,-0.16 -0.53,-0.25c-0.07,-0.04 -0.14,-0.08 -0.21,-0.13c-0.22,-0.12 -0.43,-0.25 -0.64,-0.39c-0.01,-0.01 -0.02,-0.02 -0.04,-0.03c-0.51,-0.35 -1,-0.74 -1.45,-1.2l0,0C3.12,17.26 2,14.76 2,12c0,-2.76 1.12,-5.26 2.93,-7.07l0,0c0.45,-0.45 0.93,-0.84 1.44,-1.19C6.39,3.73 6.4,3.72 6.42,3.71c0.2,-0.14 0.41,-0.26 0.62,-0.38c0.08,-0.05 0.15,-0.09 0.23,-0.14c0.17,-0.09 0.33,-0.16 0.5,-0.24c0.13,-0.06 0.27,-0.13 0.4,-0.19C8.3,2.71 8.42,2.67 8.55,2.63c0.19,-0.07 0.38,-0.14 0.58,-0.2c0.07,-0.02 0.14,-0.03 0.21,-0.05C10.18,2.14 11.07,2 12,2c0.65,0 1.29,0.07 1.91,0.19c0,0 0,0 0,0c0.25,0.05 0.5,0.11 0.75,0.18c0.07,0.02 0.14,0.03 0.22,0.06c0.19,0.06 0.38,0.13 0.57,0.2c0.12,0.05 0.25,0.09 0.37,0.14c0.14,0.06 0.27,0.12 0.4,0.18c0.17,0.08 0.34,0.16 0.51,0.25c0.08,0.04 0.15,0.09 0.23,0.14c0.21,0.12 0.42,0.24 0.62,0.38c0.01,0.01 0.03,0.02 0.04,0.03c0.51,0.35 0.99,0.74 1.45,1.19c0.24,0.24 0.47,0.49 0.68,0.75c0.04,0.04 0.06,0.09 0.1,0.13c0.17,0.22 0.34,0.45 0.5,0.68c0.01,0.01 0.02,0.03 0.03,0.04c0.69,1.05 1.17,2.21 1.42,3.44c0,0 0,0.01 0,0.01c0.06,0.29 0.1,0.58 0.13,0.87c0.01,0.04 0.01,0.09 0.02,0.13C21.98,11.32 22,11.66 22,12zM18.5,15c-1.93,0 -3.5,1.57 -3.5,3.5s1.57,3.5 3.5,3.5s3.5,-1.57 3.5,-3.5S20.43,15 18.5,15z"/> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_device_air_purifier_off.xml b/packages/SystemUI/res/drawable/ic_device_air_purifier_off.xml index b18c3e77ef10..021c3eee50df 100644 --- a/packages/SystemUI/res/drawable/ic_device_air_purifier_off.xml +++ b/packages/SystemUI/res/drawable/ic_device_air_purifier_off.xml @@ -20,15 +20,15 @@ android:viewportWidth="24" android:viewportHeight="24"> <path - android:pathData="M16,19H5V7C5.0016,6.47 5.2128,5.9623 5.5875,5.5875C5.9623,5.2128 6.47,5.0016 7,5H14C14.5299,5.0016 15.0377,5.2128 15.4125,5.5875C15.7872,5.9623 15.9984,6.47 16,7V8H18V7C18,5.9391 17.5786,4.9217 16.8284,4.1716C16.0783,3.4214 15.0609,3 14,3H7C5.9391,3 4.9217,3.4214 4.1716,4.1716C3.4214,4.9217 3,5.9391 3,7V21H18V17H16V19Z" + android:pathData="M10,3H6C5.2043,3 4.4413,3.3161 3.8787,3.8787C3.3161,4.4413 3,5.2043 3,6V21H13V6C13,5.2043 12.6839,4.4413 12.1213,3.8787C11.5587,3.3161 10.7956,3 10,3ZM11,15H10V10H11V15ZM10,8C9.4696,8 8.9609,8.2107 8.5858,8.5858C8.2107,8.9609 8,9.4696 8,10V15C8,15.5304 8.2107,16.0391 8.5858,16.4142C8.9609,16.7893 9.4696,17 10,17H11V19H5V6C5,5.7348 5.1054,5.4804 5.2929,5.2929C5.4804,5.1054 5.7348,5 6,5H10C10.2652,5 10.5196,5.1054 10.7071,5.2929C10.8946,5.4804 11,5.7348 11,6V8H10Z" android:fillColor="#FF000000" /> <path - android:pathData="M19,13C18.6049,13.378 18.1309,13.6638 17.6122,13.8367C17.0935,14.0096 16.5429,14.0653 16,14V16C16.5429,16.0653 17.0935,16.0096 17.6122,15.8367C18.1309,15.6638 18.6049,15.378 19,15C19.93,14.02 20,14 21,14V12C20,12 19.93,12.02 19,13Z" + android:pathData="M18.445,11.168C17.398,11.868 16.574,11.468 15.316,11.051L14.684,12.951C15.476,13.3014 16.3252,13.5047 17.19,13.551C18.0324,13.5503 18.8555,13.2994 19.555,12.83C20.596,12.135 21.383,12.514 22.684,12.947L23.316,11.047C22.688,10.842 20.57,9.753 18.445,11.168Z" android:fillColor="#FF000000" /> <path - android:pathData="M19,9C18.6049,9.378 18.1309,9.6638 17.6122,9.8367C17.0935,10.0096 16.5429,10.0653 16,10V12C16.5429,12.0653 17.0935,12.0096 17.6122,11.8367C18.1309,11.6638 18.6049,11.378 19,11C19.93,10.02 20,10 21,10V8C20,8 19.93,8.02 19,9Z" + android:pathData="M17.189,9.659C18.0316,9.658 18.855,9.4071 19.555,8.938C20.596,8.244 21.384,8.622 22.684,9.055L23.316,7.155C22.727,6.955 20.583,5.8489 18.445,7.2719C17.406,7.966 16.615,7.59 15.317,7.156L14.683,9.056C15.4748,9.4074 16.324,9.6117 17.189,9.659V9.659Z" android:fillColor="#FF000000" /> <path - android:pathData="M10.5,8C9.7089,8 8.9355,8.2346 8.2777,8.6741C7.6199,9.1137 7.1072,9.7383 6.8045,10.4692C6.5017,11.2001 6.4225,12.0044 6.5769,12.7803C6.7312,13.5563 7.1122,14.269 7.6716,14.8284C8.231,15.3878 8.9437,15.7688 9.7196,15.9232C10.4956,16.0775 11.2998,15.9982 12.0307,15.6955C12.7616,15.3927 13.3864,14.8801 13.8259,14.2223C14.2654,13.5645 14.5,12.7911 14.5,12C14.5,10.9391 14.0786,9.9217 13.3284,9.1716C12.5783,8.4214 11.5609,8 10.5,8ZM10.5,14C10.1044,14 9.7178,13.8827 9.3889,13.663C9.06,13.4432 8.8036,13.1308 8.6522,12.7654C8.5009,12.3999 8.4613,11.9978 8.5384,11.6098C8.6156,11.2218 8.8061,10.8655 9.0858,10.5858C9.3655,10.3061 9.7219,10.1156 10.1098,10.0385C10.4978,9.9613 10.8999,10.0008 11.2654,10.1522C11.6308,10.3036 11.9432,10.56 12.1629,10.8889C12.3827,11.2178 12.5,11.6044 12.5,12C12.5,12.5304 12.2893,13.0391 11.9142,13.4142C11.5391,13.7893 11.0304,14 10.5,14Z" + android:pathData="M18.445,15.063C17.41,15.752 16.634,15.384 15.316,14.945L14.684,16.845C15.4762,17.1948 16.3253,17.3981 17.19,17.445C18.0322,17.4438 18.8551,17.1932 19.555,16.725C20.594,16.031 21.385,16.407 22.683,16.841L23.317,14.941C22.728,14.749 20.583,13.637 18.445,15.063Z" android:fillColor="#FF000000" /> </vector> diff --git a/packages/SystemUI/res/drawable/ic_device_air_purifier_on.xml b/packages/SystemUI/res/drawable/ic_device_air_purifier_on.xml index b18c3e77ef10..9533cfe30b75 100644 --- a/packages/SystemUI/res/drawable/ic_device_air_purifier_on.xml +++ b/packages/SystemUI/res/drawable/ic_device_air_purifier_on.xml @@ -20,15 +20,18 @@ android:viewportWidth="24" android:viewportHeight="24"> <path - android:pathData="M16,19H5V7C5.0016,6.47 5.2128,5.9623 5.5875,5.5875C5.9623,5.2128 6.47,5.0016 7,5H14C14.5299,5.0016 15.0377,5.2128 15.4125,5.5875C15.7872,5.9623 15.9984,6.47 16,7V8H18V7C18,5.9391 17.5786,4.9217 16.8284,4.1716C16.0783,3.4214 15.0609,3 14,3H7C5.9391,3 4.9217,3.4214 4.1716,4.1716C3.4214,4.9217 3,5.9391 3,7V21H18V17H16V19Z" + android:pathData="M10,3H6C5.2043,3 4.4413,3.3161 3.8787,3.8787C3.3161,4.4413 3,5.2043 3,6V21H13V17H10C9.4696,17 8.9609,16.7893 8.5858,16.4142C8.2107,16.0391 8,15.5304 8,15V10C8,9.4696 8.2107,8.9609 8.5858,8.5858C8.9609,8.2107 9.4696,8 10,8H13V6C13,5.2043 12.6839,4.4413 12.1213,3.8787C11.5587,3.3161 10.7956,3 10,3Z" android:fillColor="#FF000000" /> <path - android:pathData="M19,13C18.6049,13.378 18.1309,13.6638 17.6122,13.8367C17.0935,14.0096 16.5429,14.0653 16,14V16C16.5429,16.0653 17.0935,16.0096 17.6122,15.8367C18.1309,15.6638 18.6049,15.378 19,15C19.93,14.02 20,14 21,14V12C20,12 19.93,12.02 19,13Z" + android:pathData="M13,10H10V15H13V10Z" android:fillColor="#FF000000" /> <path - android:pathData="M19,9C18.6049,9.378 18.1309,9.6638 17.6122,9.8367C17.0935,10.0096 16.5429,10.0653 16,10V12C16.5429,12.0653 17.0935,12.0096 17.6122,11.8367C18.1309,11.6638 18.6049,11.378 19,11C19.93,10.02 20,10 21,10V8C20,8 19.93,8.02 19,9Z" + android:pathData="M18.445,11.168C17.398,11.868 16.574,11.468 15.316,11.051L14.684,12.951C15.476,13.3014 16.3252,13.5047 17.19,13.551C18.0324,13.5503 18.8555,13.2994 19.555,12.83C20.596,12.135 21.383,12.514 22.684,12.947L23.316,11.047C22.688,10.842 20.57,9.753 18.445,11.168Z" android:fillColor="#FF000000" /> <path - android:pathData="M10.5,8C9.7089,8 8.9355,8.2346 8.2777,8.6741C7.6199,9.1137 7.1072,9.7383 6.8045,10.4692C6.5017,11.2001 6.4225,12.0044 6.5769,12.7803C6.7312,13.5563 7.1122,14.269 7.6716,14.8284C8.231,15.3878 8.9437,15.7688 9.7196,15.9232C10.4956,16.0775 11.2998,15.9982 12.0307,15.6955C12.7616,15.3927 13.3864,14.8801 13.8259,14.2223C14.2654,13.5645 14.5,12.7911 14.5,12C14.5,10.9391 14.0786,9.9217 13.3284,9.1716C12.5783,8.4214 11.5609,8 10.5,8ZM10.5,14C10.1044,14 9.7178,13.8827 9.3889,13.663C9.06,13.4432 8.8036,13.1308 8.6522,12.7654C8.5009,12.3999 8.4613,11.9978 8.5384,11.6098C8.6156,11.2218 8.8061,10.8655 9.0858,10.5858C9.3655,10.3061 9.7219,10.1156 10.1098,10.0385C10.4978,9.9613 10.8999,10.0008 11.2654,10.1522C11.6308,10.3036 11.9432,10.56 12.1629,10.8889C12.3827,11.2178 12.5,11.6044 12.5,12C12.5,12.5304 12.2893,13.0391 11.9142,13.4142C11.5391,13.7893 11.0304,14 10.5,14Z" + android:pathData="M17.189,9.659C18.0316,9.658 18.855,9.4071 19.555,8.938C20.596,8.244 21.384,8.622 22.684,9.055L23.316,7.155C22.727,6.955 20.583,5.8489 18.445,7.2719C17.406,7.966 16.615,7.59 15.317,7.156L14.683,9.056C15.4748,9.4074 16.324,9.6117 17.189,9.659V9.659Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M18.445,15.063C17.41,15.752 16.634,15.384 15.316,14.945L14.684,16.845C15.4762,17.1948 16.3253,17.3981 17.19,17.445C18.0322,17.4438 18.8551,17.1932 19.555,16.725C20.594,16.031 21.385,16.407 22.683,16.841L23.317,14.941C22.728,14.749 20.583,13.637 18.445,15.063Z" android:fillColor="#FF000000" /> </vector> diff --git a/packages/SystemUI/res/drawable/ic_device_cooking_off.xml b/packages/SystemUI/res/drawable/ic_device_cooking_off.xml new file mode 100644 index 000000000000..272a3bb79d40 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_cooking_off.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M9,16H2V18H9V21H11V18C11,17.4696 10.7893,16.9609 10.4142,16.5858C10.0391,16.2107 9.5304,16 9,16Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M15,16C14.4696,16 13.9609,16.2107 13.5858,16.5858C13.2107,16.9609 13,17.4696 13,18V21H15V18H22V16H15Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M6,15H18C18.7956,15 19.5587,14.6839 20.1213,14.1213C20.6839,13.5587 21,12.7956 21,12V8H3V12C3,12.7956 3.3161,13.5587 3.8787,14.1213C4.4413,14.6839 5.2043,15 6,15ZM5,10H19V12C19,12.2652 18.8946,12.5196 18.7071,12.7072C18.5196,12.8947 18.2652,13 18,13H6C5.7348,13 5.4804,12.8947 5.2929,12.7072C5.1054,12.5196 5,12.2652 5,12V10Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M21,5H15V4C15,3.7348 14.8946,3.4804 14.7071,3.2929C14.5196,3.1053 14.2652,3 14,3H10C9.7348,3 9.4804,3.1053 9.2929,3.2929C9.1054,3.4804 9,3.7348 9,4V5H3V7H21V5Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_cooking_on.xml b/packages/SystemUI/res/drawable/ic_device_cooking_on.xml new file mode 100644 index 000000000000..3785f8bffc81 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_cooking_on.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M9,16H2V18H9V21H11V18C11,17.4696 10.7893,16.9609 10.4142,16.5858C10.0391,16.2107 9.5304,16 9,16Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M13,18V21H15V18H22V16H15C14.4696,16 13.9609,16.2107 13.5858,16.5858C13.2107,16.9609 13,17.4696 13,18Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M3,12C3,12.7956 3.3161,13.5587 3.8787,14.1213C4.4413,14.6839 5.2043,15 6,15H18C18.7956,15 19.5587,14.6839 20.1213,14.1213C20.6839,13.5587 21,12.7956 21,12V8H3V12Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M21,5H15V4C15,3.7348 14.8946,3.4804 14.7071,3.2929C14.5196,3.1053 14.2652,3 14,3H10C9.7348,3 9.4804,3.1053 9.2929,3.2929C9.1054,3.4804 9,3.7348 9,4V5H3V7H21V5Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_display_off.xml b/packages/SystemUI/res/drawable/ic_device_display_off.xml new file mode 100644 index 000000000000..07737c959339 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_display_off.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M20,3H4C3.4701,3.0016 2.9623,3.2129 2.5875,3.5877C2.2128,3.9624 2.0016,4.47 2,5V17C2.0016,17.5299 2.2128,18.0376 2.5875,18.4124C2.9623,18.7871 3.4701,18.9984 4,19H8V21H16V19H20C20.5287,18.9974 21.0348,18.7854 21.4078,18.4106C21.7807,18.0359 21.99,17.5287 21.99,17L22,5C21.9984,4.47 21.7872,3.9624 21.4125,3.5877C21.0377,3.2129 20.5299,3.0016 20,3V3ZM20,17H4V5H20V17Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_display_on.xml b/packages/SystemUI/res/drawable/ic_device_display_on.xml new file mode 100644 index 000000000000..2416f6bb4b83 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_display_on.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M20,3H4C3.4701,3.0016 2.9623,3.2129 2.5875,3.5877C2.2128,3.9624 2.0016,4.47 2,5V17C2.0016,17.5299 2.2128,18.0376 2.5875,18.4124C2.9623,18.7871 3.4701,18.9984 4,19H8V21H16V19H20C20.5287,18.9974 21.0348,18.7854 21.4078,18.4106C21.7807,18.0359 21.99,17.5287 21.99,17L22,5C21.9984,4.47 21.7872,3.9624 21.4125,3.5877C21.0377,3.2129 20.5299,3.0016 20,3V3ZM20,17H4V5H20V17Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M19,6H5V16H19V6Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_door_off.xml b/packages/SystemUI/res/drawable/ic_device_door_off.xml new file mode 100644 index 000000000000..291f312e18a6 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_door_off.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M7,14H5C4.7348,14 4.4804,14.1054 4.2929,14.293C4.1054,14.4805 4,14.7348 4,15C4,15.2652 4.1054,15.5195 4.2929,15.707C4.4804,15.8946 4.7348,16 5,16H7V21H17V3H7V14ZM15,5V19H9V16H12C12.2652,16 12.5196,15.8946 12.7071,15.707C12.8946,15.5195 13,15.2652 13,15C13,14.7348 12.8946,14.4805 12.7071,14.293C12.5196,14.1054 12.2652,14 12,14H9V5H15Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M20,3C19.7348,3 19.4804,3.1054 19.2929,3.293C19.1054,3.4805 19,3.7348 19,4V8C19,8.2652 19.1054,8.5195 19.2929,8.707C19.4804,8.8946 19.7348,9 20,9C20.2652,9 20.5196,8.8946 20.7071,8.707C20.8946,8.5195 21,8.2652 21,8V4C21,3.7348 20.8946,3.4805 20.7071,3.293C20.5196,3.1054 20.2652,3 20,3Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M12,10C12.5523,10 13,9.5523 13,9C13,8.4477 12.5523,8 12,8C11.4477,8 11,8.4477 11,9C11,9.5523 11.4477,10 12,10Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_door_on.xml b/packages/SystemUI/res/drawable/ic_device_door_on.xml new file mode 100644 index 000000000000..e6cdf11f8dea --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_door_on.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M20,3C19.7348,3 19.4804,3.1054 19.2929,3.293C19.1054,3.4805 19,3.7348 19,4V8C19,8.2652 19.1054,8.5195 19.2929,8.707C19.4804,8.8946 19.7348,9 20,9C20.2652,9 20.5196,8.8946 20.7071,8.707C20.8946,8.5195 21,8.2652 21,8V4C21,3.7348 20.8946,3.4805 20.7071,3.293C20.5196,3.1054 20.2652,3 20,3Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M13,15C13,14.7348 12.8946,14.4805 12.7071,14.293C12.5196,14.1054 12.2652,14 12,14H5C4.7348,14 4.4804,14.1054 4.2929,14.293C4.1054,14.4805 4,14.7348 4,15C4,15.2652 4.1054,15.5195 4.2929,15.707C4.4804,15.8946 4.7348,16 5,16H12C12.2652,16 12.5196,15.8946 12.7071,15.707C12.8946,15.5195 13,15.2652 13,15Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M7,13H12C12.5304,13 13.0391,13.2109 13.4142,13.5859C13.7893,13.961 14,14.4696 14,15C14,15.5304 13.7893,16.039 13.4142,16.4141C13.0391,16.7891 12.5304,17 12,17H7V21H17V3H7V13ZM12,8C12.1978,8 12.3911,8.0586 12.5556,8.1685C12.72,8.2783 12.8482,8.4345 12.9239,8.6172C12.9996,8.7999 13.0194,9.0013 12.9808,9.1953C12.9422,9.3893 12.847,9.5672 12.7071,9.707C12.5673,9.8469 12.3891,9.9424 12.1951,9.981C12.0011,10.0195 11.8,9.9995 11.6173,9.9238C11.4346,9.8481 11.2784,9.7201 11.1685,9.5557C11.0586,9.3912 11,9.1978 11,9C11,8.7348 11.1054,8.4805 11.2929,8.293C11.4804,8.1054 11.7348,8 12,8Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_garage_on.xml b/packages/SystemUI/res/drawable/ic_device_garage_on.xml index 8865983f0d7d..eeb4bc153c5d 100644 --- a/packages/SystemUI/res/drawable/ic_device_garage_on.xml +++ b/packages/SystemUI/res/drawable/ic_device_garage_on.xml @@ -20,9 +20,12 @@ android:viewportWidth="24" android:viewportHeight="24"> <path - android:pathData="M20,9L12,3L4,9V21H6V10L12,5.5L18,10V21H20V9Z" + android:pathData="M12,3L4,9V21H7V11H17V21H20V9L12,3Z" android:fillColor="#FF000000" /> <path - android:pathData="M7,11V21H17V11H7ZM15,13V15H9V13H15ZM9,19V17H15V19H9Z" + android:pathData="M15,13H9V15H15V13Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M15,17H9V19H15V17Z" android:fillColor="#FF000000" /> </vector> diff --git a/packages/SystemUI/res/drawable/ic_device_outdoor_garden_off.xml b/packages/SystemUI/res/drawable/ic_device_outdoor_garden_off.xml new file mode 100644 index 000000000000..0d98f9e2a6f3 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_outdoor_garden_off.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M18,3L15,5.25L12,3L9,5.25L6,3L2,6V21H22V6L18,3ZM8,19H4V7L6,5.5L8,7V19ZM14,19H10V7L12,5.5L14,7V19ZM20,19H16V7L18,5.5L20,7V19Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_outdoor_garden_on.xml b/packages/SystemUI/res/drawable/ic_device_outdoor_garden_on.xml new file mode 100644 index 000000000000..00b6af68272a --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_outdoor_garden_on.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M2,6V21H8V6L5,3L2,6Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M9,6V21H15V6L12,3L9,6Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M19,3L16,6V21H22V6L19,3Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_pergola_on.xml b/packages/SystemUI/res/drawable/ic_device_pergola_on.xml index b7113dcd042f..cbbee8c05e1b 100644 --- a/packages/SystemUI/res/drawable/ic_device_pergola_on.xml +++ b/packages/SystemUI/res/drawable/ic_device_pergola_on.xml @@ -20,7 +20,7 @@ android:viewportWidth="24" android:viewportHeight="24"> <path - android:pathData="M20,2C19.7348,2 19.4804,2.1054 19.2929,2.293C19.1054,2.4805 19,2.7348 19,3V4H5V3C5,2.7348 4.8946,2.4805 4.7071,2.293C4.5196,2.1054 4.2652,2 4,2C3.7348,2 3.4804,2.1054 3.2929,2.293C3.1054,2.4805 3,2.7348 3,3V21H5V10H19V21H21V3C21,2.7348 20.8946,2.4805 20.7071,2.293C20.5196,2.1054 20.2652,2 20,2ZM5,8V6H19V8H5Z" + android:pathData="M20,2C19.7348,2 19.4804,2.1054 19.2929,2.293C19.1054,2.4805 19,2.7348 19,3V4H5V3C5,2.7348 4.8946,2.4805 4.7071,2.293C4.5196,2.1054 4.2652,2 4,2C3.7348,2 3.4804,2.1054 3.2929,2.293C3.1054,2.4805 3,2.7348 3,3V21H5V10H19V21H21V3C21,2.7348 20.8946,2.4805 20.7071,2.293C20.5196,2.1054 20.2652,2 20,2Z" android:fillColor="#FF000000" /> <path android:pathData="M8,18H11V21H13V18H16V16H8V18Z" diff --git a/packages/SystemUI/res/drawable/ic_device_thermostat_off.xml b/packages/SystemUI/res/drawable/ic_device_thermostat_off.xml index 1ba8741e4ae2..27da211b315d 100644 --- a/packages/SystemUI/res/drawable/ic_device_thermostat_off.xml +++ b/packages/SystemUI/res/drawable/ic_device_thermostat_off.xml @@ -20,6 +20,6 @@ android:viewportWidth="24" android:viewportHeight="24"> <path - android:pathData="M16,18.97C16.6469,18.1148 16.9979,17.0723 17,16C16.9993,15.2239 16.8183,14.4586 16.4712,13.7644C16.1241,13.0702 15.6205,12.4662 15,12V6C15,5.2043 14.6839,4.4413 14.1213,3.8787C13.5587,3.3161 12.7956,3 12,3C11.2044,3 10.4413,3.3161 9.8787,3.8787C9.3161,4.4413 9,5.2043 9,6V12C8.3795,12.4662 7.8759,13.0702 7.5288,13.7644C7.1817,14.4586 7.0007,15.2239 7,16C7.0021,17.0723 7.3531,18.1148 8,18.97V19H8.02C8.4815,19.6206 9.0818,20.1246 9.7729,20.4719C10.4639,20.8192 11.2266,21.0001 12,21.0001C12.7734,21.0001 13.5361,20.8192 14.2271,20.4719C14.9182,20.1246 15.5185,19.6206 15.98,19H16V18.97ZM10.2,13.6L11,13V6C11,5.7348 11.1054,5.4804 11.2929,5.2929C11.4804,5.1054 11.7348,5 12,5C12.2652,5 12.5196,5.1054 12.7071,5.2929C12.8946,5.4804 13,5.7348 13,6V13L13.8,13.6C14.1711,13.8809 14.4723,14.2435 14.6805,14.6598C14.8886,15.076 14.9979,15.5346 15,16H9C9.0009,15.5344 9.1098,15.0754 9.318,14.659C9.5262,14.2426 9.8281,13.8801 10.2,13.6Z" + android:pathData="M15,12V6C15,5.2043 14.6839,4.4413 14.1213,3.8787C13.5587,3.3161 12.7956,3 12,3C11.2044,3 10.4413,3.3161 9.8787,3.8787C9.3161,4.4413 9,5.2043 9,6V12C8.3795,12.4662 7.8759,13.0702 7.5288,13.7644C7.1817,14.4586 7.0007,15.2239 7,16C7.0021,17.0723 7.3531,18.1148 8,18.97V19H8.02C8.4815,19.6206 9.0818,20.1246 9.7729,20.4719C10.4639,20.8192 11.2266,21.0001 12,21.0001C12.7734,21.0001 13.5361,20.8192 14.2271,20.4719C14.9182,20.1246 15.5185,19.6206 15.98,19H16V18.97C16.6469,18.1148 16.9979,17.0723 17,16C16.9993,15.2239 16.8183,14.4586 16.4712,13.7644C16.1241,13.0702 15.6205,12.4662 15,12ZM14.4,17.773L14.367,17.819C14.0952,18.1807 13.744,18.4752 13.3405,18.6799C12.937,18.8846 12.4919,18.9941 12.0395,18.9998C11.5871,19.0055 11.1394,18.9073 10.7309,18.7128C10.3223,18.5184 9.9638,18.2327 9.683,17.878L9.604,17.778C9.2154,17.2664 9.0034,16.6425 9,16C9.0016,15.5346 9.1108,15.0758 9.3189,14.6595C9.5271,14.2432 9.8286,13.8805 10.2,13.6L11,13V6C11,5.7348 11.1054,5.4804 11.2929,5.2929C11.4804,5.1054 11.7348,5 12,5C12.2652,5 12.5196,5.1054 12.7071,5.2929C12.8946,5.4804 13,5.7348 13,6V13L13.8,13.6C14.1714,13.8805 14.4729,14.2432 14.6811,14.6595C14.8892,15.0758 14.9984,15.5346 15,16C14.9967,16.6403 14.7862,17.2623 14.4,17.773V17.773Z" android:fillColor="#FF000000" /> </vector> diff --git a/packages/SystemUI/res/drawable/ic_device_thermostat_on.xml b/packages/SystemUI/res/drawable/ic_device_thermostat_on.xml index 1ba8741e4ae2..deabb0e45b3d 100644 --- a/packages/SystemUI/res/drawable/ic_device_thermostat_on.xml +++ b/packages/SystemUI/res/drawable/ic_device_thermostat_on.xml @@ -20,6 +20,6 @@ android:viewportWidth="24" android:viewportHeight="24"> <path - android:pathData="M16,18.97C16.6469,18.1148 16.9979,17.0723 17,16C16.9993,15.2239 16.8183,14.4586 16.4712,13.7644C16.1241,13.0702 15.6205,12.4662 15,12V6C15,5.2043 14.6839,4.4413 14.1213,3.8787C13.5587,3.3161 12.7956,3 12,3C11.2044,3 10.4413,3.3161 9.8787,3.8787C9.3161,4.4413 9,5.2043 9,6V12C8.3795,12.4662 7.8759,13.0702 7.5288,13.7644C7.1817,14.4586 7.0007,15.2239 7,16C7.0021,17.0723 7.3531,18.1148 8,18.97V19H8.02C8.4815,19.6206 9.0818,20.1246 9.7729,20.4719C10.4639,20.8192 11.2266,21.0001 12,21.0001C12.7734,21.0001 13.5361,20.8192 14.2271,20.4719C14.9182,20.1246 15.5185,19.6206 15.98,19H16V18.97ZM10.2,13.6L11,13V6C11,5.7348 11.1054,5.4804 11.2929,5.2929C11.4804,5.1054 11.7348,5 12,5C12.2652,5 12.5196,5.1054 12.7071,5.2929C12.8946,5.4804 13,5.7348 13,6V13L13.8,13.6C14.1711,13.8809 14.4723,14.2435 14.6805,14.6598C14.8886,15.076 14.9979,15.5346 15,16H9C9.0009,15.5344 9.1098,15.0754 9.318,14.659C9.5262,14.2426 9.8281,13.8801 10.2,13.6Z" + android:pathData="M15,12V6C15,5.2043 14.6839,4.4413 14.1213,3.8787C13.5587,3.3161 12.7956,3 12,3C11.2044,3 10.4413,3.3161 9.8787,3.8787C9.3161,4.4413 9,5.2043 9,6V12C8.3795,12.4662 7.8759,13.0702 7.5288,13.7644C7.1817,14.4586 7.0007,15.2239 7,16C7.0021,17.0723 7.3531,18.1148 8,18.97V19H8.02C8.4815,19.6206 9.0818,20.1246 9.7729,20.4719C10.4639,20.8192 11.2266,21.0001 12,21.0001C12.7734,21.0001 13.5361,20.8192 14.2271,20.4719C14.9182,20.1246 15.5185,19.6206 15.98,19H16V18.97C16.6469,18.1148 16.9979,17.0723 17,16C16.9993,15.2239 16.8183,14.4586 16.4712,13.7644C16.1241,13.0702 15.6205,12.4662 15,12V12ZM11,6C11,5.7348 11.1054,5.4804 11.2929,5.2929C11.4804,5.1054 11.7348,5 12,5C12.2652,5 12.5196,5.1054 12.7071,5.2929C12.8946,5.4804 13,5.7348 13,6V10H11V6Z" android:fillColor="#FF000000" /> </vector> diff --git a/packages/SystemUI/res/drawable/ic_device_tv_off.xml b/packages/SystemUI/res/drawable/ic_device_tv_off.xml index dd91ed831bb8..f0c9b565acd6 100644 --- a/packages/SystemUI/res/drawable/ic_device_tv_off.xml +++ b/packages/SystemUI/res/drawable/ic_device_tv_off.xml @@ -20,6 +20,6 @@ android:viewportWidth="24" android:viewportHeight="24"> <path - android:pathData="M20,4H4C3.4701,4.0016 2.9623,4.2129 2.5875,4.5876C2.2128,4.9624 2.0016,5.47 2,6V17C2.0016,17.5299 2.2128,18.0376 2.5875,18.4124C2.9623,18.7871 3.4701,18.9984 4,19V21H5L5.667,19H18.333L19,21H20V19C20.5299,18.9984 21.0377,18.7871 21.4125,18.4124C21.7872,18.0376 21.9984,17.5299 22,17V6C21.9984,5.47 21.7872,4.9624 21.4125,4.5876C21.0377,4.2129 20.5299,4.0016 20,4ZM20,17H4V6H20V17Z" + android:pathData="M20,4H4C3.4701,4.0016 2.9623,4.2129 2.5875,4.5876C2.2128,4.9624 2.0016,5.47 2,6V17C2.0016,17.5299 2.2128,18.0376 2.5875,18.4124C2.9623,18.7871 3.4701,18.9984 4,19V21H5L5.667,19H18.333L19,21H20V19C20.5299,18.9984 21.0377,18.7871 21.4125,18.4124C21.7872,18.0376 21.9984,17.5299 22,17V6C21.9984,5.47 21.7872,4.9624 21.4125,4.5876C21.0377,4.2129 20.5299,4.0016 20,4V4ZM20,17H4V6H20V17Z" android:fillColor="#FF000000" /> </vector> diff --git a/packages/SystemUI/res/drawable/ic_device_tv_on.xml b/packages/SystemUI/res/drawable/ic_device_tv_on.xml index dd91ed831bb8..ed625e9420de 100644 --- a/packages/SystemUI/res/drawable/ic_device_tv_on.xml +++ b/packages/SystemUI/res/drawable/ic_device_tv_on.xml @@ -20,6 +20,9 @@ android:viewportWidth="24" android:viewportHeight="24"> <path - android:pathData="M20,4H4C3.4701,4.0016 2.9623,4.2129 2.5875,4.5876C2.2128,4.9624 2.0016,5.47 2,6V17C2.0016,17.5299 2.2128,18.0376 2.5875,18.4124C2.9623,18.7871 3.4701,18.9984 4,19V21H5L5.667,19H18.333L19,21H20V19C20.5299,18.9984 21.0377,18.7871 21.4125,18.4124C21.7872,18.0376 21.9984,17.5299 22,17V6C21.9984,5.47 21.7872,4.9624 21.4125,4.5876C21.0377,4.2129 20.5299,4.0016 20,4ZM20,17H4V6H20V17Z" + android:pathData="M20,4H4C3.4701,4.0016 2.9623,4.2129 2.5875,4.5876C2.2128,4.9624 2.0016,5.47 2,6V17C2.0016,17.5299 2.2128,18.0376 2.5875,18.4124C2.9623,18.7871 3.4701,18.9984 4,19V21H5L5.667,19H18.333L19,21H20V19C20.5299,18.9984 21.0377,18.7871 21.4125,18.4124C21.7872,18.0376 21.9984,17.5299 22,17V6C21.9984,5.47 21.7872,4.9624 21.4125,4.5876C21.0377,4.2129 20.5299,4.0016 20,4V4ZM20,17H4V6H20V17Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M19,7H5V16H19V7Z" android:fillColor="#FF000000" /> </vector> diff --git a/packages/SystemUI/res/drawable/ic_device_unknown_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_device_unknown_gm2_24px.xml deleted file mode 100644 index 24e063506250..000000000000 --- a/packages/SystemUI/res/drawable/ic_device_unknown_gm2_24px.xml +++ /dev/null @@ -1,9 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:fillColor="#FF000000" - android:pathData="M12,2l-5.5,9h11L12,2zM12,5.84L13.93,9h-3.87L12,5.84zM17.5,13c-2.49,0 -4.5,2.01 -4.5,4.5s2.01,4.5 4.5,4.5 4.5,-2.01 4.5,-4.5 -2.01,-4.5 -4.5,-4.5zM17.5,20c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5zM3,21.5h8v-8L3,13.5v8zM5,15.5h4v4L5,19.5v-4z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_unknown_off.xml b/packages/SystemUI/res/drawable/ic_device_unknown_off.xml new file mode 100644 index 000000000000..55820d0b5f63 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_unknown_off.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M8,6.5V11.76C8.8027,12.2963 9.4117,13.0766 9.7369,13.9856C10.0622,14.8946 10.0865,15.8841 9.8062,16.8079C9.526,17.7317 8.9561,18.541 8.1807,19.1161C7.4052,19.6912 6.4654,20.0017 5.5,20.0017C4.5346,20.0017 3.5948,19.6912 2.8193,19.1161C2.0439,18.541 1.474,17.7317 1.1938,16.8079C0.9135,15.8841 0.9378,14.8946 1.2631,13.9856C1.5883,13.0766 2.1973,12.2963 3,11.76V6.5C3,5.837 3.2634,5.2011 3.7322,4.7322C4.2011,4.2634 4.837,4 5.5,4C6.163,4 6.7989,4.2634 7.2678,4.7322C7.7366,5.2011 8,5.837 8,6.5ZM3.049,16H7.949C8.0467,15.5132 7.9978,15.0084 7.8084,14.5495C7.619,14.0905 7.2976,13.6981 6.885,13.422L5.998,12.828V6.5C5.998,6.3674 5.9453,6.2402 5.8516,6.1465C5.7578,6.0527 5.6306,6 5.498,6C5.3654,6 5.2382,6.0527 5.1445,6.1465C5.0507,6.2402 4.998,6.3674 4.998,6.5V12.828L4.111,13.422C3.7061,13.6922 3.3887,14.0746 3.1976,14.5223C3.0065,14.97 2.95,15.4637 3.035,15.943C3.0363,15.951 3.0389,15.959 3.0416,15.967C3.0453,15.978 3.049,15.989 3.049,16Z" + android:fillColor="#FF000000" + android:fillType="evenOdd"/> + <path + android:pathData="M14,16H20V18H14V16Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M17,4C15.7113,4.0006 14.457,4.416 13.4228,5.1849C12.3886,5.9538 11.6294,7.0353 11.2577,8.2692C10.8859,9.5031 10.9214,10.824 11.3587,12.0362C11.7961,13.2484 12.6121,14.2876 13.686,15H20.314C21.3879,14.2876 22.204,13.2484 22.6413,12.0362C23.0786,10.824 23.1141,9.5031 22.7423,8.2692C22.3706,7.0353 21.6114,5.9538 20.5772,5.1849C19.543,4.416 18.2887,4.0006 17,4ZM19.643,13H14.357C13.7469,12.4629 13.3149,11.7528 13.1185,10.9641C12.9221,10.1753 12.9707,9.3455 13.2577,8.5851C13.5447,7.8246 14.0566,7.1697 14.7251,6.7074C15.3937,6.2452 16.1872,5.9976 17,5.9976C17.8128,5.9976 18.6063,6.2452 19.2749,6.7074C19.9434,7.1697 20.4553,7.8246 20.7423,8.5851C21.0293,9.3455 21.0779,10.1753 20.8815,10.9641C20.6851,11.7528 20.2531,12.4629 19.643,13Z" + android:fillColor="#FF000000" + android:fillType="evenOdd"/> + <path + android:pathData="M18.0607,19.5607C17.7793,19.842 17.3978,20 17,20C16.6022,20 16.2207,19.842 15.9393,19.5607C15.658,19.2794 15.5,18.8978 15.5,18.5H18.5C18.5,18.8978 18.342,19.2794 18.0607,19.5607Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_unknown_on.xml b/packages/SystemUI/res/drawable/ic_device_unknown_on.xml new file mode 100644 index 000000000000..08d9817389d2 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_unknown_on.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M8,6.5V11.76C8.8027,12.2963 9.4117,13.0766 9.7369,13.9856C10.0622,14.8946 10.0865,15.8841 9.8062,16.8079C9.526,17.7317 8.9561,18.541 8.1807,19.1161C7.4052,19.6912 6.4654,20.0017 5.5,20.0017C4.5346,20.0017 3.5948,19.6912 2.8193,19.1161C2.0439,18.541 1.474,17.7317 1.1938,16.8079C0.9135,15.8841 0.9378,14.8946 1.2631,13.9856C1.5883,13.0766 2.1973,12.2963 3,11.76V6.5C3,5.837 3.2634,5.2011 3.7322,4.7322C4.2011,4.2634 4.837,4 5.5,4C6.163,4 6.7989,4.2634 7.2678,4.7322C7.7366,5.2011 8,5.837 8,6.5ZM3.049,16H7.949C8.0469,15.5134 7.9983,15.0087 7.8093,14.5498C7.6202,14.0909 7.2992,13.6984 6.887,13.422L6,12.828V6.5C6,6.3674 5.9473,6.2402 5.8535,6.1465C5.7598,6.0527 5.6326,6 5.5,6C5.3674,6 5.2402,6.0527 5.1465,6.1465C5.0527,6.2402 5,6.3674 5,6.5V12.828L4.111,13.422C3.7061,13.6922 3.3887,14.0746 3.1976,14.5223C3.0065,14.97 2.95,15.4637 3.035,15.943C3.0363,15.951 3.0389,15.959 3.0416,15.967C3.0453,15.978 3.049,15.989 3.049,16Z" + android:fillColor="#FF000000" + android:fillType="evenOdd"/> + <path + android:pathData="M20,16V18H14V16H20Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M17,4C15.7113,4.0006 14.457,4.416 13.4228,5.1849C12.3886,5.9538 11.6294,7.0353 11.2577,8.2692C10.8859,9.5031 10.9214,10.824 11.3587,12.0362C11.796,13.2484 12.6121,14.2876 13.686,15H20.314C21.3879,14.2876 22.204,13.2484 22.6413,12.0362C23.0786,10.824 23.1141,9.5031 22.7423,8.2692C22.3706,7.0353 21.6114,5.9538 20.5772,5.1849C19.543,4.416 18.2887,4.0006 17,4Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M18.0607,19.5607C17.7794,19.842 17.3978,20 17,20C16.6022,20 16.2206,19.842 15.9393,19.5607C15.658,19.2794 15.5,18.8978 15.5,18.5H18.5C18.5,18.8978 18.342,19.2794 18.0607,19.5607Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_water_off.xml b/packages/SystemUI/res/drawable/ic_device_water_off.xml new file mode 100644 index 000000000000..e1a7846af49a --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_water_off.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M17.654,7.563L12,2L6.346,7.563C5.6036,8.2877 5.0136,9.1533 4.6108,10.1094C4.2079,11.0654 4.0002,12.0924 4,13.1299C4,15.2516 4.8429,17.2863 6.3432,18.7866C7.8434,20.2869 9.8783,21.1299 12,21.1299C14.1217,21.1299 16.1566,20.2869 17.6569,18.7866C19.1572,17.2863 20,15.2516 20,13.1299C20,12.0924 19.7925,11.0654 19.3896,10.1094C18.9867,9.1533 18.3966,8.2875 17.654,7.563ZM12,19C10.4265,19.0152 8.9113,18.4056 7.7865,17.3052C6.6617,16.2048 6.0192,14.7033 6,13.1299C5.9996,12.3577 6.1541,11.5933 6.4543,10.8818C6.7546,10.1704 7.1945,9.5262 7.748,8.9878L12,4.8061L16.252,8.9888C16.8056,9.5269 17.2456,10.171 17.5458,10.8823C17.8461,11.5936 18.0005,12.3578 18,13.1299C17.9807,14.7033 17.3383,16.2048 16.2135,17.3052C15.0887,18.4056 13.5735,19.0152 12,19Z" + android:fillColor="#FF000000" /> + <path + android:pathData="M16,12C15.7348,12 15.4804,12.1054 15.2929,12.293C15.1054,12.4805 15,12.7348 15,13C15,13.7956 14.6839,14.5585 14.1213,15.1211C13.5587,15.6837 12.7956,16 12,16C11.7348,16 11.4804,16.1054 11.2929,16.293C11.1054,16.4805 11,16.7348 11,17C11,17.2652 11.1054,17.5195 11.2929,17.707C11.4804,17.8946 11.7348,18 12,18C13.3256,17.9984 14.5964,17.471 15.5338,16.5337C16.4711,15.5964 16.9984,14.3256 17,13C17,12.7348 16.8946,12.4805 16.7071,12.293C16.5196,12.1054 16.2652,12 16,12Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_device_water_on.xml b/packages/SystemUI/res/drawable/ic_device_water_on.xml new file mode 100644 index 000000000000..e57e053b8d4d --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_water_on.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M17.654,7.563L12,2L6.346,7.563C5.6036,8.2877 5.0136,9.1533 4.6108,10.1094C4.2079,11.0654 4.0002,12.0924 4,13.1299C4.0174,15.2343 4.87,17.2458 6.3703,18.7217C7.8705,20.1975 9.8956,21.017 12,21C14.1044,21.017 16.1295,20.1975 17.6297,18.7217C19.13,17.2458 19.9826,15.2343 20,13.1299C20,12.0924 19.7925,11.0654 19.3896,10.1094C18.9867,9.1533 18.3966,8.2875 17.654,7.563ZM12,18C11.7348,18 11.4804,17.8946 11.2929,17.707C11.1054,17.5195 11,17.2652 11,17C11,16.7348 11.1054,16.4805 11.2929,16.293C11.4804,16.1054 11.7348,16 12,16C12.7956,16 13.5587,15.6837 14.1213,15.1211C14.6839,14.5585 15,13.7956 15,13C15,12.7348 15.1054,12.4805 15.2929,12.293C15.4804,12.1054 15.7348,12 16,12C16.2652,12 16.5196,12.1054 16.7071,12.293C16.8946,12.4805 17,12.7348 17,13C16.9984,14.3256 16.4711,15.5964 15.5338,16.5337C14.5964,17.471 13.3256,17.9984 12,18Z" + android:fillColor="#FF000000" /> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_stop_bubble.xml b/packages/SystemUI/res/drawable/ic_stop_bubble.xml new file mode 100644 index 000000000000..11bc741a4f17 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_stop_bubble.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M21.98,18.32l-3.3,-3.3C20.47,15.11 21.89,16.53 21.98,18.32zM8.66,4.74C8.75,4.7 8.84,4.65 8.93,4.61c0.11,-0.05 0.23,-0.09 0.35,-0.13c0.14,-0.05 0.27,-0.1 0.41,-0.14C9.77,4.32 9.85,4.3 9.92,4.28c0.18,-0.05 0.36,-0.1 0.54,-0.13c0.03,-0.01 0.07,-0.01 0.1,-0.01c0.95,-0.17 1.93,-0.17 2.88,0c0.03,0.01 0.07,0.01 0.1,0.01c0.18,0.04 0.36,0.08 0.54,0.13c0.08,0.02 0.16,0.04 0.23,0.06c0.14,0.04 0.27,0.09 0.41,0.14c0.12,0.04 0.23,0.08 0.35,0.13c0.09,0.04 0.18,0.09 0.27,0.13c0.15,0.07 0.3,0.14 0.45,0.22c0.05,0.03 0.09,0.06 0.14,0.08c1.26,0.72 2.31,1.77 3.03,3.03c0.03,0.05 0.06,0.09 0.08,0.14c0.08,0.15 0.15,0.3 0.22,0.45c0.04,0.09 0.09,0.18 0.13,0.27c0.05,0.11 0.09,0.23 0.13,0.35c0.05,0.13 0.1,0.27 0.14,0.41c0.02,0.08 0.04,0.16 0.06,0.24c0.05,0.18 0.1,0.36 0.13,0.54c0.01,0.03 0.01,0.07 0.02,0.1c0.16,0.91 0.17,1.84 0.02,2.75l1.97,0.33C21.94,13.1 22,12.56 22,12c0,0 0,0 0,0s0,0 0,0c0,-0.34 -0.02,-0.68 -0.05,-1.01c0,-0.04 -0.01,-0.09 -0.02,-0.13c-0.03,-0.29 -0.07,-0.58 -0.13,-0.87c0,0 0,-0.01 0,-0.01c-0.25,-1.23 -0.73,-2.39 -1.42,-3.44c-0.01,-0.01 -0.02,-0.03 -0.03,-0.04c-0.15,-0.23 -0.32,-0.46 -0.5,-0.68c-0.03,-0.04 -0.06,-0.09 -0.1,-0.13c-0.21,-0.26 -0.44,-0.51 -0.68,-0.75c-0.45,-0.45 -0.94,-0.84 -1.45,-1.19c-0.01,-0.01 -0.03,-0.02 -0.04,-0.03c-0.2,-0.14 -0.41,-0.26 -0.62,-0.38c-0.08,-0.04 -0.15,-0.09 -0.23,-0.14c-0.17,-0.09 -0.34,-0.17 -0.51,-0.25c-0.13,-0.06 -0.26,-0.13 -0.4,-0.18c-0.12,-0.05 -0.25,-0.09 -0.37,-0.14c-0.19,-0.07 -0.38,-0.14 -0.57,-0.2c-0.07,-0.02 -0.14,-0.04 -0.22,-0.06c-0.25,-0.07 -0.5,-0.13 -0.75,-0.18c0,0 0,0 0,0C13.29,2.07 12.65,2 12,2c-0.93,0 -1.82,0.14 -2.67,0.37C9.26,2.39 9.19,2.41 9.12,2.43c-0.2,0.06 -0.39,0.13 -0.58,0.2C8.42,2.67 8.3,2.71 8.18,2.76c-0.14,0.06 -0.27,0.12 -0.4,0.19C7.61,3.03 7.44,3.1 7.27,3.19C7.19,3.24 7.12,3.29 7.04,3.33C7.03,3.34 7.02,3.34 7.01,3.35l1.48,1.48C8.55,4.8 8.6,4.77 8.66,4.74zM2.71,1.29L1.29,2.71l2.97,2.97C2.85,7.4 2,9.6 2,12c0,2.76 1.12,5.26 2.93,7.07l0,0c0.45,0.45 0.94,0.85 1.45,1.2c0.01,0.01 0.02,0.02 0.04,0.03c0.21,0.14 0.42,0.27 0.64,0.39c0.07,0.04 0.14,0.09 0.21,0.13c0.17,0.09 0.35,0.17 0.53,0.25c0.13,0.06 0.25,0.12 0.38,0.18c0.13,0.05 0.26,0.1 0.39,0.14c0.18,0.07 0.36,0.14 0.55,0.19c0.08,0.02 0.16,0.04 0.23,0.06c0.24,0.07 0.48,0.13 0.73,0.18c0.01,0 0.01,0 0.02,0C10.72,21.93 11.35,22 12,22v-0.01c0.54,0 1.08,-0.05 1.62,-0.14l-0.35,-1.98c-1.13,0.18 -2.29,0.13 -3.4,-0.18c-0.06,-0.02 -0.11,-0.03 -0.17,-0.04c-0.16,-0.05 -0.31,-0.11 -0.46,-0.16c-0.1,-0.04 -0.2,-0.07 -0.29,-0.11c-0.11,-0.05 -0.22,-0.1 -0.32,-0.15c-0.13,-0.06 -0.27,-0.12 -0.4,-0.19c-0.06,-0.03 -0.13,-0.08 -0.19,-0.11c-0.17,-0.1 -0.33,-0.19 -0.49,-0.3c-0.01,-0.01 -0.03,-0.02 -0.04,-0.03C5.39,17.16 4,14.74 4,12c0,-1.85 0.64,-3.54 1.7,-4.89l9.73,9.73C15.16,17.33 15,17.9 15,18.5c0,1.93 1.57,3.5 3.5,3.5c0.6,0 1.17,-0.16 1.66,-0.43l1.13,1.13l1.41,-1.41L2.71,1.29z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/rounded_user_switcher_bg.xml b/packages/SystemUI/res/drawable/kg_user_switcher_rounded_bg.xml index e3d010ee7674..13c5fe08f43a 100644 --- a/packages/SystemUI/res/drawable/rounded_user_switcher_bg.xml +++ b/packages/SystemUI/res/drawable/kg_user_switcher_rounded_bg.xml @@ -16,17 +16,17 @@ --> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?android:attr/colorControlHighlight"> - <item> - <shape> - <solid android:color="@color/qs_user_detail_avatar_frame" /> + <item> + <shape> + <solid android:color="@color/kg_user_switcher_rounded_background_color" /> - <padding - android:left="1dp" - android:right="1dp" - android:bottom="1dp" - android:top="1dp" /> + <padding + android:left="8dp" + android:right="8dp" + android:bottom="8dp" + android:top="8dp" /> - <corners android:radius="48dp" /> - </shape> - </item> + <corners android:radius="48dp" /> + </shape> + </item> </ripple> diff --git a/packages/SystemUI/res/drawable/qs_bg_avatar.xml b/packages/SystemUI/res/drawable/qs_bg_avatar.xml new file mode 100644 index 000000000000..41176a8efc5e --- /dev/null +++ b/packages/SystemUI/res/drawable/qs_bg_avatar.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportWidth="100" + android:viewportHeight="100"> + + <path + android:fillColor="@color/qs_user_switcher_avatar_background" + android:pathData="M50,50m-50,0a50,50 0,1 1,100 0a50,50 0,1 1,-100 0"/> + +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/rounded_bg_top.xml b/packages/SystemUI/res/drawable/rounded_bg_top.xml new file mode 100644 index 000000000000..988ab5874b07 --- /dev/null +++ b/packages/SystemUI/res/drawable/rounded_bg_top.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?android:attr/colorPrimaryDark" /> + <corners + android:topLeftRadius="?android:attr/dialogCornerRadius" + android:topRightRadius="?android:attr/dialogCornerRadius" /> +</shape> diff --git a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml index 1f38b1ea1da5..4413b1ef3cd3 100644 --- a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml +++ b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml @@ -20,24 +20,24 @@ <com.android.systemui.statusbar.policy.KeyguardUserDetailItemView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:sysui="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" - android:layout_marginEnd="8dp" + android:layout_marginEnd="32dp" android:gravity="end|center_vertical" android:clickable="true" - android:background="@drawable/rounded_user_switcher_bg" - sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" - sysui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.Activated"> + android:background="@drawable/kg_user_switcher_rounded_bg" + sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"> <TextView android:id="@+id/user_name" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="13dp" + android:layout_marginStart="25dp" + android:layout_marginEnd="12dp" android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" /> <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture" - android:layout_width="@dimen/framed_avatar_size" - android:layout_height="@dimen/framed_avatar_size" + android:layout_width="@dimen/kg_framed_avatar_size" + android:layout_height="@dimen/kg_framed_avatar_size" android:contentDescription="@null" sysui:badgeDiameter="18dp" sysui:badgeMargin="1dp" /> diff --git a/packages/SystemUI/res/layout/app_ops_info.xml b/packages/SystemUI/res/layout/app_ops_info.xml index bfa252c5a14b..8342a2a4a560 100644 --- a/packages/SystemUI/res/layout/app_ops_info.xml +++ b/packages/SystemUI/res/layout/app_ops_info.xml @@ -19,8 +19,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:focusable="true" android:id="@+id/app_ops_info" - android:clickable="true" android:clipChildren="false" android:clipToPadding="false" android:orientation="vertical" diff --git a/packages/SystemUI/res/layout/bubble_dismiss_target.xml b/packages/SystemUI/res/layout/bubble_dismiss_target.xml index ca085b69c35d..f5cd727a6d03 100644 --- a/packages/SystemUI/res/layout/bubble_dismiss_target.xml +++ b/packages/SystemUI/res/layout/bubble_dismiss_target.xml @@ -17,7 +17,7 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" - android:layout_height="@dimen/pip_dismiss_gradient_height" + android:layout_height="@dimen/floating_dismiss_gradient_height" android:layout_gravity="bottom|center_horizontal"> <FrameLayout diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml index db81e2348cd8..6a8621398191 100644 --- a/packages/SystemUI/res/layout/controls_base_item.xml +++ b/packages/SystemUI/res/layout/controls_base_item.xml @@ -24,6 +24,7 @@ android:clickable="false" android:focusable="true" android:screenReaderFocusable="true" + android:stateListAnimator="@anim/control_state_list_animator" android:layout_marginLeft="@dimen/control_base_item_margin" android:layout_marginRight="@dimen/control_base_item_margin" android:background="@drawable/control_background"> @@ -45,7 +46,8 @@ android:textAppearance="@style/TextAppearance.Control.Status" android:paddingTop="@dimen/control_padding_adjustment" android:paddingStart="@dimen/control_status_padding" - android:clickable="true" + android:screenReaderFocusable="false" + android:clickable="false" android:focusable="false" android:singleLine="true" android:ellipsize="marquee" diff --git a/packages/SystemUI/res/layout/controls_detail_dialog.xml b/packages/SystemUI/res/layout/controls_detail_dialog.xml index f2de45a57ff6..34b603f4bc3d 100644 --- a/packages/SystemUI/res/layout/controls_detail_dialog.xml +++ b/packages/SystemUI/res/layout/controls_detail_dialog.xml @@ -15,9 +15,76 @@ limitations under the License. --> -<FrameLayout +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/controls_activity_view" + android:id="@+id/control_detail_root" android:layout_width="match_parent" - android:layout_height="match_parent" /> + android:layout_height="match_parent" + android:layout_marginTop="@dimen/controls_activity_view_top_offset" + android:orientation="vertical"> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginBottom="10dp"> + <ImageView + android:id="@+id/control_detail_close" + android:contentDescription="@string/accessibility_desc_close" + android:src="@drawable/ic_close" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:tint="@color/control_primary_text" + android:layout_width="48dp" + android:layout_height="48dp" + android:padding="12dp" /> + <Space + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="1dp" /> + <ImageView + android:id="@+id/control_detail_open_in_app" + android:src="@drawable/ic_open_in_new" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:tint="@color/control_primary_text" + android:layout_width="48dp" + android:layout_height="48dp" + android:padding="12dp" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="@dimen/controls_activity_view_top_padding" + android:paddingLeft="@dimen/controls_activity_view_side_padding" + android:paddingRight="@dimen/controls_activity_view_side_padding" + android:background="@drawable/rounded_bg_top" + android:orientation="vertical"> + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.ControlDialog" + android:clickable="false" + android:focusable="false" + android:maxLines="1" + android:ellipsize="end" /> + <TextView + android:id="@+id/subtitle" + android:layout_marginTop="6dp" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.ControlDialog" + android:clickable="false" + android:focusable="false" + android:maxLines="1" + android:ellipsize="end" /> + + <FrameLayout + android:id="@+id/controls_activity_view" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginTop="10dp" + android:layout_weight="1" /> + + </LinearLayout> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/controls_dialog_pin.xml b/packages/SystemUI/res/layout/controls_dialog_pin.xml index b77d6fa6a956..afef5eaa3979 100644 --- a/packages/SystemUI/res/layout/controls_dialog_pin.xml +++ b/packages/SystemUI/res/layout/controls_dialog_pin.xml @@ -25,6 +25,7 @@ android:id="@+id/controls_pin_input" android:layout_width="match_parent" android:layout_height="wrap_content" + android:minHeight="48dp" android:hint="@string/controls_pin_instructions" android:inputType="numberPassword" /> <CheckBox @@ -32,5 +33,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" + android:minHeight="48dp" android:text="@string/controls_pin_use_alphanumeric" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/controls_horizontal_divider_with_empty.xml b/packages/SystemUI/res/layout/controls_horizontal_divider_with_empty.xml new file mode 100644 index 000000000000..90b3398e3de2 --- /dev/null +++ b/packages/SystemUI/res/layout/controls_horizontal_divider_with_empty.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" +> + + <View + android:layout_width="match_parent" + android:layout_height="@dimen/controls_management_list_margin" + /> + + <FrameLayout + android:id="@+id/frame" + android:layout_width="match_parent" + android:layout_height="@dimen/control_height" + android:visibility="gone" + > + </FrameLayout> + <View + android:id="@+id/divider" + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginBottom="10dp" + android:layout_marginStart="40dp" + android:layout_marginEnd="40dp" + android:background="#4dffffff" /> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml index 9d5eb63ba795..ae57563cfb09 100644 --- a/packages/SystemUI/res/layout/controls_management.xml +++ b/packages/SystemUI/res/layout/controls_management.xml @@ -29,6 +29,8 @@ android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:focusable="false" + android:clickable="false" android:gravity="center_vertical"> <FrameLayout diff --git a/packages/SystemUI/res/layout/controls_management_apps.xml b/packages/SystemUI/res/layout/controls_management_apps.xml index 42d73f3cc9ce..94df9d8f4775 100644 --- a/packages/SystemUI/res/layout/controls_management_apps.xml +++ b/packages/SystemUI/res/layout/controls_management_apps.xml @@ -14,18 +14,11 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<androidx.core.widget.NestedScrollView +<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/list" android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" - android:orientation="vertical" - android:layout_marginTop="@dimen/controls_management_list_margin"> + android:layout_height="match_parent" + android:layout_marginTop="@dimen/controls_management_list_margin" +/> - <androidx.recyclerview.widget.RecyclerView - android:id="@+id/list" - android:layout_width="match_parent" - android:layout_height="match_parent" - /> - -</androidx.core.widget.NestedScrollView> diff --git a/packages/SystemUI/res/layout/controls_management_editing.xml b/packages/SystemUI/res/layout/controls_management_editing.xml new file mode 100644 index 000000000000..8a14ec3666b2 --- /dev/null +++ b/packages/SystemUI/res/layout/controls_management_editing.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<androidx.recyclerview.widget.RecyclerView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clipChildren="false" + android:clipToPadding="false" + android:paddingTop="@dimen/controls_management_list_margin" +/> + diff --git a/packages/SystemUI/res/layout/controls_spinner_item.xml b/packages/SystemUI/res/layout/controls_spinner_item.xml index 00654c832525..45540f102de1 100644 --- a/packages/SystemUI/res/layout/controls_spinner_item.xml +++ b/packages/SystemUI/res/layout/controls_spinner_item.xml @@ -30,6 +30,7 @@ android:layout_gravity="center" android:layout_width="@dimen/controls_header_app_icon_size" android:layout_height="@dimen/controls_header_app_icon_size" + android:contentDescription="@null" android:layout_marginEnd="10dp" /> <TextView diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml index 91beeb88d87f..b32320956e26 100644 --- a/packages/SystemUI/res/layout/controls_with_favorites.xml +++ b/packages/SystemUI/res/layout/controls_with_favorites.xml @@ -34,6 +34,7 @@ android:orientation="horizontal" android:layout_width="0dp" android:layout_weight="1" + android:minHeight="48dp" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center"> @@ -43,6 +44,7 @@ android:layout_gravity="center" android:layout_width="@dimen/controls_header_app_icon_size" android:layout_height="@dimen/controls_header_app_icon_size" + android:contentDescription="@null" android:layout_marginEnd="10dp" /> <TextView @@ -72,6 +74,6 @@ android:layout_height="wrap_content" android:orientation="vertical" android:paddingTop="30dp" - android:layout_marginLeft="@dimen/controls_list_side_margin" - android:layout_marginRight="@dimen/controls_list_side_margin" /> + android:layout_marginLeft="@dimen/global_actions_side_margin" + android:layout_marginRight="@dimen/global_actions_side_margin" /> </merge> diff --git a/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml index 50aa212c94a6..477ec6a1c72c 100644 --- a/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml +++ b/packages/SystemUI/res/layout/global_actions_grid_item_v2.xml @@ -18,16 +18,18 @@ work around this for now with LinearLayouts. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" + android:layout_width="0dp" + android:layout_weight="1" android:layout_height="wrap_content" android:gravity="center" android:paddingTop="@dimen/global_actions_grid_item_vertical_margin" android:paddingBottom="@dimen/global_actions_grid_item_vertical_margin" android:paddingLeft="@dimen/global_actions_grid_item_side_margin" android:paddingRight="@dimen/global_actions_grid_item_side_margin" - android:layout_marginRight="3dp" - android:layout_marginLeft="3dp" - android:background="@drawable/rounded_bg_full"> + android:layout_marginRight="@dimen/control_base_item_margin" + android:layout_marginLeft="@dimen/control_base_item_margin" + android:stateListAnimator="@anim/control_state_list_animator" + android:background="@drawable/control_background"> <LinearLayout android:layout_width="@dimen/global_actions_grid_item_width" android:layout_height="@dimen/global_actions_grid_item_height" @@ -42,7 +44,7 @@ android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin" android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin" android:scaleType="centerInside" - android:tint="@color/global_actions_text" /> + android:tint="@color/control_default_foreground" /> <TextView android:id="@*android:id/message" @@ -53,7 +55,7 @@ android:singleLine="true" android:gravity="center" android:textSize="12dp" - android:textColor="@color/global_actions_text" + android:textColor="@color/control_default_foreground" android:textAppearance="?android:attr/textAppearanceSmall" /> <TextView @@ -62,7 +64,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" - android:textColor="@color/global_actions_text" + android:textColor="@color/control_default_foreground" android:textAppearance="?android:attr/textAppearanceSmall" /> </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml index 620e2e6b509c..dba003aa82a9 100644 --- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml +++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml @@ -12,34 +12,46 @@ android:layout_height="wrap_content" android:orientation="horizontal" android:theme="@style/qs_theme" - android:gravity="top | center_horizontal" android:clipChildren="false" android:clipToPadding="false" android:layout_marginTop="@dimen/global_actions_top_margin" + android:layout_marginLeft="@dimen/global_actions_side_margin" + android:layout_marginRight="@dimen/global_actions_side_margin" > <LinearLayout android:id="@android:id/list" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginLeft="@dimen/global_actions_grid_side_margin" - android:layout_marginRight="@dimen/global_actions_grid_side_margin" android:paddingLeft="@dimen/global_actions_grid_horizontal_padding" android:paddingRight="@dimen/global_actions_grid_horizontal_padding" android:paddingTop="@dimen/global_actions_grid_vertical_padding" android:paddingBottom="@dimen/global_actions_grid_vertical_padding" android:orientation="horizontal" - android:gravity="left" + android:gravity="left | center_vertical" android:translationZ="@dimen/global_actions_translate" - /> + > + <RelativeLayout + android:id="@+id/global_actions_overflow_button" + android:layout_width="48dp" + android:layout_height="48dp" + > + <ImageView + android:src="@drawable/ic_more_vert" + android:layout_centerInParent="true" + android:layout_width="24dp" + android:layout_height="24dp" + android:tint="@color/control_more_vert" + /> + </RelativeLayout> + </LinearLayout> </com.android.systemui.globalactions.GlobalActionsFlatLayout> <com.android.systemui.globalactions.MinHeightScrollView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset" - android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset" - android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset" + android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset" + android:orientation="vertical" > <LinearLayout android:id="@+id/global_actions_grid_root" diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml index b1e51659817e..626951c8c0b7 100644 --- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml +++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml @@ -36,8 +36,8 @@ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" /> <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture" - android:layout_width="@dimen/framed_avatar_size" - android:layout_height="@dimen/framed_avatar_size" + android:layout_width="@dimen/kg_framed_avatar_size" + android:layout_height="@dimen/kg_framed_avatar_size" android:contentDescription="@null" android:backgroundTint="@color/qs_user_detail_avatar_tint" android:backgroundTintMode="src_atop" @@ -45,5 +45,5 @@ sysui:framePadding="2.5dp" sysui:badgeDiameter="18dp" sysui:badgeMargin="1dp" - sysui:frameColor="@color/qs_user_detail_avatar_frame" /> + sysui:frameColor="@color/kg_user_switcher_rounded_background_color" /> </com.android.systemui.statusbar.policy.KeyguardUserDetailItemView> diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml index 87cb5c7f746c..9dc502efab43 100644 --- a/packages/SystemUI/res/layout/notification_conversation_info.xml +++ b/packages/SystemUI/res/layout/notification_conversation_info.xml @@ -20,7 +20,7 @@ android:id="@+id/notification_guts" android:layout_width="match_parent" android:layout_height="wrap_content" - android:clickable="true" + android:focusable="true" android:clipChildren="false" android:clipToPadding="true" android:orientation="vertical" diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml index dc94697f32fa..5399f57c322f 100644 --- a/packages/SystemUI/res/layout/notification_guts.xml +++ b/packages/SystemUI/res/layout/notification_guts.xml @@ -19,8 +19,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:focusable="true" android:id="@+id/notification_guts" android:visibility="gone" - android:clickable="true" android:gravity="top|start" android:theme="@*android:style/Theme.DeviceDefault.Light"/> diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index 73b711d275f3..5b363820e4e2 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -20,7 +20,7 @@ android:id="@+id/notification_guts" android:layout_width="match_parent" android:layout_height="wrap_content" - android:clickable="true" + android:focusable="true" android:clipChildren="false" android:clipToPadding="true" android:orientation="vertical" diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml index c350ed22b765..253bc328c5b8 100644 --- a/packages/SystemUI/res/layout/notification_snooze.xml +++ b/packages/SystemUI/res/layout/notification_snooze.xml @@ -20,7 +20,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:clickable="true" android:background="@color/notification_material_background_color" android:theme="@style/Theme.SystemUI"> @@ -55,6 +54,8 @@ android:layout_marginEnd="@dimen/notification_guts_button_side_margin" android:layout_alignParentEnd="true" android:layout_centerVertical="true" + android:minWidth="@dimen/min_clickable_item_size" + android:minHeight="@dimen/min_clickable_item_size" android:text="@string/snooze_undo" style="@style/TextAppearance.NotificationInfo.Button" /> </RelativeLayout> diff --git a/packages/SystemUI/res/layout/pip_dismiss_view.xml b/packages/SystemUI/res/layout/pip_dismiss_view.xml deleted file mode 100644 index 2cc4b220fe2b..000000000000 --- a/packages/SystemUI/res/layout/pip_dismiss_view.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2016 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="@dimen/pip_dismiss_gradient_height" - android:alpha="0"> - - <TextView - android:id="@+id/pip_dismiss_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="bottom|center_horizontal" - android:text="@string/pip_phone_dismiss_hint" - android:textColor="#FFFFFFFF" - android:textSize="14sp" - android:shadowColor="@android:color/black" - android:shadowDx="-2" - android:shadowDy="2" - android:shadowRadius="0.01" /> - -</FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/qs_media_panel.xml b/packages/SystemUI/res/layout/qs_media_panel.xml index fc3bf941b27a..e5ac5f89cd25 100644 --- a/packages/SystemUI/res/layout/qs_media_panel.xml +++ b/packages/SystemUI/res/layout/qs_media_panel.xml @@ -23,7 +23,8 @@ android:layout_height="match_parent" android:orientation="vertical" android:gravity="center_horizontal|fill_vertical" - android:padding="16dp" + android:paddingTop="@dimen/qs_media_panel_outer_padding" + android:paddingBottom="@dimen/qs_media_panel_outer_padding" android:background="@drawable/qs_media_background" > @@ -42,7 +43,9 @@ android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="16dp" + android:layout_marginBottom="@dimen/qs_media_panel_outer_padding" + android:paddingStart="@dimen/qs_media_panel_outer_padding" + android:paddingEnd="16dp" > <ImageView @@ -139,6 +142,7 @@ <!-- Seek Bar --> <SeekBar android:id="@+id/media_progress_bar" + style="@android:style/Widget.ProgressBar.Horizontal" android:clickable="true" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -154,6 +158,9 @@ android:id="@+id/notification_media_progress_time" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingStart="@dimen/qs_media_panel_outer_padding" + android:paddingEnd="@dimen/qs_media_panel_outer_padding" + android:layout_marginBottom="10dp" android:layout_gravity="center" > <!-- width is set to "match_parent" to avoid extra layout calls --> @@ -184,6 +191,8 @@ android:layoutDirection="ltr" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingStart="@dimen/qs_media_panel_outer_padding" + android:paddingEnd="@dimen/qs_media_panel_outer_padding" android:gravity="center" > <ImageButton diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml index 5c03e3099522..0608685c3440 100644 --- a/packages/SystemUI/res/layout/qs_user_detail_item.xml +++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml @@ -30,21 +30,20 @@ android:clipToPadding="false" android:focusable="true" android:background="@drawable/ripple_drawable" - systemui:regularTextAppearance="@style/TextAppearance.QS.UserSwitcher" - systemui:activatedTextAppearance="@style/TextAppearance.QS.UserSwitcher.Activated"> + systemui:regularTextAppearance="@style/TextAppearance.QS.UserSwitcher"> <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture" - android:layout_width="@dimen/framed_avatar_size" - android:layout_height="@dimen/framed_avatar_size" + android:layout_width="@dimen/qs_framed_avatar_size" + android:layout_height="@dimen/qs_framed_avatar_size" android:layout_marginBottom="7dp" android:backgroundTint="@color/qs_user_detail_avatar_tint" android:backgroundTintMode="src_atop" - systemui:frameWidth="2dp" - systemui:framePadding="2.5dp" + systemui:frameWidth="6dp" systemui:badgeDiameter="18dp" systemui:badgeMargin="1dp" - systemui:frameColor="@color/qs_user_detail_avatar_frame"/> + systemui:framePadding="-1dp" + systemui:frameColor="@color/qs_user_avatar_frame"/> <LinearLayout android:layout_width="wrap_content" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 29e4361209f8..efa28792271a 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Vergrotingoorleggervenster"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingvenster"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Vergrotingvensterkontroles"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Kitskontroles"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Toestelkontroles"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Voeg kontroles vir jou gekoppelde toestelle by"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Stel kitskontroles op"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Stel toestelkontroles op"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Hou die aan/af-skakelaar in om na jou kontroles toe te gaan"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Kies program om kontroles by te voeg"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kontroles"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Kies kontroles om toegang vanaf die aan/af-kieslys te kry"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Hou en sleep \'n kontrole om dit te beweeg"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Die lys met alle kontroles kon nie gelaai word nie."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Ander"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Voeg by kitskontroles"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Voeg by toestelkontroles"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Voeg by gunstelinge"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> het voorgestel dat hierdie kontrole by jou gunstelinge gevoeg word."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontroles opgedateer"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 58809e60eb85..96934b17eeb0 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"ፍቀድ"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"የዩኤስቢ እርማት አይፈቀድም"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"አሁን ወደዚህ መሣሪያ የገባው ተጠቃሚ የዩኤስቢ እርማትን ማብራት አይችልም። ይህን ባህሪ ለመጠቀም ወደ ዋና ተጠቃሚ ይቀይሩ።"</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"በዚህ አውታረ መረብ ላይ ገመድ-አልባ ማረም ይፈቀድ?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"በዚህ አውታረ መረብ ላይ ገመድ-አልባ debugging ይፈቀድ?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"የአውታረ መረብ ስም (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nየWi‑Fi አድራሻ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"ሁልጊዜ በዚህ አውታረ መረብ ላይ ፍቀድ"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"ፍቀድ"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"ገመድ-አልባ ማረም አይፈቀድም"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"በአሁኑ ጊዜ በመለያ ወደዚህ መሣሪያ የገባው ተጠቃሚ የገመድ-አልባ ማረምን ማብራት አይችልም። ይህን ባህሪ ለመጠቀም ወደ ዋና ተጠቃሚ ይቀይሩ።"</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"ገመድ-አልባ debugging አይፈቀድም"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"በአሁኑ ጊዜ በመለያ ወደዚህ መሣሪያ የገባው ተጠቃሚ የገመድ-አልባ debuggingን ማብራት አይችልም። ይህን ባህሪ ለመጠቀም ወደ ዋና ተጠቃሚ ይቀይሩ።"</string> <string name="usb_contaminant_title" msgid="894052515034594113">"የዩኤስቢ ወደብ ተሰናክሏል"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"መሣሪያዎን ከፈሳሽ ወይም ፍርስራሽ ለመጠበቅ ሲባል የዩኤስቢ ወደቡ ተሰናክሏል፣ እና ማናቸውም ተቀጥላዎችን አያገኝም።\n\nየዩኤስቢ ወደቡን እንደገና መጠቀም ችግር በማይኖረው ጊዜ ማሳወቂያ ይደርሰዎታል።"</string> <string name="usb_port_enabled" msgid="531823867664717018">"ኃይል መሙያዎችን እና ተጨማሪ መሣሪያዎችን ፈልጎ ለማግኘት የነቃ የዩኤስቢ ወደብ"</string> @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ቅጽበታዊ ገጽ እይታዎችን ማንሳት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ቅጽበታዊ ገጽ እይታን አሰናብት"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"ቅጽበታዊ ገጽ እይታን ክፈት"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"ማያ መቅረጫ"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"የማያ መቅጃ"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"ለአንድ የማያ ገጽ ቀረጻ ክፍለ-ጊዜ በመካሄድ ያለ ማሳወቂያ"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"መቅረጽ ይጀመር?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"እየቀረጹ ሳለ የAndroid ስርዓት በማያ ገጽዎ ላይ የሚታይ ወይም በመሣሪያዎ ላይ የሚጫወት ማንኛውም ሚስጥራዊነት ያለው መረጃን መያዝ ይችላል። ይህ የይለፍ ቃላትን፣ የክፍያ መረጃን፣ ፎቶዎችን፣ መልዕክቶችን እና ኦዲዮን ያካትታል።"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"የማጉያ ንብርብር መስኮት"</string> <string name="magnification_window_title" msgid="4863914360847258333">"የማጉያ መስኮት"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"የማጉያ መስኮት መቆጣጠሪያዎች"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"ፈጣን መቆጣጠሪያዎች"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"የመሣሪያ መቆጣጠሪያዎች"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"ለእርስዎ የተገናኙ መሣሪያዎች መቆጣጠሪያዎችን ያክሉ"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"ፈጣን መቆጣጠሪያዎችን ያቀናብሩ"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"የመሣሪያ መቆጣጠሪያዎችን ያቀናብሩ"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"የእርስዎን መቆጣጠሪያዎች ለመድረስ የኃይል አዝራሩን ይያዙ"</string> <string name="controls_providers_title" msgid="6879775889857085056">"መቆጣጠሪያዎችን ለማከል መተግበሪያ ይምረጡ"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"መቆጣጠሪያዎች"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"ከኃይል ምናሌ ላይ ለመድረስ መቆጣጠሪያዎችን ይምረጡ"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"ለማንቀሳቀስ መቆጣጠሪያውን ይያዙት እና ይጎትቱት"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"የሁሉም መቆጣጠሪያዎች ዝርዝር ሊጫን አልተቻለም።"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ሌላ"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"ወደ ፈጣን መቆጣጠሪያዎች ያክሉ"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"ወደ የመሣሪያ መቆጣጠሪያዎች ያክሉ"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"ወደ ተወዳጆች አክል"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ይህን ቁጥጥር ወደ ተወዳጆችዎ እንዲታከል ሐሳብ ጠቁሟል።"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"መቆጣጠሪያዎች ተዘምነዋል"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index ca1af6765edf..de8a07b0382c 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -34,7 +34,7 @@ <string name="invalid_charger_text" msgid="2339310107232691577">"استخدم الشاحن المرفق بجهازك."</string> <string name="battery_low_why" msgid="2056750982959359863">"الإعدادات"</string> <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"هل تريد تفعيل ميزة توفير شحن البطارية؟"</string> - <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"لمحة حول ميزة \"توفير شحن البطارية\""</string> + <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"لمحة عن ميزة \"توفير شحن البطارية\""</string> <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"تفعيل"</string> <string name="battery_saver_start_action" msgid="4553256017945469937">"هل تريد تفعيل ميزة توفير شحن البطارية؟"</string> <string name="status_bar_settings_settings_button" msgid="534331565185171556">"الإعدادات"</string> @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"سماح"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"لا يُسمح بتصحيح أخطاء USB"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"لا يمكن للمستخدم الذي يسجّل دخوله حاليًا إلى هذا الجهاز تفعيل تصحيح الأخطاء USB. لاستخدام هذه الميزة، يمكنك التبديل إلى المستخدم الأساسي."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"هل تريد السماح باستخدام ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\" على هذه الشبكة؟"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"هل تريد السماح باستخدام ميزة \"تصحيح الأخطاء اللاسلكي\" على هذه الشبكة؟"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"اسم الشبكة (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nعنوان شبكة Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"السماح باستخدام هذه الميزة على هذه الشبكة دائمًا"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"سماح"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"غير مسموح باستخدام ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\""</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"لا يمكن للمستخدم المسجِّل دخوله حاليًا على هذا الجهاز تفعيل ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\". لاستخدام هذه الميزة، يمكنك التبديل إلى المستخدم الأساسي."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"غير مسموح باستخدام ميزة \"تصحيح الأخطاء اللاسلكي\""</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"لا يمكن للمستخدم المسجِّل دخوله حاليًا على هذا الجهاز تفعيل ميزة \"تصحيح الأخطاء اللاسلكي\". لاستخدام هذه الميزة، يمكنك التبديل إلى المستخدم الأساسي."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"تمّ إيقاف منفذ USB"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"لحماية جهازك من السوائل أو الشوائب، سيتمّ إيقاف منفذ USB ولن يتم رصد أيّ ملحقات.\n\nوسيتمّ إعلامك عندما يُسمح باستخدام منفذ USB مرة أخرى."</string> <string name="usb_port_enabled" msgid="531823867664717018">"تم تفعيل منفذ USB لاكتشاف أجهزة الشحن والملحقات."</string> @@ -257,10 +257,10 @@ <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"تم تجاهل الإشعار."</string> <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"مركز الإشعارات."</string> <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"الإعدادات السريعة."</string> - <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"شاشة التأمين."</string> + <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"شاشة القفل."</string> <string name="accessibility_desc_settings" msgid="6728577365389151969">"الإعدادات"</string> <string name="accessibility_desc_recent_apps" msgid="1748675199348914194">"النظرة عامة."</string> - <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"شاشة تأمين بيانات العمل"</string> + <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"شاشة قفل بيانات العمل"</string> <string name="accessibility_desc_close" msgid="8293708213442107755">"إغلاق"</string> <string name="accessibility_quick_settings_wifi" msgid="167707325133803052">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string> <string name="accessibility_quick_settings_wifi_changed_off" msgid="2230487165558877262">"تم إيقاف Wifi."</string> @@ -335,8 +335,8 @@ <string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"إعدادات الإشعارات"</string> <string name="status_bar_notification_app_settings_title" msgid="5050006438806013903">"إعدادات <xliff:g id="APP_NAME">%s</xliff:g>"</string> <string name="accessibility_rotation_lock_off" msgid="3880436123632448930">"سيتم تدوير الشاشة تلقائيًا."</string> - <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"تم تأمين الشاشة في الاتجاه الأفقي."</string> - <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"تم تأمين الشاشة في الاتجاه العمودي."</string> + <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"تم قفل الشاشة في الاتجاه الأفقي."</string> + <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"تم قفل الشاشة في الاتجاه العمودي."</string> <string name="accessibility_rotation_lock_off_changed" msgid="5772498370935088261">"سيتم الآن تدوير الشاشة تلقائيًا."</string> <string name="accessibility_rotation_lock_on_landscape_changed" msgid="5785739044300729592">"تم قفل الشاشة الآن في الاتجاه الأفقي."</string> <string name="accessibility_rotation_lock_on_portrait_changed" msgid="5580170829728987989">"تم قفل الشاشة الآن في الاتجاه الرأسي."</string> @@ -693,7 +693,7 @@ <string name="tuner_full_importance_settings" msgid="1388025816553459059">"عناصر التحكم في إشعارات التشغيل"</string> <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"تشغيل"</string> <string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"إيقاف"</string> - <string name="power_notification_controls_description" msgid="1334963837572708952">"باستخدام عناصر التحكم في إشعار التشغيل، يمكنك تعيين مستوى الأهمية من 0 إلى 5 لإشعارات التطبيق. \n\n"<b>"المستوى 5"</b>" \n- العرض أعلى قائمة الإشعارات \n- يسمح بمقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 4"</b>" \n- منع مقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 3"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n\n"<b>"المستوى 2"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات واهتزاز \n\n"<b>"المستوى 1"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات أو اهتزاز أبدًا \n- الإخفاء من شاشة التأمين وشريط الحالة \n- العرض أسفل قائمة الإشعارات \n\n"<b>"المستوى 0"</b>" \n- حظر جميع الإشعارات من التطبيق"</string> + <string name="power_notification_controls_description" msgid="1334963837572708952">"باستخدام عناصر التحكم في إشعار التشغيل، يمكنك تعيين مستوى الأهمية من 0 إلى 5 لإشعارات التطبيق. \n\n"<b>"المستوى 5"</b>" \n- العرض أعلى قائمة الإشعارات \n- يسمح بمقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 4"</b>" \n- منع مقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 3"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n\n"<b>"المستوى 2"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات واهتزاز \n\n"<b>"المستوى 1"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات أو اهتزاز أبدًا \n- الإخفاء من شاشة القفل وشريط الحالة \n- العرض أسفل قائمة الإشعارات \n\n"<b>"المستوى 0"</b>" \n- حظر جميع الإشعارات من التطبيق"</string> <string name="notification_header_default_channel" msgid="225454696914642444">"الإشعارات"</string> <string name="notification_channel_disabled" msgid="928065923928416337">"لن تتلقى هذه الإشعارات بعد الآن."</string> <string name="notification_channel_minimized" msgid="6892672757877552959">"سيتم تصغير هذه الإشعارات."</string> @@ -720,12 +720,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"يساعدك هذا الإشعار على التركيز بدون صوت أو اهتزاز."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"يلفت هذا الإشعار انتباهك باستخدام الصوت والاهتزاز."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"يلفِت هذا الإشعار انتباهك لهذا المحتوى باستخدام اختصار عائم."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"تظهر كفقاعة في أعلى قسم المحادثات"</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"تظهر كل المحادثات من تطبيق <xliff:g id="APP_NAME_0">%1$s</xliff:g> كفقاعات تلقائيًا. يمكنك إدارة هذا الإعداد في <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"تظهر كفقاعة محادثة في أعلى قسم المحادثات"</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"تظهر كل المحادثات من تطبيق <xliff:g id="APP_NAME_0">%1$s</xliff:g> كفقاعات محادثات تلقائيًا. يمكنك إدارة هذا الإعداد في <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"الإعدادات"</string> <string name="notification_priority_title" msgid="2079708866333537093">"الأولوية"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ليس هناك فقاعات حديثة"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ستظهر هنا أحدث الفقاعات والفقاعات التي تم إغلاقها."</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ليس هناك فقاعات محادثات"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ستظهر هنا أحدث فقاعات المحادثات وفقاعات المحادثات التي تم إغلاقها."</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"يتعذّر تعديل هذه الإشعارات."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"يتعذّر ضبط مجموعة الإشعارات هذه هنا."</string> <string name="notification_delegate_header" msgid="1264510071031479920">"إشعار مستند إلى خادم وكيل"</string> @@ -753,7 +753,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"تم كتم الصوت"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"تنبيه"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"إظهار فقاعة تفسيرية"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"إزالة الفقاعات التفسيرية"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"إزالة فقاعات المحادثات"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"إضافة إلى الشاشة الرئيسية"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"عناصر التحكم في الإشعارات"</string> @@ -1003,7 +1003,7 @@ <string name="device_services" msgid="1549944177856658705">"خدمات الأجهزة"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"بلا عنوان"</string> <string name="restart_button_description" msgid="6916116576177456480">"انقر لإعادة تشغيل هذا التطبيق والانتقال إلى وضع ملء الشاشة."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"إعداد الفقاعات التفسيرية على <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"إعدادات فقاعات المحادثات على <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"إدارة"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> من <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> من <xliff:g id="APP_NAME">%2$s</xliff:g> و<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> أيضًا"</string> @@ -1013,11 +1013,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نقل إلى أسفل يمين الشاشة"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نقل إلى أسفل اليسار"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"تجاهل"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"عدم عرض المحادثة كفقاعة"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"الدردشة باستخدام الفقاعات"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"تظهر المحادثات الجديدة كرموز عائمة أو فقاعات. انقر عليها لفتحها كفقاعة أو اسحبها لتحريكها."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"التحكّم في الفقاعات في أي وقت"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"انقر على \"إدارة\" لإيقاف الفقاعات من هذا التطبيق."</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"عدم عرض المحادثة كفقاعة محادثة"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"الدردشة باستخدام فقاعات المحادثات"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"تظهر المحادثات الجديدة كرموز عائمة أو كفقاعات. انقر لفتح فقاعة المحادثة، واسحبها لتحريكها."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"التحكّم في فقاعات المحادثات في أي وقت"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"انقر على \"إدارة\" لإيقاف فقاعات المحادثات من هذا التطبيق."</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"حسنًا"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"تم تحديث التنقل داخل النظام. لإجراء التغييرات، يُرجى الانتقال إلى \"الإعدادات\"."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"الانتقال إلى \"الإعدادات\" لتعديل التنقل داخل النظام"</string> @@ -1025,9 +1025,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"نافذة تراكب التكبير"</string> <string name="magnification_window_title" msgid="4863914360847258333">"نافذة التكبير"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"عناصر التحكم في نافذة التكبير"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"عناصر التحكّم السريعة"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"عناصر التحكم في الأجهزة"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"إضافة عناصر تحكّم لأجهزتك المتصلة"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"إعداد عناصر التحكّم السريعة"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"إعداد عناصر التحكم في الأجهزة"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"اضغط مع الاستمرار على زر التشغيل للوصول إلى عناصر التحكّم"</string> <string name="controls_providers_title" msgid="6879775889857085056">"اختيار تطبيق لإضافة عناصر التحكّم"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1040,10 +1040,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"عناصر التحكّم"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"اختيار عناصر التحكّم التي تريد الوصول إليها من قائمة التشغيل"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"اضغط مع الاستمرار على عنصر تحكّم واسحبه لتحريكه."</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"تعذّر تحميل قائمة كل عناصر التحكّم."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"غير ذلك"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"إضافة إلى عناصر التحكم السريعة"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"إضافة إلى عناصر التحكم في الأجهزة"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"إضافة إلى الإعدادات المفضّلة"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"اقترح تطبيق <xliff:g id="APP">%s</xliff:g> إضافة عنصر التحكّم هذا إلى الإعدادات المفضّلة."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"تم تعديل عناصر التحكّم."</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 17dba435ffe1..f32757c2720f 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"অনুমতি দিয়ক"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"ইউএছবি ডিবাগিঙৰ অনুমতি নাই"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"এই ডিভাইচটোত বর্তমান ছাইন ইন হৈ থকা ব্যৱহাৰকাৰীজনে ইউএছবি ডিবাগিং অন কৰিব নোৱাৰে। এই সুবিধাটো ব্যৱহাৰ কৰিবলৈ হ\'লে মুখ্য ব্যৱহাৰকাৰী হিচাপে ছাইন ইন কৰক।"</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"এই নেটৱৰ্কত ৱায়াৰলেছ ডিবাগিঙৰ অনুমতি দিবনে?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"এই নেটৱৰ্কত ৱায়াৰলেচ ডি\'বাগিংৰ অনুমতি দিবনে?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"নেটৱৰ্কৰ নাম (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nৱাই-ফাইৰ ঠিকনা (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"এই নেটৱৰ্কত সদায় অনুমতি দিয়ক"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"অনুমতি দিয়ক"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"ৱায়াৰলেছ ডিবাগিঙৰ অনুমতি নাই"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"এই ডিভাইচটোত বর্তমান ছাইন ইন হৈ থকা ব্যৱহাৰকাৰীজনে ৱায়াৰলেছ ডিবাগিং অন কৰিব নোৱাৰে। এই সুবিধাটো ব্যৱহাৰ কৰিবলৈ হ’লে প্ৰাথমিক ব্যৱহাৰকাৰী হিচাপে ছাইন ইন কৰক।"</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"ৱায়াৰলেচ ডি\'বাগিংৰ অনুমতি নাই"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"এই ডিভাইচটোত বর্তমান ছাইন ইন হৈ থকা ব্যৱহাৰকাৰীজনে ৱায়াৰলেচ ডি\'বাগিং অন কৰিব নোৱাৰে। এই সুবিধাটো ব্যৱহাৰ কৰিবলৈ হ’লে প্ৰাথমিক ব্যৱহাৰকাৰী হিচাপে ছাইন ইন কৰক।"</string> <string name="usb_contaminant_title" msgid="894052515034594113">"ইউএছবি প’ৰ্ট অক্ষম কৰা হ’ল"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"আপোনাৰ ডিভাইচটো তৰল বা ধূলি-মাকতিৰ পৰা ৰক্ষা কৰিবলৈ ইউএছবি প’ৰ্টটো অক্ষম কৰি ৰখা হৈছে ফলত ই কোনো আনুষংগিক সামগ্ৰী ধৰা পেলাব নোৱাৰে।\n\nযেতিয়া ইউএছবি প’ৰ্টটো নিৰাপদভাৱে ব্যৱহাৰ কৰিব পৰা হ’ব তেতিয়া আপোনাক জনোৱা হ’ব।"</string> <string name="usb_port_enabled" msgid="531823867664717018">"চাৰ্জাৰ আৰু আনুষংগিক সামগ্ৰী চিনাক্ত কৰিবলৈ USB প’ৰ্ট সক্ষম কৰা হ’ল"</string> @@ -509,7 +509,7 @@ <string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string> <string name="notification_section_header_gentle" msgid="3044910806569985386">"নীৰৱ জাননীসমূহ"</string> <string name="notification_section_header_alerting" msgid="3168140660646863240">"সতৰ্কতামূলক জাননীসমূহ"</string> - <string name="notification_section_header_conversations" msgid="821834744538345661">"বাৰ্তালাপসমূহ"</string> + <string name="notification_section_header_conversations" msgid="821834744538345661">"বাৰ্তালাপ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"সকলো নীৰৱ জাননী মচক"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"অসুবিধা নিদিব-ই জাননী পজ কৰিছে"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"এতিয়াই আৰম্ভ কৰক"</string> @@ -712,8 +712,8 @@ <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>ৰ সকলো বাৰ্তালাপ ডিফ’ল্ট হিচাপে বাবল হয়। <xliff:g id="APP_NAME_1">%2$s</xliff:g>ত পৰিচালনা কৰক।"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ছেটিংসমূহ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"অগ্ৰাধিকাৰ"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"কোনো শেহতীয়া বাবল নাই"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"শেহতীয়া বাবলসমূহ আৰু অগ্ৰাহ্য কৰা বাবলসমূহ ইয়াত প্ৰদর্শিত হ\'ব"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"কোনো শেহতীয়া bubbles নাই"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"শেহতীয়া bubbles আৰু অগ্ৰাহ্য কৰা bubbles ইয়াত প্ৰদর্শিত হ\'ব"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"এই ধৰণৰ জাননীবোৰ ইয়াত কনফিগাৰ কৰিব পৰা নাযায়"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"প্ৰক্সি হিচাপে পঠিওৱা জাননী"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"নীৰৱ কৰি ৰখা হৈছে"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"সতৰ্কতামূলক"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"বাবল হিচাপে দেখুৱাওক"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"বাবলসমূহ আঁতৰাওক"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Bubbles আঁতৰাওক"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"গৃহ স্ক্ৰীনত যোগ কৰক"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"জাননীৰ নিয়ন্ত্ৰণসমূহ"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"ডিভাইচ সেৱা"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"কোনো শিৰোনাম নাই"</string> <string name="restart_button_description" msgid="6916116576177456480">"এপ্টো ৰিষ্টাৰ্ট কৰক আৰু পূৰ্ণ স্ক্ৰীণ ব্যৱহাৰ কৰক।"</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবলৰ ছেটিংসমূহ"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ bubblesৰ ছেটিংসমূহ"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"পৰিচালনা কৰক"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>ৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> আৰু<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>টাৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -994,10 +994,10 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"তলৰ সোঁফালে নিয়ক"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"অগ্ৰাহ্য কৰক"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"বাৰ্তালাপ বাবল নকৰিব"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"বাবলসমূহ ব্যৱহাৰ কৰি চাট কৰক"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"নতুন বার্তালাপসমূহ উপঙি থকা চিহ্নসমূহ অথবা বাবলসমূহ হিচাপে প্ৰদর্শিত হয়। বাবল খুলিবলৈ টিপক। এইটো স্থানান্তৰ কৰিবলৈ টানি নিয়ক।"</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"যিকোনো সময়তে বাবলসমূহ নিয়ন্ত্ৰণ কৰক"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"এই এপ্টোৰ পৰা বাবল অফ কৰিবলৈ পৰিচালনা কৰকত টিপক"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bubbles ব্যৱহাৰ কৰি চাট কৰক"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"নতুন বাৰ্তালাপ উপঙি থকা চিহ্নসমূহ অথবা bubbles হিচাপে প্ৰদর্শিত হয়। Bubbles খুলিবলৈ টিপক। এইটো স্থানান্তৰ কৰিবলৈ টানি নিয়ক।"</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"যিকোনো সময়তে bubbles নিয়ন্ত্ৰণ কৰক"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"এই এপ্টোৰ পৰা bubbles অফ কৰিবলৈ পৰিচালনা কৰকত টিপক"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"বুজি পালোঁ"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰা হ’ল। সলনি কৰিবলৈ ছেটিংসমূহ-লৈ যাওক।"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰিবলৈ ছেটিংসমূহ-লৈ যাওক"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"বিবৰ্ধন অ’ভাৰলে’ৰ ৱিণ্ড’"</string> <string name="magnification_window_title" msgid="4863914360847258333">"বিবৰ্ধন ৱিণ্ড’"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"বিবৰ্ধন ৱিণ্ড’ৰ নিয়ন্ত্ৰণসমূহ"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"ক্ষিপ্ৰ নিয়ন্ত্ৰণসমূহ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"আপোনাৰ সংযোজিত ডিভাইচসমূহৰ বাবে নিয়ন্ত্ৰণসমূহ যোগ কৰক"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"ক্ষিপ্ৰ নিয়ন্ত্ৰণসমূহ ছেট আপ কৰক"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ ছেট আপ কৰক"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"আপোনাৰ নিয়ন্ত্ৰণসমূহ এক্সেছ কৰিবলৈ পাৱাৰ বুটামটো হেঁচি ধৰি ৰাখক"</string> <string name="controls_providers_title" msgid="6879775889857085056">"নিয়ন্ত্ৰণসমূহ যোগ কৰিবলৈ এপ্ বাছনি কৰক"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"নিয়ন্ত্ৰণসমূহ"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"পাৱাৰ মেনুখনৰ পৰা এক্সেছ পাবলৈ নিয়ন্ত্ৰণসমূহ বাছনি কৰক"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"নিয়ন্ত্ৰণটো স্থানান্তৰ কৰিবলৈ ধৰি ৰাখি টানি নিয়ক"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"নিয়ন্ত্ৰণসমূহৰ সম্পূর্ণ সূচীখন ল’ড কৰিব পৰা নগ’ল।"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"ক্ষিপ্ৰ নিয়ন্ত্ৰণসমূহত যোগ কৰক"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহত যোগ দিয়ক"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"প্ৰিয়সমূহত যোগ কৰক"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g>এ এই নিয়ন্ত্ৰণটো আপোনাৰ প্ৰিয়সমূহত যোগ কৰাৰ পৰামৰ্শ দিছে।"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"নিয়ন্ত্ৰণসমূহ আপডে\'ট কৰা হৈছে"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 55c3bbe647a1..b06a8ea597bf 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"İcazə verin"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB debaq prosesinə icazə verilmir"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Hazırda bu cihaza daxil olmuş istifadəçi USB sazlama prosesini aktiv edə bilməz. Bu funksiyadan istifadə etmək üçün əsas istifadəçi hesaba daxil olmalıdır."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Bu şəbəkədə simsiz sazlamaya icazə verilsin?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Bu şəbəkədə WiFi sazlamasına icazə verilsin?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Şəbəkə Adı (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Ünvanı (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Bu şəbəkədə həmişə icazə verilsin"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"İcazə verin"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Simsiz sazlamaya icazə verilmir"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Hazırda bu cihaza daxil olmuş istifadəçi simsiz sazlamanı aktiv edə bilmir. Bu funksiyadan istifadə etmək üçün əsas istifadəçiyə keçin."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"WiFi sazlamasına icazə verilmir"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Hazırda bu cihaza daxil olmuş istifadəçi WiFi sazlamasını aktiv edə bilmir. Bu funksiyadan istifadə etmək üçün əsas istifadəçiyə keçin."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB portu deaktiv edildi"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"USB portu deaktivdir. Cihazı maye və zərbədən qorumaq üçün aksesuar aşkarlanmayacaq.\n\nUSB portu yenidən istifadə üçün təhlükəsiz olduqda bildiriş göndəriləcək."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Adapter və aksesuarları aşkarlamaq üçün USB portu aktiv edildi"</string> @@ -708,12 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"Səs və ya vibrasiya olmadan fokuslanmağınıza kömək edir."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"Səs və ya vibrasiya ilə diqqətinizi çəkir."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Bu məzmuna üzən qısayol ilə diqqətinizi cəlb edir."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Söhbət bölməsinin yuxarısında göstərilir və qabarcıq kimi görünür."</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Defolt olaraq, <xliff:g id="APP_NAME_0">%1$s</xliff:g> tətbiqindən gələn söhbətlər qabarcıq şəklində göstərilir. <xliff:g id="APP_NAME_1">%2$s</xliff:g> tətbiqində idarə edin."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Söhbət bölməsinin yuxarısında göstərilir və yumrucuq kimi görünür."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Defolt olaraq, <xliff:g id="APP_NAME_0">%1$s</xliff:g> tətbiqindən gələn söhbətlər yumrucuq şəklində göstərilir. <xliff:g id="APP_NAME_1">%2$s</xliff:g> tətbiqində idarə edin."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Qabarcıq yoxdur"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Son qabarcıqlar və buraxılmış qabarcıqlar burada görünəcək"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Yumrucuqlar yoxdur"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Son yumrucuqlar və buraxılmış yumrucuqlar burada görünəcək"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirişlər dəyişdirilə bilməz."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Bu bildiriş qrupunu burada konfiqurasiya etmək olmaz"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Proksi bildirişi"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"Susdurulub"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Siqnal"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"Qabarcığı göstərin"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Qabarcıqları silin"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Yumrucuqları silin"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Əsas ekrana əlavə edin"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"bildiriş nəzarəti"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"Cihaz Xidmətləri"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Başlıq yoxdur"</string> <string name="restart_button_description" msgid="6916116576177456480">"Bu tətbiqi sıfırlayaraq tam ekrana keçmək üçün klikləyin."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> qabarcıqları üçün ayarlar"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> yumrucuqları üçün ayarlar"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"İdarə edin"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> tətbiqindən <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> tətbiqindən <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> və daha <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> qabarcıq"</string> @@ -994,10 +994,10 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Aşağıya sağa köçürün"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Kənarlaşdırın"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Söhbətdən gələn bildirişi göstərməyin"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Qabarcıqlardan istifadə edərək söhbət edin"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yeni söhbətlər üzən nişanlar və ya qabarcıqlar kimi görünür. Qabarcığı açmaq üçün toxunun. Hərəkət etdirmək üçün sürüşdürün."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Qabarcıqları istənilən vaxt idarə edin"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu tətbiqdə qabarcıqları deaktiv etmək üçün \"İdarə edin\" seçiminə toxunun"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Yumrucuqlardan istifadə edərək söhbət edin"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yeni söhbətlər üzən nişanlar və ya yumrucuqlar kimi görünür. Yumrucuğu açmaq üçün toxunun. Hərəkət etdirmək üçün sürüşdürün."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Yumrucuqları istənilən vaxt idarə edin"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu tətbiqdə yumrucuqları deaktiv etmək üçün \"İdarə edin\" seçiminə toxunun"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Anladım"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistem naviqasiyası yeniləndi. Dəyişiklik etmək üçün Ayarlara daxil olun."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistem naviqasiyasını yeniləmək üçün Ayarlara keçin"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Böyütmə Üst-üstə Düşən Pəncərəsi"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Böyütmə Pəncərəsi"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Böyütmə Pəncərəsi Kontrolları"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Sürətli nizamlayıcılar"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Cihaz nizamlayıcıları"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Qoşulmuş cihazlarınız üçün nizamlayıcılar əlavə edin"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Sürətli nizamlayıcıları ayarlayın"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Cihaz nizamlayıcılarını ayarlayın"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Nizamlayıcılara giriş üçün Yandırıb-söndürmə düyməsini basıb saxlayın"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Nizamlayıcıları əlavə etmək üçün tətbiq seçin"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Nizamlayıcılar"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Enerji menyusundan daxil olacağınız nizamlayıcıları seçin"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Hərəkət etdirmək üçün nizamlayıcını tutub sürüşdürün"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Bütün nizamlayıcıların siyahısı yüklənmədi."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Digər"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Cəld nizamlayıcılara əlavə edin"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Cihaz nizamlayıcılarına əlavə edin"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Sevimlilərə əlavə edin"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> sevimlilərə əlavə etmək üçün bu nizamlayıcını təklif edib."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Nizamlayıcılar güncəlləndi"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 5aea86bca758..702c89901ad7 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -1010,9 +1010,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Preklopni prozor za uvećanje"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećanje"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za uvećanje"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Brze kontrole"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrole za povezane uređaje"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Podesite brze kontrole"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Podesite kontrole uređaja"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Zadržite dugme za uključivanje da biste pristupili kontrolama"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Odaberite aplikaciju za dodavanje kontrola"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1022,10 +1022,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrole"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Odaberite kontrole kojima ćete pristupati iz menija napajanja"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Zadržite i prevucite kontrolu da biste je premestili"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Učitavanje liste svih kontrola nije uspelo."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Dodajte u brze kontrole"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Dodajte u kontrole uređaja"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Dodajte u omiljene"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> predlaže da dodate ovu kontrolu u omiljene."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 6945010897b8..f976b36c696f 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Дазволіць"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Адладка USB не дапускаецца"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Карыстальнік, які зараз увайшоў у гэту прыладу, не можа ўключыць адладку USB. Каб выкарыстоўваць гэту функцыю, пераключыцеся на асноўнага карыстальніка."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Дазволіць бесправадную адладку ў гэтай сетцы?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Дазволіць адладку па Wi-Fi у гэтай сетцы?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Назва сеткі (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nАдрас Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Заўсёды дазваляць у гэтай сетцы"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Дазволіць"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Бесправадная адладка не дазволена"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Карыстальнік, які зараз увайшоў у гэту прыладу, не можа ўключыць бесправадную адладку. Каб выкарыстоўваць гэту функцыю, пераключыцеся на асноўнага карыстальніка."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Адладка па Wi-Fi не дазволена"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Карыстальнік, які зараз увайшоў у гэту прыладу, не можа ўключыць адладку па Wi-Fi. Каб выкарыстоўваць гэту функцыю, пераключыцеся на асноўнага карыстальніка."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"Порт USB адключаны"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Порт USB адключаны, каб засцерагчы прыладу ад вадкасці і смецця, таму дадатковае абсталяванне не будзе выяўлена.\n\nВы атрымаеце апавяшчэнне, калі порт USB можна будзе выкарыстоўваць зноў."</string> <string name="usb_port_enabled" msgid="531823867664717018">"USB-порту дазволена вызначаць зарадныя прылады і аксесуары"</string> @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Рабіць здымкі экрана не дазваляе праграма ці ваша арганізацыя"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Адхіліць здымак экрана"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Адкрыць здымак экрана"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Праграма запісу экрана"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Запіс экрана"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Бягучае апавяшчэнне для сеанса запісу экрана"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Пачаць запіс?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Падчас запісу сістэма Android можа збіраць канфідэнцыяльную інфармацыю, якая адлюстроўваецца на экране вашай прылады ці прайграецца на ёй. Гэта могуць быць паролі, плацежная інфармацыя, фота, паведамленні і аўдыяданыя."</string> @@ -993,7 +993,7 @@ <string name="device_services" msgid="1549944177856658705">"Сэрвісы прылады"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Без назвы"</string> <string name="restart_button_description" msgid="6916116576177456480">"Націсніце, каб перазапусціць гэту праграму і перайсці ў поўнаэкранны рэжым."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Налады дыялогаў у праграме \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Налады ўсплывальных апавяшчэнняў у праграме \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"Кіраваць"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ад праграмы \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ад праграмы \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" і яшчэ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string> @@ -1007,7 +1007,7 @@ <string name="bubbles_user_education_title" msgid="5547017089271445797">"Размаўляйце ў чаце, які паказвае ўсплывальныя апавяшчэнні"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новыя размовы будуць паказвацца як рухомыя значкі ці ўсплывальныя апавяшчэнні. Націсніце, каб адкрыць усплывальнае апавяшчэнне. Перацягніце яго, каб перамясціць."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Кіруйце ўсплывальнымі апавяшчэннямі ў любы час"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Каб выключыць усплывальная апавяшчэнні з гэтай праграмы, націсніце \"Кіраваць\""</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Каб выключыць усплывальныя апавяшчэнні з гэтай праграмы, націсніце \"Кіраваць\""</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Зразумела"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацыя ў сістэме абноўлена. Каб унесці змяненні, перайдзіце ў Налады."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перайдзіце ў Налады, каб абнавіць параметры навігацыі ў сістэме"</string> @@ -1015,9 +1015,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Акно-накладка з павелічэннем"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Акно павелічэння"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Налады акна павелічэння"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Элементы хуткага кіравання"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Элементы кіравання прыладай"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Дадайце элементы кіравання для падключаных прылад"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Наладзіць элементы хуткага кіравання"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Наладзіць элементы кіравання прыладай"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Для доступу да элементаў кіравання ўтрымлівайце кнопку сілкавання націснутай"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Выберыце праграму для дадавання элементаў кіравання"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1028,10 +1028,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Сродкі кіравання"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Выберыце элементы кіравання, да якіх вы хочаце мець доступ з меню сілкавання"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Каб перамясціць элемент кіравання, перацягніце яго"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Не ўдалося загрузіць спіс усіх сродкаў кіравання."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Іншае"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Дадаць у хуткае кіраванне"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Дадаць у элементы кіравання прыладай"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Дадаць у абраныя"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> прапануе дадаць гэты элемент кіравання ў вашы абраныя."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Элементы кіравання абноўлены"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index d350c407929c..d838c2bf9860 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Правенето на екранни снимки не е разрешено от приложението или организацията ви"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Отхвърляне на екранната снимка"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Отваряне на екранната снимка"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Записване на екрана"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Запис на екрана"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущо известие за сесия за записване на екрана"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Да се стартира ли записът?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"По време на записване системата Android може да прихване поверителна информация, която е показана на екрана или възпроизвеждана на устройството ви. Това включва пароли, данни за плащане, снимки, съобщения и аудио."</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Прозорец с наслагване за ниво на мащаба"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за ниво на мащаба"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Контроли за прозореца за ниво на мащаба"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Бързи контроли"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Контроли за устройството"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Добавяне на контроли за свързаните ви устройства"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Настройване на бързи контроли"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Настройване на контролите за устройството"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Задръжте бутона за захранване, за да осъществите достъп до контролите"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Изберете приложение, за да добавите контроли"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Контроли"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Избиране на контроли, които да са достъпни в менюто за захранване"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Задръжте и плъзнете дадена контрола, за да я преместите"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Списъкът с всички контроли не бе зареден."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Добавяне към бързите контроли"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Добавяне към контролите за устройството"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Добавяне в любимите"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> предложи тази контрола да се добави към любимите ви."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Контролите са актуализирани"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 047d00bfc962..095bee6e67ca 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -993,7 +993,7 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"নিচে বাঁদিকে সরান"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"নিচে ডান দিকে সরান"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"খারিজ করুন"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"কথোপকথন বাবল হিসেবে দেখাবেন না"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"কথোপকথন বাবল হিসেবে দেখাবে না"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"বাবল ব্যবহার করে চ্যাট করুন"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"নতুন কথোপকথন ভেসে থাকা আইকন বা বাবল হিসেবে দেখানো হয়। বাবল খুলতে ট্যাপ করুন। সেটি সরাতে ধরে টেনে আনুন।"</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"যেকোনও সময় বাবল নিয়ন্ত্রণ করুন"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"ওভারলে উইন্ডো বড় করে দেখা"</string> <string name="magnification_window_title" msgid="4863914360847258333">"উইন্ডো বড় করে দেখা"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"উইন্ডো কন্ট্রোল বড় করে দেখা"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"দ্রুত কন্ট্রোল"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইস কন্ট্রোল"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"আপনার কানেক্ট করা ডিভাইসের জন্য কন্ট্রোল যোগ করুন"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"দ্রুত কন্ট্রোল সেট-আপ করুন"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"ডিভাইস কন্ট্রোল সেট-আপ করুন"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"আপনার কন্ট্রোল অ্যাক্সেস করতে পাওয়ার বোতাম ধরে থাকুন"</string> <string name="controls_providers_title" msgid="6879775889857085056">"কন্ট্রোল যোগ করতে অ্যাপ বেছে নিন"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"নিয়ন্ত্রণ"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"যেসব কন্ট্রোল অ্যাক্সেস করতে চান সেগুলি পাওয়ার মেনু থেকে বেছে নিন"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"কন্ট্রোল সরাতে সেটি ধরে টেনে আনুন"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"সব কন্ট্রোলের তালিকা লোড করা যায়নি।"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"কুইক কন্ট্রোলে যোগ করুন"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"ডিভাইস কন্ট্রোলে যোগ করুন"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"পছন্দসইতে যোগ করুন"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"আপনার পছন্দসইতে যোগ করতে <xliff:g id="APP">%s</xliff:g> এই কন্ট্রোল সাজেস্ট করেছে।"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"কন্ট্রোল আপডেট করা হয়েছে"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 76b46de18e9c..6d05242352fe 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -1012,9 +1012,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Preklopni prozor za uvećavanje"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećavanje"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za uvećavanje"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Brze kontrole"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodavanje kontrola za povezane uređaje"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Postavite brze kontrole"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Postavite kontrole uređaja"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Držite dugme za uključivanje da pristupite kontrolama"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Odaberite aplikaciju da dodate kontrole"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1024,10 +1024,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrole"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Izaberite kontrole za pristup iz menija napajanja"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Zadržite i prevucite kontrolu da je premjestite"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Učitavanje liste svih kontrola nije uspjelo."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Dodajte u brze kontrole"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Dodajte u kontrole uređaja"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Dodajte u omiljeno"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikacija <xliff:g id="APP">%s</xliff:g> je predložila da se ova kontrola doda u omiljeno."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 04e053d9ba03..638282d75722 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -500,7 +500,7 @@ <string name="battery_saver_notification_text" msgid="2617841636449016951">"Redueix el rendiment i l\'ús de les dades en segon pla."</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactiva l\'estalvi de bateria"</string> <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tindrà accés a tota la informació que es veu en pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servei que ofereix aquesta funció tindrà accés a tota la informació que es veu en pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servei que ofereix aquesta funció tindrà accés a tota la informació visible a la teva pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio que reprodueixis."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vols començar a gravar o emetre contingut?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Vols començar a gravar o emetre contingut amb <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"No ho tornis a mostrar"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Finestra superposada d\'ampliació"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Finestra d\'ampliació"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Finestra de controls d\'ampliació"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Controls ràpids"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controls del dispositiu"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Afegeix controls per als teus dispositius connectats"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Configura els controls ràpids"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configura els controls del dispositiu"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Mantén el botó d\'engegada premut per accedir als teus controls"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Selecciona l\'aplicació per afegir controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controls"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Selecciona els controls per accedir-hi des del menú d\'engegada"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Mantén premut i arrossega un control per moure\'l"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"No s\'ha pogut carregar la llista completa de controls."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altres"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Afegeix als controls ràpids"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Afegeix als controls del dispositiu"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Afegeix als preferits"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ha suggerit aquest control perquè l\'afegeixis als preferits."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"S\'han actualitzat els controls"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 6c356a947dc3..c5192825073c 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikace nebo organizace zakazuje pořizování snímků obrazovky"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Zavřít snímek obrazovky"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Otevřít snímek obrazovky"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Nahrávání obrazovky"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Trvalé oznámení o relaci nahrávání"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Spustit nahrávání?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Při nahrávání může systém Android zaznamenávat citlivé údaje, které jsou viditelné na obrazovce nebo které jsou přehrávány na zařízení. Týká se to hesel, údajů o platbě, fotek, zpráv a zvuků."</string> @@ -1015,9 +1015,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Překryvné zvětšovací okno"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Zvětšovací okno"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Ovládací prvky zvětšovacího okna"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Rychlé ovládací prvky"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Ovládací prvky zařízení"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Přidejte ovládací prvky pro připojená zařízení"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Nastavení rychlých ovládacích prvků"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavení ovládacích prvků zařízení"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Podržením vypínače zobrazíte ovládací prvky"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Vyberte aplikaci, pro kterou chcete přidat ovládací prvky"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1028,10 +1028,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Ovládací prvky"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Vyberte ovládací prvky, které budou zobrazeny v nabídce vypínače"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Ovládací prvek přesunete přetáhnutím"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Načtení seznamu všech ovládacích prvků se nezdařilo."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Jiné"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Přidat do rychlých ovládacích prvků"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Přidání ovládacích prvků zařízení"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Přidat k oblíbeným"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikace <xliff:g id="APP">%s</xliff:g> navrhuje přidat tento ovládací prvek do oblíbených."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Ovládací prvky aktualizovány"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 82e554b16e77..c6dac99d3989 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Appen eller din organisation tillader ikke, at du tager screenshots"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Luk screenshot"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Åbn screenshot"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Skærmoptager"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Skærmoptagelse"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Konstant notifikation om skærmoptagelse"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Vil du starte optagelse?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Når du optager, kan Android-systemet registrere følsomme oplysninger, der er synlige på din skærm, eller som afspilles på din enhed. Dette inkluderer adgangskoder, betalingsoplysninger, fotos, meddelelser og lyd."</string> @@ -597,7 +597,7 @@ <string name="screen_pinning_toast" msgid="2083944237147005811">"Hold knapperne Tilbage og Oversigt nede for at frigøre skærmen"</string> <string name="screen_pinning_toast_recents_invisible" msgid="6343770487795352573">"Hold knapperne Tilbage og Hjem nede for at frigøre skærmen"</string> <string name="screen_pinning_toast_gesture_nav" msgid="2884536903398445645">"Stryg opad, og hold fingeren nede for at frigøre denne skærm"</string> - <string name="screen_pinning_positive" msgid="3285785989665266984">"OK, det er forstået"</string> + <string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string> <string name="screen_pinning_negative" msgid="6882816864569211666">"Nej tak"</string> <string name="screen_pinning_start" msgid="5695091877402422575">"Skærmen blev fastgjort"</string> <string name="screen_pinning_exit" msgid="5114993350662745840">"Skærmen blev frigjort"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Vindue med overlejret forstørrelse"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Vindue med forstørrelse"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Vindue med forstørrelsesstyring"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Hurtig betjening"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Styring af enheder"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Tilføj betjeningselementer på dine tilsluttede enheder"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Konfigurer hurtig betjening"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurer styring af enheder"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Hold afbryderknappen nede for at få adgang til dine betjeningselementer"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Vælg en app for at tilføje betjeningselementer"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1015,11 +1015,14 @@ <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> styringselementer er tilføjet.</item> </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Betjeningselementer"</string> - <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Vælg, hvilke betjeningselementer der skal være adgang til fra afbryderknappens menu"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Hold et betjeningselement nede, og træk for at flytte det"</string> + <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Vælg, hvilke indstillinger der skal være i menuen for afbryderknappen"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Listen over styringselementer kunne ikke indlæses."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andre"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Føj til Hurtig betjening"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Føj til styring af enheder"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Føj til favoritter"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> har foreslået, at du føjer denne funktion til dine favoritter."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Betjeningselementerne er opdateret"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 46733b0f86d0..842689509317 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Erlauben"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB-Debugging nicht zulässig"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Der momentan auf diesem Gerät angemeldete Nutzer kann das USB-Debugging nicht aktivieren. Um diese Funktion verwenden zu können, wechsle zum primären Nutzer."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Kabelloses Debugging in diesem Netzwerk zulassen?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"\"Debugging über WLAN\" in diesem Netzwerk zulassen?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Netzwerkname (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWLAN-Adresse (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Immer in diesem Netzwerk zulassen"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Zulassen"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Kabelloses Debugging nicht zulässig"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Der momentan auf diesem Gerät angemeldete Nutzer kann das kabellose Debugging nicht aktivieren. Um diese Funktion verwenden zu können, wechsle zum Hauptnutzer."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"\"Debugging über WLAN\" nicht zulässig"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Der momentan auf diesem Gerät angemeldete Nutzer kann \"Debugging über WLAN\" nicht aktivieren. Um diese Funktion verwenden zu können, wechsle zum Hauptnutzer."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB-Port deaktiviert"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Zum Schutz deines Geräts vor Flüssigkeiten oder Fremdkörpern ist der USB-Port zurzeit deaktiviert und erkennt kein Zubehör.\n\nDu wirst benachrichtigt, wenn der USB-Port wieder verwendet werden kann."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Erkennung von Ladegeräten und Zubehör am USB-Port aktiviert"</string> @@ -168,7 +168,7 @@ <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Zu viele Fehlversuche. Die Daten auf diesem Gerät werden gelöscht."</string> <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Zu viele Fehlversuche. Dieser Nutzer wird vom Gerät entfernt."</string> <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Zu viele Fehlversuche. Dieses Arbeitsprofil und die zugehörigen Daten werden gelöscht."</string> - <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Ablehnen"</string> + <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Schließen"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Berühre den Fingerabdrucksensor"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Fingerabdruck-Symbol"</string> <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"Wir suchen nach dir…"</string> @@ -508,7 +508,7 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Verwalten"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Verlauf"</string> <string name="notification_section_header_gentle" msgid="3044910806569985386">"Lautlose Benachrichtigungen"</string> - <string name="notification_section_header_alerting" msgid="3168140660646863240">"Nicht stummgeschaltete Benachrichtigungen"</string> + <string name="notification_section_header_alerting" msgid="3168140660646863240">"Laut gestellte Benachrichtigungen"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Unterhaltungen"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Alle lautlosen Benachrichtigungen löschen"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Benachrichtigungen durch \"Bitte nicht stören\" pausiert"</string> @@ -704,7 +704,7 @@ <string name="inline_keep_showing_app" msgid="4393429060390649757">"Benachrichtigungen dieser App weiterhin anzeigen?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Lautlos"</string> <string name="notification_alert_title" msgid="7629202599338071971">"Benachrichtigen"</string> - <string name="notification_bubble_title" msgid="8330481035191903164">"Infofeld"</string> + <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string> <string name="notification_channel_summary_low" msgid="7300447764759926720">"Benachrichtigungen werden ohne Ton oder Vibration angekündigt, um deine Konzentration nicht zu stören."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"Benachrichtigungen werden mit einem Ton oder einer Vibration angekündigt."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Du wirst mit einer unverankerten Verknüpfung darauf aufmerksam gemacht."</string> @@ -740,8 +740,8 @@ <string name="notification_conversation_unfavorite" msgid="181383708304763807">"Keine wichtige Unterhaltung"</string> <string name="notification_conversation_mute" msgid="268951550222925548">"Stummgeschaltet"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Nicht stummgeschaltet"</string> - <string name="notification_conversation_bubble" msgid="2242180995373949022">"Infofeld anzeigen"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Infofelder entfernen"</string> + <string name="notification_conversation_bubble" msgid="2242180995373949022">"Bubble anzeigen"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Bubbles entfernen"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Zum Startbildschirm hinzufügen"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g> – <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"Benachrichtigungseinstellungen"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Overlay-Vergrößerungsfenster"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Vergrößerungsfenster"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Einstellungen für Vergrößerungsfenster"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Schnellsteuerung"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Gerätesteuerung"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Karten für deine verbundenen Geräte hinzufügen"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Schnellsteuerung einrichten"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Gerätesteuerung einrichten"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Halte die Ein-/Aus-Taste gedrückt, um auf die Steuerelemente zuzugreifen."</string> <string name="controls_providers_title" msgid="6879775889857085056">"App zum Hinzufügen von Steuerelementen auswählen"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1015,11 +1015,14 @@ <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> Steuerelement hinzugefügt.</item> </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Steuerelemente"</string> - <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Karten auswählen, auf die über das Menü \"Ein/Aus\" zugegriffen werden kann"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Zum Verschieben einer Gerätekarte Karte halten und ziehen"</string> + <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Karten auswählen, auf die man über das Ein-/Aus-Menü zugreifen kann"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Fehler beim Laden der Liste mit Steuerelementen."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andere"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Zum Kartenbereich hinzufügen"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Zur Gerätesteuerung hinzufügen"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Zu Favoriten hinzufügen"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"\"<xliff:g id="APP">%s</xliff:g>\" hat vorgeschlagen, dieses Steuerelement deinen Favoriten hinzuzufügen."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Gerätekarten aktualisiert"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index a745c8ca55ac..dc026e4e156a 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Να επιτρέπεται"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Δεν επιτρέπεται ο εντοπισμός σφαλμάτων USB"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Ο χρήστης που είναι συνδεδεμένος αυτήν τη στιγμή σε αυτήν τη συσκευή δεν μπορεί να ενεργοποιήσει τον εντοπισμό σφαλμάτων USB. Για να χρησιμοποιήσετε αυτήν τη λειτουργία, κάντε εναλλαγή στον κύριο χρήστη."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Να επιτρέπεται ο εντοπισμός σφαλμάτων μέσω ασύρματης σύνδεσης σε αυτό το δίκτυο;"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Να επιτρέπεται ο ασύρματος εντοπισμός σφαλμάτων σε αυτό το δίκτυο;"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Όνομα δικτύου (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nΔιεύθυνση Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Να επιτρέπεται πάντα σε αυτό το δίκτυο"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Να επιτρέπεται"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Ο εντοπισμός σφαλμάτων μέσω ασύρματης σύνδεσης δεν επιτρέπεται"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Ο χρήστης που είναι συνδεδεμένος αυτήν τη στιγμή στη συγκεκριμένη συσκευή δεν μπορεί να ενεργοποιήσει τον εντοπισμό σφαλμάτων μέσω ασύρματης σύνδεσης. Για να χρησιμοποιήσετε αυτήν τη λειτουργία, κάντε εναλλαγή στον κύριο χρήστη."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Ο ασύρματος εντοπισμός σφαλμάτων δεν επιτρέπεται"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Ο χρήστης που είναι συνδεδεμένος αυτήν τη στιγμή στη συγκεκριμένη συσκευή δεν μπορεί να ενεργοποιήσει τον ασύρματο εντοπισμό σφαλμάτων. Για να χρησιμοποιήσετε αυτήν τη λειτουργία, κάντε εναλλαγή στον κύριο χρήστη."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"Η θύρα USB απενεργοποιήθηκε"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Για την προστασία της συσκευής σας από υγρασία ή ακαθαρσίες, η θύρα USB έχει απενεργοποιηθεί και δεν θα εντοπίζει τυχόν αξεσουάρ.\n\nΘα ειδοποιηθείτε όταν θα μπορείτε να χρησιμοποιήσετε ξανά τη θύρα USB."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Η θύρα USB ενεργοποιήθηκε για τον εντοπισμό φορτιστών και αξεσουάρ"</string> @@ -509,7 +509,7 @@ <string name="manage_notifications_history_text" msgid="57055985396576230">"Ιστορικό"</string> <string name="notification_section_header_gentle" msgid="3044910806569985386">"Ειδοποιήσεις σε σίγαση"</string> <string name="notification_section_header_alerting" msgid="3168140660646863240">"Ειδοποιήσεις"</string> - <string name="notification_section_header_conversations" msgid="821834744538345661">"Συνομιλίες"</string> + <string name="notification_section_header_conversations" msgid="821834744538345661">"Συζητήσεις"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Διαγραφή όλων των ειδοποιήσεων σε σίγαση"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Οι ειδοποιήσεις τέθηκαν σε παύση από τη λειτουργία \"Μην ενοχλείτε\""</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Έναρξη τώρα"</string> @@ -708,12 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"Σας βοηθά να συγκεντρωθείτε χωρίς ήχο και δόνηση."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"Τραβά την προσοχή σας με ήχο ή δόνηση."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Κρατάει την προσοχή σας με μια κινούμενη συντόμευση προς αυτό το περιεχόμενο."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Εμφανίζεται στο επάνω μέρος της ενότητας συνομιλίας ως φούσκα."</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Όλες οι συνομιλίες από την εφαρμογή <xliff:g id="APP_NAME_0">%1$s</xliff:g> εμφανίζονται από προεπιλογή ως φούσκες. Διαχείριση στην εφαρμογή <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Εμφανίζεται στο επάνω μέρος της ενότητας συζήτησης ως συννεφάκι."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Όλες οι συζητήσεις από την εφαρμογή <xliff:g id="APP_NAME_0">%1$s</xliff:g> εμφανίζονται από προεπιλογή ως συννεφάκια. Διαχείριση στην εφαρμογή <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ρυθμίσεις"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Προτεραιότητα"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Δεν υπάρχουν πρόσφατες φούσκες"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Οι πρόσφατες φούσκες και οι φούσκες που παραβλέψατε θα εμφανίζονται εδώ."</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Δεν υπάρχουν πρόσφατα συννεφάκια"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Τα πρόσφατα συννεφάκια και τα συννεφάκια που παραβλέψατε θα εμφανίζονται εδώ."</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Δεν είναι δυνατή η τροποποίηση αυτών των ειδοποιήσεων"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Δεν είναι δυνατή η διαμόρφωση αυτής της ομάδας ειδοποιήσεων εδώ"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Ειδοποίηση μέσω διακομιστή μεσολάβησης"</string> @@ -993,10 +993,10 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Μετακίνηση κάτω αριστερά"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Μετακίνηση κάτω δεξιά"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Παράβλεψη"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Να μη γίνει προβολή της συνομιλίας σε φούσκες."</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Συζητήστε χρησιμοποιώντας φούσκες."</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"Οι νέες συνομιλίες εμφανίζονται ως κινούμενα εικονίδια ή φούσκες. Πατήστε για να ανοίξετε τη φούσκα. Σύρετε για να το μετακινήσετε."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Ελέγξτε τις φούσκες ανά πάσα στιγμή."</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Να μην γίνει προβολή της συζήτησης σε συννεφάκια."</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Συζητήστε χρησιμοποιώντας συννεφάκια."</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"Οι νέες συζητήσεις εμφανίζονται ως κινούμενα εικονίδια ή φούσκες. Πατήστε για να ανοίξετε τη φούσκα. Σύρετε για να το μετακινήσετε."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Ελέγξτε τα συννεφάκια ανά πάσα στιγμή."</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Πατήστε Διαχείριση για να απενεργοποιήσετε τα συννεφάκια από αυτήν την εφαρμογή."</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Το κατάλαβα."</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Η πλοήγηση συστήματος ενημερώθηκε. Για να κάνετε αλλαγές, μεταβείτε στις Ρυθμίσεις."</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Παράθυρο επικάλυψης μεγέθυνσης"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Παράθυρο μεγέθυνσης"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Στοιχεία ελέγχου παραθύρου μεγέθυνσης"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Στοιχεία γρήγορου ελέγχου"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Στοιχεία ελέγχου συσκευής"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Προσθήκη στοιχείων ελέγχου για τις συνδεδεμένες συσκευές σας."</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Ρύθμιση στοιχείων γρήγορου ελέγχου"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Ρύθμιση στοιχείων ελέγχου συσκευής"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Κρατήστε πατημένο το κουμπί λειτουργίας, για να αποκτήσετε πρόσβαση στα στοιχεία ελέγχου"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Επιλογή εφαρμογής για προσθήκη στοιχείων ελέγχου"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Στοιχεία ελέγχου"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Επιλέξτε τα στοιχεία ελέγχου στα οποία θα έχετε πρόσβαση από το μενού λειτουργίας."</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Πατήστε παρατεταμένα και σύρετε ένα στοιχείο ελέγχου, για να το μετακινήσετε."</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Ανεπιτυχής φόρτωση λίστας όλων των στοιχ. ελέγχου."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Άλλο"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Προσθ. σε Στοιχ. γρήγ. ελέγχου"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Προσθήκη στα στοιχεία ελέγχου συσκευής"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Προσθήκη στα αγαπημένα"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"Η εφαρμογή <xliff:g id="APP">%s</xliff:g> πρότεινε αυτό το στοιχείο ελέγχου για προσθήκη στα αγαπημένα."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Ενημέρωση στοιχείων ελέγχου"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 15fdaf1d1d84..bbaa283e9fe7 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Open screenshot"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Screen recorder"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string> @@ -713,7 +713,7 @@ <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent Bubbles and dismissed Bubbles will appear here"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Proxied notification"</string> @@ -994,9 +994,9 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using Bubbles"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or Bubbles. Tap to open bubble. Drag to move it."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control Bubbles at any time"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control bubbles at any time"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tap Manage to turn off bubbles from this app"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Quick controls"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Set up quick controls"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Hold the Power button to access your controls"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controls"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Choose controls to access from the power menu"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Hold and drag a control to move it"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Hold and drag to rearrange controls"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Add to quick controls"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 084d82b4f11e..55bc58288b2e 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Open screenshot"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Screen recorder"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string> @@ -713,7 +713,7 @@ <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent Bubbles and dismissed Bubbles will appear here"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Proxied notification"</string> @@ -994,9 +994,9 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using Bubbles"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or Bubbles. Tap to open bubble. Drag to move it."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control Bubbles at any time"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control bubbles at any time"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tap Manage to turn off bubbles from this app"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Quick controls"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Set up quick controls"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Hold the Power button to access your controls"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controls"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Choose controls to access from the power menu"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Hold and drag a control to move it"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Hold and drag to rearrange controls"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Add to quick controls"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 15fdaf1d1d84..bbaa283e9fe7 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Open screenshot"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Screen recorder"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string> @@ -713,7 +713,7 @@ <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent Bubbles and dismissed Bubbles will appear here"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Proxied notification"</string> @@ -994,9 +994,9 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using Bubbles"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or Bubbles. Tap to open bubble. Drag to move it."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control Bubbles at any time"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control bubbles at any time"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tap Manage to turn off bubbles from this app"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Quick controls"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Set up quick controls"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Hold the Power button to access your controls"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controls"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Choose controls to access from the power menu"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Hold and drag a control to move it"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Hold and drag to rearrange controls"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Add to quick controls"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 15fdaf1d1d84..bbaa283e9fe7 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Open screenshot"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Screen recorder"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string> @@ -713,7 +713,7 @@ <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent Bubbles and dismissed Bubbles will appear here"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Proxied notification"</string> @@ -994,9 +994,9 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using Bubbles"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or Bubbles. Tap to open bubble. Drag to move it."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control Bubbles at any time"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control bubbles at any time"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tap Manage to turn off bubbles from this app"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Quick controls"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Set up quick controls"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Hold the Power button to access your controls"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controls"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Choose controls to access from the power menu"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Hold and drag a control to move it"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Hold and drag to rearrange controls"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Add to quick controls"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 24628b54fdb2..046f5cd34efb 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification Overlay Window"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Magnification Window"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Magnification Window Controls"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Quick controls"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Add controls for your connected devices"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Set up quick controls"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Set up device controls"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Hold the Power button to access your controls"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controls"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Choose controls to access from the power menu"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Hold and drag a control to move it"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Hold & drag to rearrange controls"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"All controls removed"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Add to quick controls"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Add to device controls"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favorites"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favorites."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controls updated"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 9e7bfb9a4ca7..4cc643b36a3f 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"Servicios del dispositivo"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string> <string name="restart_button_description" msgid="6916116576177456480">"Presiona para reiniciar esta app y acceder al modo de pantalla completa."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configuración para cuadros de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configuración para burbujas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"Administrar"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> y <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> más"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Ventana superpuesta de ampliación"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Controles de ampliación de la ventana"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Controles rápidos"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controles del dispositivo"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Agrega controles para los dispositivos conectados"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Configura los controles rápidos"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles del dispositivo"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Mantén presionado el botón de encendido para acceder a los controles"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Elige la app para agregar los controles"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controles"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Elige los controles a los que quieres acceder desde el menú de encendido"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Mantén presionado un control y arrástralo para moverlo"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"No se cargó la lista completa de controles."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Agregar a controles rápidos"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Agregar a controles del dispositivo"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Agregar a favoritos"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"La app <xliff:g id="APP">%s</xliff:g> sugirió que agregaras este control a favoritos."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles actualizados"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index d6700232cab9..80dca347ab06 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -28,7 +28,7 @@ <string name="battery_low_percent_format" msgid="4276661262843170964">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería"</string> <string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"Queda un <xliff:g id="PERCENTAGE">%1$s</xliff:g> (tiempo restante aproximado según tu uso: <xliff:g id="TIME">%2$s</xliff:g>)"</string> <string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"Queda un <xliff:g id="PERCENTAGE">%1$s</xliff:g> (tiempo restante aproximado: <xliff:g id="TIME">%2$s</xliff:g>)"</string> - <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. Se ha activado la función Ahorro de energía."</string> + <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de batería. Se ha activado el modo Ahorro de batería."</string> <string name="invalid_charger" msgid="4370074072117767416">"No se puede cargar por USB. Utiliza el cargador original incluido con el dispositivo."</string> <string name="invalid_charger_title" msgid="938685362320735167">"No se puede cargar por USB"</string> <string name="invalid_charger_text" msgid="2339310107232691577">"Utiliza el cargador original incluido con el dispositivo"</string> @@ -46,9 +46,9 @@ <string name="bluetooth_tethered" msgid="4171071193052799041">"Bluetooth anclado"</string> <string name="status_bar_input_method_settings_configure_input_methods" msgid="2972273031043777851">"Configurar métodos de entrada"</string> <string name="status_bar_use_physical_keyboard" msgid="4849251850931213371">"Teclado físico"</string> - <string name="usb_device_permission_prompt" msgid="4414719028369181772">"¿Quieres permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string> + <string name="usb_device_permission_prompt" msgid="4414719028369181772">"¿Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string> <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"¿Quieres que <xliff:g id="APPLICATION">%1$s</xliff:g> pueda acceder a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta aplicación no tiene permisos para grabar, pero podría captar audio a través de este dispositivo USB."</string> - <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"¿Quieres permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string> + <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"¿Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string> <string name="usb_device_confirm_prompt" msgid="4091711472439910809">"¿Quieres abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para utilizar <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string> <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"¿Quieres abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para gestionar <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta aplicación no tiene permisos para grabar, pero puede capturar audio mediante este dispositivo USB."</string> <string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"¿Quieres abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para utilizar <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string> @@ -499,20 +499,20 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Ahorro de batería activado"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduce el rendimiento y los datos en segundo plano"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactivar Ahorro de batería"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tendrá acceso a toda la información que se muestra en pantalla o se reproduce en el dispositivo mientras grabas o envías contenido, incluyendo contraseñas, detalles de pagos, fotos, mensajes y audios que reproduzcas."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servicio que ofrece esta función tendrá acceso a toda la información que se muestra en pantalla o se reproduce en el dispositivo mientras grabas o envías contenido, incluyendo contraseñas, detalles de pagos, fotos, mensajes y audios que reproduzcas."</string> - <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"¿Quieres empezar a grabar o enviar contenido?"</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tendrá acceso a toda la información que se muestre en pantalla o se reproduzca en el dispositivo mientras grabas o envías contenido, incluyendo contraseñas, detalles de pagos, fotos, mensajes y audios que reproduzcas."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servicio que ofrece esta función tendrá acceso a toda la información que se muestre en pantalla o se reproduzca en el dispositivo mientras grabas o envías contenido, incluyendo contraseñas, detalles de pagos, fotos, mensajes y audios que reproduzcas."</string> + <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"¿Empezar a grabar o enviar contenido?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"¿Quieres iniciar la grabación o el envío de contenido con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"No volver a mostrar"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Gestionar"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string> <string name="notification_section_header_gentle" msgid="3044910806569985386">"Notificaciones silenciadas"</string> - <string name="notification_section_header_alerting" msgid="3168140660646863240">"Notificaciones que alertan"</string> + <string name="notification_section_header_alerting" msgid="3168140660646863240">"Notificaciones de alerta"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas las notificaciones silenciadas"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificaciones pausadas por el modo No molestar"</string> - <string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar ahora"</string> + <string name="media_projection_action_text" msgid="3634906766918186440">"Empezar ahora"</string> <string name="empty_shade_text" msgid="8935967157319717412">"No hay notificaciones"</string> <string name="profile_owned_footer" msgid="2756770645766113964">"Es posible que se supervise el perfil"</string> <string name="vpn_footer" msgid="3457155078010607471">"Puede que la red esté supervisada"</string> @@ -638,7 +638,7 @@ <string name="output_service_bt_wifi" msgid="7186882540475524124">"Bluetooth y Wi‑Fi"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Configurador de UI del sistema"</string> <string name="show_battery_percentage" msgid="6235377891802910455">"Mostrar porcentaje de batería insertado"</string> - <string name="show_battery_percentage_summary" msgid="9053024758304102915">"Mostrar el porcentaje del nivel de batería en el icono de la barra de estado cuando no se esté cargando"</string> + <string name="show_battery_percentage_summary" msgid="9053024758304102915">"Muestra el porcentaje del nivel de batería en el icono de la barra de estado cuando no se esté cargando"</string> <string name="quick_settings" msgid="6211774484997470203">"Ajustes rápidos"</string> <string name="status_bar" msgid="4357390266055077437">"Barra de estado"</string> <string name="overview" msgid="3522318590458536816">"Aplicaciones recientes"</string> @@ -965,7 +965,7 @@ <string name="mobile_data_disable_message" msgid="8604966027899770415">"No tendrás conexión a Internet ni de datos móviles a través de <xliff:g id="CARRIER">%s</xliff:g>. Solo podrás conectarte a Internet mediante una red Wi‑Fi."</string> <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"tu operador"</string> <string name="touch_filtered_warning" msgid="8119511393338714836">"Una aplicación impide ver una solicitud de permiso, por lo que Ajustes no puede verificar tu respuesta."</string> - <string name="slice_permission_title" msgid="3262615140094151017">"¿Quieres permitir que <xliff:g id="APP_0">%1$s</xliff:g> muestre fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>?"</string> + <string name="slice_permission_title" msgid="3262615140094151017">"¿Permitir que <xliff:g id="APP_0">%1$s</xliff:g> muestre fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>?"</string> <string name="slice_permission_text_1" msgid="6675965177075443714">"- Puede leer información de <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="slice_permission_text_2" msgid="6758906940360746983">"- Puede realizar acciones en <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="slice_permission_checkbox" msgid="4242888137592298523">"Permitir que <xliff:g id="APP">%1$s</xliff:g> muestre fragmentos de cualquier aplicación"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Ventana de superposición de ampliación"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Ventana de controles de ampliación"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Controles rápidos"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controles del dispositivo"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Añade controles a tus dispositivos conectados"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Configurar controles rápidos"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles del dispositivo"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Mantén pulsado el botón de encendido para acceder a tus controles"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Elige una aplicación para añadir controles"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controles"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Elige los controles a los que acceder desde el menú de encendido"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Pulsa y arrastra un control para moverlo"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"No se ha podido cargar la lista de los controles."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Añadir a controles rápidos"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Añadir a controles del dispositivo"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Añadir a favoritos"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"La aplicación <xliff:g id="APP">%s</xliff:g> ha sugerido este control para que lo añadas a tus favoritos."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles actualizados"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 5ee56bf92163..aab46930286a 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Rakendus või teie organisatsioon ei luba ekraanipilte jäädvustada"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Sule ekraanipilt"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Ava ekraanipilt"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Ekraanikuva salvesti"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Ekraanisalvesti"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Kas alustada salvestamist?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Heli salvestamise ajal võib Androidi süsteem jäädvustada tundlikku teavet, mis on ekraanikuval nähtav või mida seadmes esitatakse. See hõlmab paroole, makseteavet, fotosid, sõnumeid ja heli."</string> @@ -962,7 +962,7 @@ <string name="running_foreground_services_title" msgid="5137313173431186685">"Rakendusi käitatakse taustal"</string> <string name="running_foreground_services_msg" msgid="3009459259222695385">"Aku ja andmekasutuse üksikasjade nägemiseks puudutage"</string> <string name="mobile_data_disable_title" msgid="5366476131671617790">"Kas lülitada mobiilne andmeside välja?"</string> - <string name="mobile_data_disable_message" msgid="8604966027899770415">"Teil ei ole operaatori <xliff:g id="CARRIER">%s</xliff:g> kaudu juurdepääsu andmesidele ega Internetile. Internet on saadaval ainult WiFi kaudu."</string> + <string name="mobile_data_disable_message" msgid="8604966027899770415">"Pärast seda pole teil operaatori <xliff:g id="CARRIER">%s</xliff:g> kaudu juurdepääsu andmesidele ega internetile. Internet on saadaval ainult WiFi kaudu."</string> <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"teie operaator"</string> <string name="touch_filtered_warning" msgid="8119511393338714836">"Seaded ei saa teie vastust kinnitada, sest rakendus varjab loataotlust."</string> <string name="slice_permission_title" msgid="3262615140094151017">"Kas lubada rakendusel <xliff:g id="APP_0">%1$s</xliff:g> näidata rakenduse <xliff:g id="APP_2">%2$s</xliff:g> lõike?"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Suurendamisakna ülekate"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Suurendamisaken"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Suurendamisakna juhtelemendid"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Kiirnupud"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Seadme juhtelemendid"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Lisage juhtelemendid ühendatud seadmete jaoks"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Kiirnuppude seadistamine"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Seadme juhtelementide seadistamine"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Juhtelementidele juurdepääsemiseks hoidke all toitenuppu"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Valige juhtelementide lisamiseks rakendus"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Juhtnupud"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Valige toitemenüüs saadaolevad juhtelemendid"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Hoidke ja lohistage juhtelementi, et seda liigutada"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Kõikide juhtelementide loendit ei saanud laadida."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Lisa kiirnuppude hulka"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Seadme juhtelementide hulka lisamine"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Lisa lemmikutesse"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> soovitas selle juhtnupu teie lemmikutesse lisada."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Juhtelemente värskendati"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 1688fc324a05..56c2f7c26016 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -68,7 +68,7 @@ <string name="wifi_debugging_always" msgid="2968383799517975155">"Onartu beti sare honetan"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Baimendu"</string> <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Ez da onartzen hari gabeko arazketa"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Gailu honetan saioa hasita daukan erabiltzaileak ezin du aktibatu hari gabeko bidezko arazketa. Eginbide hori erabiltzeko, aldatu erabiltzaile nagusira."</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Gailu honetan saioa hasita daukan erabiltzaileak ezin du aktibatu hari gabeko arazketa. Eginbide hori erabiltzeko, aldatu erabiltzaile nagusira."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"Desgaitu egin da USB ataka"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"USB ataka desgaitu egin da gailua likido edo zikinkeriengandik babesteko, eta ez du hautemango osagarririk.\n\nJakinarazpen bat jasoko duzu USB ataka berriz erabiltzeko moduan dagoenean."</string> <string name="usb_port_enabled" msgid="531823867664717018">"USB ataka gaitu da kargagailuak eta osagarriak hautemateko"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Lupa-leiho gainjarria"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Lupa-leihoa"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Lupa-leihoaren aukerak"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Kontrolatzeko aukera bizkorrak"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Gailua kontrolatzeko aukerak"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Gehitu kontrolatzeko aukerak konektatutako gailuetan"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Konfiguratu kontrolatzeko aukera bizkorrak"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfiguratu gailua kontrolatzeko aukerak"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Kontrol-aukerak atzitzeko, eduki sakatuta etengailua"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Aukeratu aplikazio bat kontrolatzeko aukerak gehitzeko"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1015,11 +1015,14 @@ <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> kontrol-aukera gehitu da.</item> </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrolatzeko aukerak"</string> - <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Aukeratu pizteko menutik atzitu nahi dituzun kontrolatzeko aukerak"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Kontrolatzeko aukera bat mugitzeko, eduki ezazu sakatuta, eta arrastatu"</string> + <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Aukeratu itzaltzeko menutik atzitu nahi dituzun kontrolatzeko aukerak"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Ezin izan da kargatu kontrol guztien zerrenda."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Beste bat"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Gehitu kontrolatzeko aukera bizkorretan"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Gehitu gailua kontrolatzeko aukeretan"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Gehitu gogokoetan"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> aplikazioak aukera hau gogokoetan gehitzea iradoki du."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Eguneratu dira kontrolatzeko aukerak"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index e719c538ca81..a343bdf42ef2 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"پنجره همپوشانی بزرگنمایی"</string> <string name="magnification_window_title" msgid="4863914360847258333">"پنجره بزرگنمایی"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"کنترلهای پنجره بزرگنمایی"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"کنترلهای سریع"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"کنترلهای دستگاه"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"افزودن کنترلها برای دستگاههای متصل"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"راهاندازی کنترلهای سریع"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"تنظیم کنترلهای دستگاه"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"دکمه روشن/خاموش را نگه دارید تا به کنترلها دسترسی پیدا کنید"</string> <string name="controls_providers_title" msgid="6879775889857085056">"انتخاب برنامه برای افزودن کنترلها"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"کنترلها"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"برای دسترسی از منوی روشن/خاموش، کنترلها را انتخاب کنید"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"برای جابهجایی کنترل، آن را نگه دارید و بکشید"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"فهرست همه کنترلها را نمیتوان بارگیری کرد."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"موارد دیگر"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"افزودن به «کنترلهای سریع»"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"افزودن به کنترلهای دستگاه"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"افزودن به موارد دلخواه"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> پیشنهاد میکند این کنترل به موارد دلخواهتان اضافه شود."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"کنترلها بهروزرسانی شد"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index b71fc5309b54..c082c75788a3 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -712,7 +712,7 @@ <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Kaikki sovelluksen <xliff:g id="APP_NAME_0">%1$s</xliff:g> keskustelut näytetään oletuksena kuplina. Muuta asetuksia sovelluksessa <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Asetukset"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Tärkeä"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ei viimeaikaisia ohjekuplia"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ei viimeaikaisia kuplia"</string> <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Viimeaikaiset ja äskettäin ohitetut kuplat näkyvät täällä"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Näitä ilmoituksia ei voi muokata"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Tätä ilmoitusryhmää ei voi määrittää tässä"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"Mykistetty"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Hälyttää"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"Näytä ohjekuplana"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Poista ohjekuplat"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Poista kuplat"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Lisää aloitusnäytölle"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"Ilmoitusten hallinta"</string> @@ -997,7 +997,7 @@ <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chattaile kuplien avulla"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Uudet keskustelut näkyvät kelluvina kuvakkeina tai kuplina. Avaa kupla napauttamalla. Siirrä sitä vetämällä."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Muuta kuplien asetuksia milloin tahansa"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Valitse Hallinnoi, jos haluat poistaa ohjekuplat käytöstä tästä sovelluksesta"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Valitse Hallinnoi, jos haluat poistaa kuplat käytöstä tästä sovelluksesta"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Selvä"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Järjestelmän navigointitapa vaihdettu. Voit muuttaa sitä asetuksista."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Vaihda järjestelmän navigointitapaa asetuksista"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Suurennuksen peittoikkuna"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Suurennusikkuna"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Suurennusikkunan ohjaimet"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Pikasäätimet"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Laitteen säätimet"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Lisää säätimiä yhdistettyihin laitteisiisi"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Ota pikasäätimet käyttöön"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Laitteen säätimien käyttöönotto"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Voit käyttää säätimiä painamalla virtapainiketta"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Valitse sovellus lisätäksesi säätimiä"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Säätimet"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Valitse säätimet, joita käytetään virtavalikosta"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Siirrä säädintä painamalla sitä pitkään ja vetämällä"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Kaikkien säätimien luetteloa ei voitu ladata."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Lisää pikasäätimiin"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Lisää laitteen säätimiin"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Lisää suosikkeihin"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ehdotti tämän säätimen lisäämistä suosikkeihisi."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Säätimet päivitetty"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index bd86b0841a29..82879f188f19 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -500,7 +500,7 @@ <string name="battery_saver_notification_text" msgid="2617841636449016951">"Réduire les performances et de fond"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Désactiver la fonction Économie d\'énergie"</string> <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aura accès à toute l\'information visible sur votre écran ou qui joue sur votre appareil durant l\'enregistrement ou la diffusion. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et l\'audio que vous faites jouer."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Le service offrant cette fonction aura accès à toute l\'information visible sur votre écran ou qui joue sur votre appareil durant l\'enregistrement ou la diffusion. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et l\'audio que vous faites jouer."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Le service offrant cette fonction aura accès à toute l\'information qui est visible sur votre écran ou sur ce qui joue sur votre appareil durant l\'enregistrement ou la diffusion. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et le contenu audio que vous faites jouer."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Commencer à enregistrer ou à diffuser?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Commencer à enregistrer ou à diffuser avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Ne plus afficher"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Fenêtre d\'agrandissement superposée"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Commandes pour la fenêtre d\'agrandissement"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Commandes rapides"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Commandes de l\'appareil"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajoutez des commandes pour vos appareils connectés"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Configurer les commandes rapides"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes de l\'appareil"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Maintenez l\'interrupteur enfoncé pour accéder à vos commandes"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'application pour laquelle ajouter des commandes"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Commandes"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Sélectionnez les commandes auxquelles vous souhaitez accéder à partir du menu de l\'interrupteur"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Maintenez le doigt sur une commande et faites-la glisser pour la déplacer"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Maintenez le doigt sur l\'écran, puis glissez-le pour réorganiser les commandes"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"Toutes les commandes ont été supprimées"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger la liste des commandes."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Ajouter aux commandes rapides"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes de l\'appareil"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Ajouter aux favoris"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"L\'application <xliff:g id="APP">%s</xliff:g> a suggéré d\'ajouter cette commande à vos favoris."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 4b78d1680cbc..4193499de4e4 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Autoriser"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Débogage USB non autorisé"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"L\'utilisateur actuellement connecté sur cet appareil ne peut pas activer le débogage USB. Pour utiliser cette fonctionnalité, l\'utilisateur principal doit se connecter."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Autoriser le débogage via Wi-Fi sur ce réseau ?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Autoriser le débogage sans fil sur ce réseau ?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Nom du réseau (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresse Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Toujours autoriser sur ce réseau"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Autoriser"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Débogage via Wi-Fi non autorisé"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"L\'utilisateur actuellement connecté sur cet appareil ne peut pas activer le débogage via Wi-Fi. Pour que cette fonctionnalité soit disponible, l\'utilisateur principal doit se connecter."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Débogage sans fil non autorisé"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"L\'utilisateur actuellement connecté sur cet appareil ne peut pas activer le débogage sans fil. Pour que cette fonctionnalité soit disponible, l\'utilisateur principal doit se connecter."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"Port USB désactivé"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Pour protéger votre appareil des liquides et des saletés, le port USB est désactivé et ne détecte plus les accessoires.\n\nVous recevrez une notification lorsque vous pourrez de nouveau utiliser le port USB."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Port USB activé pour détecter les chargeurs et les accessoires"</string> @@ -500,7 +500,7 @@ <string name="battery_saver_notification_text" msgid="2617841636449016951">"Limite les performances et les données en arrière-plan."</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Désactiver l\'économiseur de batterie"</string> <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aura accès à toutes les informations visibles sur votre écran ou lues depuis votre appareil lors d\'un enregistrement ou d\'une diffusion de contenu. Par exemple, vos mots de passe, vos données de paiement, vos photos, vos messages ou encore vos contenus audio lus."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Le service fournissant cette fonctionnalité aura accès à toutes les informations visibles sur votre écran ou lues depuis votre appareil lors d\'un enregistrement ou d\'une diffusion de contenu. Par exemple, vos mots de passe, vos données de paiement, vos photos, vos messages ou encore vos contenus audio lus."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Le service qui fournit cette fonction aura accès à toutes les informations visibles sur votre écran ou lues depuis votre appareil lors d\'un enregistrement ou d\'une diffusion de contenu. Cela comprend, entre autres, vos mots de passe, vos données de paiement, vos photos, vos messages ou encore les contenus audio que vous lisez."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Démarrer l\'enregistrement ou la diffusion ?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Démarrer l\'enregistrement ou la diffusion avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Ne plus afficher"</string> @@ -708,12 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"Sans sons ni vibrations, vous aide à vous concentrer."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"Attire votre attention à l\'aide de sons ou de vibrations."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Attire votre attention à l\'aide d\'un raccourci flottant vers ce contenu."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"S\'affiche en haut de la section des conversations sous forme de bulle."</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Par défaut, toutes les conversations <xliff:g id="APP_NAME_0">%1$s</xliff:g> s\'affichent sous forme de bulles. Gérer dans <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"S\'affiche en haut de la section des conversations et apparaît sous forme de bulle."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Par défaut, toutes les conversations <xliff:g id="APP_NAME_0">%1$s</xliff:g> s\'affichent sous forme de bulles. Vous pouvez gérer cela dans <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Aucune bulle récente"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bulles récentes et fermées s\'afficheront ici"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bulles récentes et ignorées s\'afficheront ici"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossible de modifier ces notifications."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Vous ne pouvez pas configurer ce groupe de notifications ici"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Notification de proxy"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"En silencieux"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Réactiver le son"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"Afficher sous forme de bulle"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Désactiver l\'affichage sous forme de bulle"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Désactiver l\'affichage sous forme de bulles"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Ajouter à l\'écran d\'accueil"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> : <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"paramètres des notifications"</string> @@ -993,11 +993,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Déplacer en bas à gauche"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Déplacer en bas à droite"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorer"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne pas afficher les conversations dans des bulles"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne pas afficher la conversations dans des bulles"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatter en utilisant des bulles"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes ou bulles. Appuyez sur la bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Contrôler les paramètres des bulles"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Appuyez sur \"Gérer\" pour désactiver les bulles pour cette application"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Appuyez sur \"Gérer\" pour désactiver les bulles de cette application"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigation système mise à jour. Pour apporter des modifications, accédez aux paramètres."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez aux paramètres pour mettre à jour la navigation système"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Fenêtre de superposition de l\'agrandissement"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Fenêtre des commandes d\'agrandissement"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Commandes rapides"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Commandes de l\'appareil"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajouter des commandes pour vos appareils connectés"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Configurez des commandes rapides"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes de l\'appareil"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Appuyez de manière prolongée sur le bouton Marche/Arrêt pour accéder aux commandes"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'appli pour laquelle ajouter des commandes"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Commandes"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Sélectionnez les commandes auxquelles vous souhaitez accéder depuis le menu de démarrage"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Appuyez de manière prolongée sur une commande pour la déplacer"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger toutes les commandes."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Ajouter aux commandes rapides"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes de l\'appareil"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Ajouter aux favoris"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> a suggéré d\'ajouter cette commande aux favoris."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 95f432e35152..dec9c71b31e6 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Ampliación da ventá de superposición"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Ventá de superposición"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Controis de ampliación da ventá"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Controis rápidos"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Engade controis para os dispositivos conectados"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Configurar os controis rápidos"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar control de dispositivos"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Mantén premido o botón de acendido para acceder aos controis"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Escolle unha aplicación para engadir controis"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controis"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Escolle os controis para acceder desde o menú de acendido"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Mantén premido un control e arrástrao para movelo"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Non se puido cargar a lista de todos os controis."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outra"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Engadir a controis rápidos"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Engadir ao control de dispositivos"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Engadir a favoritos"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suxeriu que se engada este control aos teus favoritos."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Actualizáronse os controis"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index f781c3f542ea..b0ebf7afa03e 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"વિસ્તૃતીકરણ ઓવરલે વિંડો"</string> <string name="magnification_window_title" msgid="4863914360847258333">"વિસ્તૃતીકરણ વિંડો"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"વિસ્તૃતીકરણ વિંડોના નિયંત્રણો"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"ઝડપી નિયંત્રણો"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ડિવાઇસનાં નિયંત્રણો"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"તમારા કનેક્ટ કરેલા ડિવાઇસ માટે નિયંત્રણો ઉમેરો"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"ઝડપી નિયંત્રણો સેટઅપ કરો"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"ડિવાઇસનાં નિયંત્રણો સેટઅપ કરો"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"તમારા નિયંત્રણોને ઍક્સેસ કરવા માટે પાવર બટન દબાવી રાખો"</string> <string name="controls_providers_title" msgid="6879775889857085056">"નિયંત્રણો ઉમેરવા માટે ઍપ પસંદ કરો"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"નિયંત્રણો"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"પાવર મેનૂમાંથી ઍક્સેસ કરવા માટેના નિયંત્રણોને પસંદ કરો"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"નિયંત્રણને ખસેડવા માટે તેના પર આંગળી દબાવીને ખેંચો"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"બધા નિયંત્રણોની સૂચિ લોડ કરી શકાઈ નથી."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"અન્ય"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"ઝડપી નિયંત્રણોમાં ઉમેરો"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"ડિવાઇસનાં નિયંત્રણોમાં ઉમેરો"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"મનપસંદમાં ઉમેરો"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> એ આ નિયંત્રણને તમારા મનપસંદમાં ઉમેરવાનું સૂચવ્યું છે."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"નિયંત્રણ અપડેટ કર્યા"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 107edb8ae716..cdfa4f723227 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"अनुमति दें"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB डीबगिंग की अनुमति नहीं है"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"अभी इस डिवाइस में जिस उपयोगकर्ता ने साइन इन किया है, वो USB डीबगिंग चालू नहीं कर सकता. इस सुविधा का इस्तेमाल करने के लिए, प्राथमिक उपयोगकर्ता में बदलें."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"क्या आप इस नेटवर्क पर वायरलेस तरीके से डीबग करने की सुविधा के इस्तेमाल की अनुमति देना चाहते हैं?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"क्या आप इस नेटवर्क पर वॉयरलेस डीबगिंग की सुविधा के इस्तेमाल की अनुमति देना चाहते हैं?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"नेटवर्क का नाम (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nवाई-फ़ाई का पता (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"इस नेटवर्क पर हमेशा अनुमति दें"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"अनुमति दें"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"वायरलेस तरीके से डीबग करने की सुविधा चालू करने की अनुमति नहीं है"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"अभी इस डिवाइस में जिस उपयोगकर्ता ने साइन इन कर रखा है वह वायरलेस तरीके से डीबग करने की सुविधा चालू नहीं कर सकता. इस सुविधा का इस्तेमाल करने के लिए, मुख्य उपयोगकर्ता के तौर पर साइन इन करें."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"वॉयरलेस डीबगिंग की सुविधा चालू करने की अनुमति नहीं है"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"अभी इस डिवाइस में जिस उपयोगकर्ता ने साइन इन कर रखा है वह वॉयरलेस डीबगिंग की सुविधा चालू नहीं कर सकता. इस सुविधा का इस्तेमाल करने के लिए, मुख्य उपयोगकर्ता के तौर पर साइन इन करें."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"यूएसबी पोर्ट बंद है"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"तरल चीज़ या कचरे से आपके डिवाइस की सुरक्षा करने के लिए, यूएसबी पोर्ट को बंद कर दिया गया है. साथ ही, इससे किसी भी एक्सेसरी की पहचान नहीं की जा सकेगी.\n\nयूएसबी पोर्ट का दोबारा इस्तेमाल करना सुरक्षित होने पर आपको सूचित किया जाएगा."</string> <string name="usb_port_enabled" msgid="531823867664717018">"चार्जर और एक्सेसरी पहचानने के लिए यूएसबी पोर्ट को चालू कर दिया गया है"</string> @@ -743,7 +743,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"आवाज़ और वाइब्रेशन बंद किया गया"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"आवाज़ या वाइब्रेशन चालू करें"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"बबल दिखाएं"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"बबल हटाएं"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"बबल्स हटाएं"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"होम स्क्रीन पर जोड़ें"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"सूचना नियंत्रण"</string> @@ -985,7 +985,7 @@ <string name="device_services" msgid="1549944177856658705">"डिवाइस सेवाएं"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"कोई शीर्षक नहीं"</string> <string name="restart_button_description" msgid="6916116576177456480">"इस ऐप्लिकेशन को रीस्टार्ट करने और फ़ुल स्क्रीन चालू करने के लिए टैप करें."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> बबल की सेटिंग"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> बबल्स की सेटिंग"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"प्रबंधित करें"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> से <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> और <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> अन्य ऐप्लिकेशन से <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -1007,9 +1007,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification Overlay Window"</string> <string name="magnification_window_title" msgid="4863914360847258333">"स्क्रीन को बड़ा करके दिखाने वाली विंडो"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"स्क्रीन को बड़ा करके दिखाने वाली विंडो के नियंत्रण"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"क्विक कंट्रोल"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"डिवाइस के कंट्रोल"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"कनेक्ट किए गए डिवाइस के लिए कंट्रोल जोड़ें"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"क्विक कंट्रोल सेट अप करें"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"डिवाइस के कंट्रोल सेट अप करें"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"कंट्रोल ऐक्सेस करने के लिए पावर बटन को दबाकर रखें"</string> <string name="controls_providers_title" msgid="6879775889857085056">"कंट्रोल जोड़ने के लिए ऐप्लिकेशन चुनें"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1018,10 +1018,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"कंट्राेल"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"पावर मेन्यू से ऐक्सेस करने के लिए कंट्रोल चुनें"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"किसी कंट्रोल को एक जगह से दूसरी जगह ले जाने के लिए, इसे दबाकर खींचें और छोड़ें"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"सभी कंट्रोल की सूची लोड नहीं हो सकी."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"\'फटाफट कंट्रोल\' में जोड़ें"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"डिवाइस के कंट्रोल में जोड़ें"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"पसंदीदा में जोड़ें"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> आपको इस कंट्रोल को अपनी पसंदीदा में जोड़ने का सुझाव देता है."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"कंट्रोल अपडेट किए गए"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 338eb63118c9..fd4aa6c296ff 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -1010,9 +1010,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Prozor preklapanja povećavanja"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Prozor za povećavanje"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za povećavanje"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Brze kontrole"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Upravljanje uređajem"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodavanje kontrola za povezane uređaje"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Postavljanje brzih kontrola"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Postavljanje kontrola uređaja"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Dulje pritisnite tipku za uključivanje/isključivanje da biste pristupili kontrolama"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Odabir aplikacije za dodavanje kontrola"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1022,10 +1022,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrole"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Odaberite kontrole kojima želite pristupati iz izbornika napajanja"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Zadržite i povucite kontrolu da biste je pomaknuli"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Popis svih kontrola nije se učitao."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Dodavanje u brze kontrole"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Dodavanje kontrolama uređaja"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Dodaj u favorite"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikacija <xliff:g id="APP">%s</xliff:g> predlaže dodavanje ove kontrole u vaše favorite."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrole su ažurirane"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 78458be81dd0..76c344546a1a 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -223,7 +223,7 @@ <string name="data_connection_lte" msgid="557021044282539923">"LTE"</string> <string name="data_connection_lte_plus" msgid="4799302403782283178">"LTE+"</string> <string name="data_connection_cdma" msgid="7678457855627313518">"1X"</string> - <string name="data_connection_roaming" msgid="375650836665414797">"Barangolás"</string> + <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string> <string name="data_connection_edge" msgid="6316755666481405762">"EDGE"</string> <string name="accessibility_data_connection_wifi" msgid="4422160347472742434">"Wi-Fi"</string> <string name="accessibility_no_sim" msgid="1140839832913084973">"Nincs SIM."</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Nagyítási fedvény ablaka"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Nagyítás ablaka"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Nagyítási vezérlők ablaka"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Gyorsvezérlők"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Eszközvezérlők"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Vezérlők hozzáadása a csatlakoztatott eszközökhöz"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Gyorsvezérlők beállítása"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Eszközvezérlők beállítása"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Tartsa nyomva a bekapcsológombot, hogy hozzáférhessen a vezérlőkhöz"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Válasszon alkalmazást a vezérlők hozzáadásához"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Vezérlők"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"A bekapcsológomb menüjéből hozzáférhető vezérlők kiválasztása"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Áthelyezéséhez tartsa nyomva, majd húzza a kívánt helyre a vezérlőt"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Nem sikerült betölteni az összes vezérlő listáját."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Más"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Hozzáadás a gyorsvezérlőkhöz"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Hozzáadás az eszközvezérlőkhöz"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Hozzáadás a kedvencekhez"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"A(z) <xliff:g id="APP">%s</xliff:g> azt javasolta, hogy adja hozzá ezt a vezérlőt a kedvenceihez."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Vezérlők frissítve"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index e42ccc5991e1..d625bb3fde1e 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Խոշորացման պատուհանի վրադրում"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Խոշորացման պատուհան"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Խոշորացման պատուհանի կառավարման տարրեր"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Արագ կառավարման տարրեր"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Սարքի կառավարման տարրեր"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Ավելացրեք կառավարման տարրեր ձեր միացված սարքերի համար"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Արագ կառավարման տարրերի կարգավորում"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Սարքի կառավարման տարրերի կարգավորում"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Սեղմած պահեք սնուցման կոճակը՝ կառավարման տարրերը բացելու համար"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Ընտրեք հավելված` կառավարման տարրեր ավելացնելու համար"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Կառավարման տարրեր"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Ընտրեք կառավարման տարրերը՝ դրանք սնուցման ընտրացանկից բացելու համար"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Կառավարման տարրը տեղափոխելու համար պահեք և քաշեք այն"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Պահեք և քաշեք՝ կառավարման տարրերը վերադասավորելու համար"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"Կառավարման բոլոր տարրերը հեռացվեցին"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Չհաջողվեց բեռնել բոլոր կառավարների ցանկը։"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Այլ"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Ավելացրեք արագ կառավարման տարրերում"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Ավելացրեք սարքի կառավարման տարրերում"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Ավելացնել ընտրանիում"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> հավելվածն առաջարկում է ավելացնել այս կառավարը ձեր ընտրանիում։"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Կառավարման տարրերը թարմացվեցին"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 2cd79d78f568..3f6cbb472b8f 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -406,7 +406,7 @@ <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lampu Senter"</string> <string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Kamera sedang digunakan"</string> <string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Data seluler"</string> - <string name="quick_settings_cellular_detail_data_usage" msgid="6105969068871138427">"Penggunaan kuota"</string> + <string name="quick_settings_cellular_detail_data_usage" msgid="6105969068871138427">"Penggunaan data"</string> <string name="quick_settings_cellular_detail_remaining_data" msgid="1136599216568805644">"Data tersisa"</string> <string name="quick_settings_cellular_detail_over_limit" msgid="4561921367680636235">"Melebihi batas"</string> <string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> digunakan"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Jendela Overlay Pembesaran"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Jendela Pembesaran"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Kontrol Jendela Pembesaran"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Kontrol cepat"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kontrol perangkat"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Tambahkan kontrol untuk perangkat terhubung"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Siapkan kontrol cepat"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Siapkan kontrol perangkat"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Tahan tombol Daya untuk mengakses kontrol"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Pilih aplikasi untuk menambahkan kontrol"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrol"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Pilih kontrol yang akan diakses dari menu daya"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Tahan dan tarik kontrol untuk memindahkannya"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Daftar semua kontrol tidak dapat dimuat."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lainnya"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Tambahkan ke kontrol cepat"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Tambahkan ke kontrol perangkat"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Tambahkan ke favorit"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> menyarankan kontrol ini ditambahkan ke favorit."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrol diperbarui"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 803d99493c8c..2dad05035ee2 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Forritið eða fyrirtækið þitt leyfir ekki skjámyndatöku"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Loka skjámynd"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Opna skjámynd"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Upptökutæki á skjá"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Skjáupptaka"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Áframhaldandi tilkynning fyrir skjáupptökulotu"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Hefja upptöku?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Á meðan tekið er upp getur Android kerfið fangað viðkvæmar upplýsingar sem sjást á skjánum eða spilast í tækinu. Þar á meðal eru upplýsingar á borð við aðgangsorð, greiðsluupplýsingar, myndir, skilaboð og hljóð."</string> @@ -993,7 +993,7 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Færa neðst til vinstri"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Færðu neðst til hægri"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Hunsa"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ekki setja samtöl í blöðrur"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ekki setja samtal í blöðru"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Spjalla með blöðrum"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Ný samtöl birtast sem fljótandi tákn eða blöðrur. Ýttu til að opna blöðru. Dragðu hana til að færa."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Hægt er að stjórna blöðrum hvenær sem er"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Stækkun yfirglugga"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Stækkunargluggi"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Stækkunarstillingar glugga"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Flýtistýringar"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Tækjastýringar"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Bæta við stýringum fyrir tengd tæki"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Setja upp flýtistýringar"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Setja upp tækjastýringar"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Haltu inni aflrofanum til að sjá stýringarnar þínar"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Veldu forrit til að bæta við stýringum"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Stýringar"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Veldu hvaða stýringar birtast í aflrofavalmyndinni"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Haltu og dragðu stýringu til að færa hana"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Ekki tókst að hlaða lista yfir allar stýringar."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annað"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Bæta við flýtistýringar"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Bæta við tækjastýringar"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Bæta við uppáhald"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> stakk upp á að bæta þessari stýringu við uppáhald."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Stýringar uppfærðar"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 875bc4f39cc7..587e94be88e7 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'acquisizione di screenshot non è consentita dall\'app o dall\'organizzazione"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ignora screenshot"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Apri screenshot"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Registrazione dello schermo"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifica costante per una sessione di registrazione dello schermo"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Avviare la registrazione?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Durante la registrazione, il sistema Android può catturare dati sensibili visibili sullo schermo o riprodotti sul tuo dispositivo. Sono incluse password, dati di pagamento, foto, messaggi e audio."</string> @@ -362,7 +362,7 @@ <string name="quick_settings_rotation_locked_portrait_label" msgid="1194988975270484482">"Verticale"</string> <string name="quick_settings_rotation_locked_landscape_label" msgid="2000295772687238645">"Orizzontale"</string> <string name="quick_settings_ime_label" msgid="3351174938144332051">"Metodo di immissione"</string> - <string name="quick_settings_location_label" msgid="2621868789013389163">"Geolocalizz."</string> + <string name="quick_settings_location_label" msgid="2621868789013389163">"Geolocalizzazione"</string> <string name="quick_settings_location_off_label" msgid="7923929131443915919">"Geolocalizz. non attiva"</string> <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimediale"</string> <string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"Silenziata"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Avvisi"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"Mostra fumetto"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Rimuovi fumetti"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Rimuovi bolle"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Aggiungi a schermata Home"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"gestione delle notifiche"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"Servizi del dispositivo"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Senza titolo"</string> <string name="restart_button_description" msgid="6916116576177456480">"Tocca per riavviare l\'app e passare a schermo intero."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Impostazioni per fumetti <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Impostazioni per bolle <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"Gestisci"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g> e altre <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Finestra overlay ingrandimento"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Finestra ingrandimento"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Finestra controlli di ingrandimento"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Controlli rapidi"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controlli del dispositivo"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Aggiungi controlli per i dispositivi connessi"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Configura controlli rapidi"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configura i controlli del dispositivo"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Tieni premuto il tasto di accensione per accedere ai controlli"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Scegli un\'app per aggiungere controlli"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controlli"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Seleziona i controlli a cui accedere dal menu di accensione"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Tieni premuto un controllo e trascinalo per spostarlo"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossibile caricare l\'elenco di tutti i controlli."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altro"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Aggiungi ai controlli rapidi"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Aggiungi ai controlli del dispositivo"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Aggiungi ai preferiti"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ha suggerito di aggiungere questo controllo ai preferiti."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controlli aggiornati"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 0d9f8391bccf..b6f445d670f0 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"האפליקציה או הארגון שלך אינם מתירים ליצור צילומי מסך"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"סגירת צילום מסך"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"פתיחת צילום מסך"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"מקליט מסך"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"מקליט המסך"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"התראה מתמשכת לסשן הקלטת מסך"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"להתחיל את ההקלטה?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"בזמן ההקלטה, מערכת Android יכולה לתעד מידע רגיש שגלוי במסך או מופעל במכשיר שלך. מידע זה כולל סיסמאות, פרטי תשלום, תמונות, הודעות ואודיו."</string> @@ -1015,9 +1015,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"חלון ליצירת שכבת-על להגדלה"</string> <string name="magnification_window_title" msgid="4863914360847258333">"חלון הגדלה"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"בקרות של חלון ההגדלה"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"פקדים מהירים"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"פקדי המכשיר"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"יש להוסיף פקדים למכשירים המחוברים"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"הגדרה של פקדים מהירים"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"הגדרה של פקדי המכשיר"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"יש ללחוץ לחיצה ארוכה על לחצן ההפעלה כדי לגשת לבקרים"</string> <string name="controls_providers_title" msgid="6879775889857085056">"יש לבחור אפליקציה כדי להוסיף פקדים"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1028,10 +1028,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"פקדים"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"יש לבחור פקדים לגישה מתפריט ההפעלה"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"כדי להזיז פקד, יש ללחוץ עליו ולגרור אותו"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"לא ניתן היה לטעון את הרשימה של כל הפקדים."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"אחר"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"הוספה לפקדים מהירים"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"הוספה לפקדי המכשיר"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"הוספה למועדפים"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"בקרה זו הוצעה על ידי <xliff:g id="APP">%s</xliff:g> להוספה למועדפים."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"הפקדים עודכנו"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 41888fdeef9c..8a2b923d7664 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"スクリーンショットの作成はアプリまたは組織で許可されていません"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"スクリーンショットを閉じます"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"スクリーンショットを開きます"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"画面レコーダー"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"スクリーン レコーダー"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"画面の録画セッション中の通知"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"録画を開始しますか?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"録画中に機密情報が画面に表示されたりデバイスで再生されたりした場合、Android システムでキャプチャされることがあります。これには、パスワード、お支払い情報、写真、メッセージ、音声などが含まれます。"</string> @@ -708,12 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"音やバイブレーションが作動しないため、通知に煩わされずに済みます。"</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"音やバイブレーションで通知をお知らせします。"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"このコンテンツのフローティング ショートカットで通知をお知らせします。"</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"会話セクションの一番上にふきだしとして表示されます。"</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"デフォルトでは <xliff:g id="APP_NAME_0">%1$s</xliff:g> からのすべての会話がふきだしで表示されます。[<xliff:g id="APP_NAME_1">%2$s</xliff:g>] で管理します。"</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"会話セクションの一番上にバブルとして表示されます。"</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"デフォルトでは <xliff:g id="APP_NAME_0">%1$s</xliff:g> からのすべての会話がバブルで表示されます。[<xliff:g id="APP_NAME_1">%2$s</xliff:g>] で管理します。"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string> <string name="notification_priority_title" msgid="2079708866333537093">"優先度"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近閉じたふきだしはありません"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近表示されたふきだしや閉じたふきだしが、ここに表示されます"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近閉じたバブルはありません"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近表示されたバブルや閉じたバブルが、ここに表示されます"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"これらの通知は変更できません。"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"このグループの通知はここでは設定できません"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"代理通知"</string> @@ -740,8 +740,8 @@ <string name="notification_conversation_unfavorite" msgid="181383708304763807">"重要でない会話"</string> <string name="notification_conversation_mute" msgid="268951550222925548">"マナーモード"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"アラートを受け取る"</string> - <string name="notification_conversation_bubble" msgid="2242180995373949022">"ふきだしを表示"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"ふきだしを削除"</string> + <string name="notification_conversation_bubble" msgid="2242180995373949022">"バブルを表示"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"バブルを削除"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"ホーム画面に追加"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"通知管理"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"デバイス サービス"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"タイトルなし"</string> <string name="restart_button_description" msgid="6916116576177456480">"タップしてこのアプリを再起動すると、全画面表示になります。"</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> のふきだしの設定"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> のバブルの設定"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"管理"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)、他 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 件"</string> @@ -993,10 +993,10 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"左下に移動"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"右下に移動"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"閉じる"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"会話をふきだしにしない"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"チャットでのふきだしの使用"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"新しい会話はフローティング アイコン(ふきだし)として表示されます。タップするとふきだしが開きます。ドラッグしてふきだしを移動できます。"</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"いつでもふきだしを管理"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"会話をバブルにしない"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"チャットでのバブルの使用"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"新しい会話はフローティング アイコン(バブル)として表示されます。タップするとバブルが開きます。ドラッグしてバブルを移動できます。"</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"いつでもバブルを管理"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"このアプリからのバブルをオフにするには、[管理] をタップしてください"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"システム ナビゲーションを更新しました。変更するには [設定] に移動してください。"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"拡大オーバーレイ ウィンドウ"</string> <string name="magnification_window_title" msgid="4863914360847258333">"拡大ウィンドウ"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"拡大ウィンドウ コントロール"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"クイック コントロール"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"デバイス コントロール"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"接続済みデバイスのコントロールを追加します"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"クイック コントロールの設定"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"デバイス コントロールの設定"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"コントロールにアクセスするには、電源ボタンを長押しします"</string> <string name="controls_providers_title" msgid="6879775889857085056">"コントロールを追加するアプリの選択"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"コントロール"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"電源メニューからアクセスするコントロールを選択する"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"コントロールを移動するには、長押してドラッグします"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"コントロールを並べ替えるには長押ししてドラッグします"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"すべてのコントロールを削除しました"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"全コントロールの一覧を読み込めませんでした。"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"その他"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"クイック コントロールへの追加"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"デバイス コントロールに追加"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"お気に入りに追加"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g>が、お気に入りに追加のためにこのコントロールを提案しました。"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"コントロールを更新しました"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 2097892ceba4..99b10c10cb2b 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ეკრანის ანაბეჭდების შექმნა არ არის ნებადართული აპის ან თქვენი ორგანიზაციის მიერ"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ეკრანის ანაბეჭდის დახურვა"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"ეკრანის ანაბეჭდის გახსნა"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"ეკრანის რეკორდერი"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"ეკრანის ჩამწერი"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"უწყვეტი შეტყობინება ეკრანის ჩაწერის სესიისთვის"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"დაიწყოს ჩაწერა?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"ჩაწერის განმავლობაში Android სისტემას შეუძლია აღბეჭდოს ნებისმიერი სენსიტიური ინფორმაცია, რომელიც თქვენს ეკრანზე გამოჩნდება ან თქვენს მოწყობილობაზე დაიკვრება. აღნიშნული მოიცავს პაროლებს, გადახდის დეტალებს, ფოტოებს, შეტყობინებებსა და აუდიოს."</string> @@ -509,7 +509,7 @@ <string name="manage_notifications_history_text" msgid="57055985396576230">"ისტორია"</string> <string name="notification_section_header_gentle" msgid="3044910806569985386">"ჩუმი შეტყობინებები"</string> <string name="notification_section_header_alerting" msgid="3168140660646863240">"გამაფრთხილებელი შეტყობინებები"</string> - <string name="notification_section_header_conversations" msgid="821834744538345661">"მიმოწერები"</string> + <string name="notification_section_header_conversations" msgid="821834744538345661">"საუბრები"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ყველა ჩუმი შეტყობინების გასუფთავება"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"შეტყობინებები დაპაუზდა „არ შემაწუხოთ“ რეჟიმის მეშვეობით"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"დაწყება ახლავე"</string> @@ -708,8 +708,8 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"გეხმარებათ ფოკუსირებაში ხმის ან ვიბრაციის უქონლობის გამო."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"იპყრობს თქვენს ყურადღებას ხმით ან ვიბრაციით."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"იპყრობს თქვენს ყურადღებას ამ კონტენტის მოლივლივე მალსახმობით."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"გამოჩნდება მიმოწერის სექციის ზედა ნაწილში ბუშტის სახით."</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"ყველა მიმოწერა <xliff:g id="APP_NAME_0">%1$s</xliff:g>-დან ნაგულისხმევად გამოჩნდება ბუშტის სახით. <xliff:g id="APP_NAME_1">%2$s</xliff:g>-ში მართვა."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"გამოჩნდება საუბრის სექციის ზედა ნაწილში ბუშტის სახით."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"ყველა საუბარი <xliff:g id="APP_NAME_0">%1$s</xliff:g>-დან ნაგულისხმევად გამოჩნდება ბუშტის სახით. <xliff:g id="APP_NAME_1">%2$s</xliff:g>-ში მართვა."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"პარამეტრები"</string> <string name="notification_priority_title" msgid="2079708866333537093">"პრიორიტეტი"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ბოლო დროს გამოყენებული ბუშტები არ არის"</string> @@ -993,9 +993,9 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ქვევით და მარცხნივ გადატანა"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"გადაანაცვ. ქვემოთ და მარჯვნივ"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"დახურვა"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"აიკრძალოს მიმოწერის ბუშტები"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"აიკრძალოს საუბრის ბუშტები"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"ჩეთი ბუშტების გამოყენებით"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"ახალი მიმოწერები გამოჩნდება როგორც მოტივტივე ხატულები ან ბუშტები. შეეხეთ ბუშტის გასახსნელად. გადაიტანეთ ჩავლებით."</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"ახალი საუბრები გამოჩნდება როგორც მოტივტივე ხატულები ან ბუშტები. შეეხეთ ბუშტის გასახსნელად. გადაიტანეთ ჩავლებით."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ბუშტების ნებისმიერ დროს გაკონტროლება"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ამ აპის ბუშტების გამოსართავად შეეხეთ „მართვას“"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"გასაგებია"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"გადიდების გადაფარვის ფანჯარა"</string> <string name="magnification_window_title" msgid="4863914360847258333">"გადიდების ფანჯარა"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"გადიდების კონტროლის ფანჯარა"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"სწრაფად მართვის საშუალებები"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"მოწყობილ. მართვის საშუალებები"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"მართვის საშუალებების დამატება თქვენს დაკავშირებულ მოწყობილობებზე"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"სწრაფად მართვის საშუალებების დაყენება"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"მოწყობილობის მართვის საშუალებების დაყენება"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"ხანგრძლივად დააჭირეთ ჩართვის ღილაკს მართვის საშუალებებზე წვდომისთვის"</string> <string name="controls_providers_title" msgid="6879775889857085056">"აირჩიეთ აპი მართვის საშუალებების დასამატებლად"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"მართვის საშუალებები"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"აირჩიეთ მართვის საშუალებები ელკვების მენიუდან"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"ჩავლებით გადაიტანეთ კონტროლის საშუალება"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"მართვის ყველა საშუალების სია ვერ ჩაიტვირთა."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"სხვა"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"სწრაფად მართვის საშ. დამატება"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"მოწყობილ. მართვის საშუალებებში დამატება"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"რჩეულებში დამატება"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> გთავაზობთ, მართვის ეს საშუალება თქვენს რჩეულებში დაამატოთ."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"მართვის საშუალებები განახლდა"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 6fc5ff3cf440..dd8ecc40e1f1 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Қолданба немесе ұйым скриншоттар түсіруге рұқсат етпейді"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Скриншотты жабу"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Скриншотты ашу"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Экрандағы бейнені жазу"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Экран жазғыш"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды бейнеге жазудың ағымдағы хабарландыруы"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Жазу басталсын ба?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Жазу кезінде Android жүйесі экранда көрсетілетін немесе құрылғыда ойнатылатын құпия ақпаратты пайдалана алады. Ол ақпаратқа құпия сөздер, төлеу ақпараты, фотосуреттер, хабарлар және аудио жатады."</string> @@ -509,7 +509,7 @@ <string name="manage_notifications_history_text" msgid="57055985396576230">"Тарих"</string> <string name="notification_section_header_gentle" msgid="3044910806569985386">"Дыбыссыз хабарландырулар"</string> <string name="notification_section_header_alerting" msgid="3168140660646863240">"Ескертуші хабарландлырулар"</string> - <string name="notification_section_header_conversations" msgid="821834744538345661">"Сөйлесулер"</string> + <string name="notification_section_header_conversations" msgid="821834744538345661">"Әңгімелер"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Барлық дыбыссыз хабарландыруларды өшіру"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Хабарландырулар \"Мазаламау\" режимінде кідіртілді"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Қазір бастау"</string> @@ -708,12 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"Хабарландырулар келгенде, дыбыс шықпайды не дірілдемейді"</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"Хабарландырулар келгенде, дыбыс шығады не дірілдейді"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Осы мазмұнға бекітілген қалқымалы таңбашамен назарыңызды өзіне тартады."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Чат бөлімінің жоғарғы жағында және қалқымалы хабар түрінде көрсетіледі."</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> хабарлары әдепкісінше көрсетіледі. <xliff:g id="APP_NAME_1">%2$s</xliff:g> арқылы басқарыңыз."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Сөйлесу бөлімінің жоғарғы жағында және қалқыма хабар түрінде көрсетіледі."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Барлық <xliff:g id="APP_NAME_0">%1$s</xliff:g> әңгімесінің қалқыма хабарлары әдепкісінше көрсетіледі. <xliff:g id="APP_NAME_1">%2$s</xliff:g> арқылы басқарыңыз."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Параметрлер"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Маңыздылығы"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Жақындағы қалқымалы анықтамалар жоқ"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Жақында ашылған және жабылған қалқымалы хабарлар осы жерде көрсетіледі."</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Жақындағы қалқыма хабарлар жоқ"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Жақында ашылған және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Мұндай хабарландырулар бұл жерде конфигурацияланбайды."</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Прокси-сервер арқылы жіберілген хабарландыру"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"Үнсіз режимге қойылған."</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Дыбысын қосу"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"Қалқымалы анықтаманы көрсету"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Қалқымалы анықтамаларды өшіру"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Қалқыма хабарларды өшіру"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Негізгі экранға қосу"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"хабарландыруларды басқару элементтері"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"Құрылғы қызметтері"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Атауы жоқ"</string> <string name="restart_button_description" msgid="6916116576177456480">"Бұл қолданбаны қайта қосып, толық экранға өту үшін түртіңіз."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> қалқымалы анықтамаларының параметрлері"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> қалқыма хабарларының параметрлері"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"Басқару"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> жіберген хабарландыру: <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасы жіберген <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> және тағы <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string> @@ -993,11 +993,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Төменгі сол жаққа жылжыту"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Төменгі оң жаққа жылжыту"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабу"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Қалқымалы хабар көрсетілмесін"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Сөйлесуге арналған қалқымалы хабарлар"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңа чаттар қалқымалы белгішелер немесе хабарлар түрінде көрсетіледі. Қалқымалы хабарды ашу үшін түртіңіз. Жылжыту үшін сүйреңіз."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Қалқымалы хабарларды реттеу"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бұл қолданбадан қалқымалы анықтамаларды өшіру үшін \"Басқару\" түймесін түртіңіз."</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Әңгіменің қалқыма хабары көрсетілмесін"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Сөйлесуге арналған қалқыма хабарлар"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңа әңгімелер қалқыма белгішелер немесе хабарлар түрінде көрсетіледі. Қалқыма хабарды ашу үшін түртіңіз. Жылжыту үшін сүйреңіз."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Қалқыма хабарларды реттеу"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бұл қолданбадан қалқыма хабарларды өшіру үшін \"Басқару\" түймесін түртіңіз."</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Түсінікті"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Жүйе навигациясы жаңартылды. Өзгерту енгізу үшін \"Параметрлер\" бөліміне өтіңіз."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Жүйе навигациясын жаңарту үшін \"Параметрлер\" бөліміне өтіңіз."</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Ұлғайту терезесін қабаттастыру"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Ұлғайту терезесі"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Ұлғайту терезесінің басқару элементтері"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Жылдам басқару элементтері"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Құрылғыны басқару элементтері"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Жалғанған құрылғыларға басқару элементтерін енгізу"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Жылдам басқару элементтерін реттеу"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Құрылғыны басқару элементтерін реттеу"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Басқару элементтерін шығару үшін қуат түймесін басып тұрыңыз."</string> <string name="controls_providers_title" msgid="6879775889857085056">"Басқару элементтері енгізілетін қолданбаны таңдаңыз"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Басқару элементтері"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"\"Қуат\" мәзірінен пайдалануға болатын басқару элементтерін таңдаңыз."</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Басқару элементін жылжыту үшін оны басып тұрып, сүйреңіз."</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Барлық басқару элементі тізімі жүктелмеді."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Басқа"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Жылдам басқару элементтеріне қосу"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Құрылғыны басқару элементтеріне қосу"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Таңдаулыларға қосу"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> қолданбасы бұл басқару элементін таңдаулыларға қосып қоюды ұсынды."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Басқару элементтері жаңартылды"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index a6f993e500b3..53e9c0eb8d13 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ការថតរូបអេក្រង់មិនត្រូវបានអនុញ្ញាតដោយកម្មវិធីនេះ ឬស្ថាប័នរបស់អ្នក"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ច្រានចោលរូបថតអេក្រង់"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"បើករូបថតអេក្រង់"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"កម្មវិធីថតអេក្រង់"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"មុខងារថតអេក្រង់"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"ការជូនដំណឹងដែលកំពុងដំណើរការសម្រាប់រយៈពេលប្រើការថតសកម្មភាពអេក្រង់"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"ចាប់ផ្តើមថតឬ?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"នៅពេលកំពុងថត ប្រព័ន្ធ Android អាចថតព័ត៌មានរសើបដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬដែលបានចាក់នៅលើឧបករណ៍របស់អ្នក។ ព័ត៌មាននេះរួមមានពាក្យសម្ងាត់ ព័ត៌មានអំពីការបង់ប្រាក់ រូបថត សារ និងសំឡេង។"</string> @@ -708,12 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"ជួយឱ្យអ្នកផ្តោតអារម្មណ៍ ដោយមិនឮសំឡេង ឬការញ័រ។"</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"ធ្វើឱ្យអ្នកចាប់អារម្មណ៍តាមរយៈសំឡេង ឬការញ័រ។"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ធ្វើឱ្យអ្នកចាប់អារម្មណ៍ដោយប្រើផ្លូវកាត់អណ្ដែតសម្រាប់ខ្លឹមសារនេះ។"</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"បង្ហាញនៅខាងលើផ្នែកនៃការសន្ទនា និងបង្ហាញជាសារលេចឡើង។"</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"ការសន្ទនាទាំងអស់ពី <xliff:g id="APP_NAME_0">%1$s</xliff:g> បង្ហាញជាសារលេចឡើងតាមលំនាំដើម។ គ្រប់គ្រងនៅក្នុង <xliff:g id="APP_NAME_1">%2$s</xliff:g>។"</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"បង្ហាញនៅខាងលើផ្នែកសន្ទនា និងបង្ហាញជាពពុះ។"</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"ការសន្ទនាទាំងអស់ពី <xliff:g id="APP_NAME_0">%1$s</xliff:g> បង្ហាញជាពពុះតាមលំនាំដើម។ គ្រប់គ្រងនៅក្នុង <xliff:g id="APP_NAME_1">%2$s</xliff:g>។"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ការកំណត់"</string> <string name="notification_priority_title" msgid="2079708866333537093">"អាទិភាព"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"មិនមានសារលេចឡើងថ្មីៗទេ"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"សារលេចឡើងដែលបានច្រានចោល និងសារលេចឡើងថ្មីៗនឹងបង្ហាញនៅទីនេះ"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"មិនមានពពុះថ្មីៗទេ"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ពពុះថ្មីៗ និងពពុះដែលបានបិទនឹងបង្ហាញនៅទីនេះ"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"មិនអាចកែប្រែការជូនដំណឹងទាំងនេះបានទេ។"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"មិនអាចកំណត់រចនាសម្ព័ន្ធក្រុមការជូនដំណឹងនេះនៅទីនេះបានទេ"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"ការជូនដំណឹងជាប្រូកស៊ី"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"បានបិទសំឡេង"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"បញ្ចេញសំឡេង"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"បង្ហាញជាសារលេចឡើង"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"លុបសារលេចឡើង"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"លុបពពុះ"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"បញ្ចូលទៅក្នុងអេក្រង់ដើម"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"ការគ្រប់គ្រងការជូនដំណឹង"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"សេវាកម្មឧបករណ៍"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"គ្មានចំណងជើង"</string> <string name="restart_button_description" msgid="6916116576177456480">"ចុចដើម្បីចាប់ផ្ដើមកម្មវិធីនេះឡើងវិញ រួចចូលប្រើពេញអេក្រង់។"</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"ការកំណត់សម្រាប់សារលេចឡើង <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"ការកំណត់សម្រាប់ពពុះ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"គ្រប់គ្រង"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g> និង <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ទៀត"</string> @@ -993,11 +993,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ផ្លាស់ទីទៅផ្នែកខាងក្រោមខាងឆ្វេង"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ផ្លាស់ទីទៅផ្នែកខាងក្រោមខាងស្ដាំ"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"ច្រានចោល"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"កុំបង្ហាញការសន្ទនាជាសារលេចឡើង"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"ជជែកដោយប្រើសារលេចឡើង"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"ការសន្ទនាថ្មីៗបង្ហាញជាសារលេចឡើង ឬរូបអណ្ដែត។ ចុច ដើម្បីបើកសារលេចឡើង។ អូស ដើម្បីផ្លាស់ទីសារលេចឡើងនេះ។"</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"គ្រប់គ្រងសារលេចឡើងបានគ្រប់ពេល"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ចុច \"គ្រប់គ្រង\" ដើម្បីបិទសារលេចឡើងពីកម្មវិធីនេះ"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"កុំបង្ហាញការសន្ទនាជាពពុះ"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"ជជែកដោយប្រើពពុះ"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"ការសន្ទនាថ្មីៗបង្ហាញជាពពុះ ឬរូបអណ្ដែត។ ចុច ដើម្បីបើកពពុះ។ អូស ដើម្បីផ្លាស់ទីពពុះនេះ។"</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"គ្រប់គ្រងពពុះបានគ្រប់ពេល"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ចុច \"គ្រប់គ្រង\" ដើម្បីបិទពពុះពីកម្មវិធីនេះ"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"យល់ហើយ"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"បានធ្វើបច្ចុប្បន្នភាពការរុករកក្នុងប្រព័ន្ធ។ ដើម្បីធ្វើការផ្លាស់ប្ដូរ សូមចូលទៅកាន់ការកំណត់។"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ចូលទៅកាន់ការកំណត់ ដើម្បីធ្វើបច្ចុប្បន្នភាពការរុករកក្នុងប្រព័ន្ធ"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"វិនដូត្រួតគ្នាលើការពង្រីក"</string> <string name="magnification_window_title" msgid="4863914360847258333">"វិនដូការពង្រីក"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"វិនដូគ្រប់គ្រងការពង្រីក"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"ការគ្រប់គ្រងរហ័ស"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ការគ្រប់គ្រងឧបករណ៍"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"បញ្ចូលការគ្រប់គ្រងសម្រាប់ឧបករណ៍ដែលបានភ្ជាប់របស់អ្នក"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"រៀបចំការគ្រប់គ្រងរហ័ស"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"រៀបចំការគ្រប់គ្រងឧបករណ៍"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"សង្កត់ប៊ូតុងថាមពលឱ្យជាប់ ដើម្បីចូលប្រើការគ្រប់គ្រងរបស់អ្នក"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ជ្រើសរើសកម្មវិធី ដើម្បីបញ្ចូលការគ្រប់គ្រង"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"ការគ្រប់គ្រង"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"ជ្រើសរើសការគ្រប់គ្រង ដើម្បីចូលប្រើពីម៉ឺនុយថាមពល"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"សង្កត់ និងអូសការគ្រប់គ្រង ដើម្បីផ្លាស់ទីវា"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"មិនអាចផ្ទុកបញ្ជីនៃការគ្រប់គ្រងទាំងអស់បានទេ។"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ផ្សេងៗ"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"បញ្ចូលទៅក្នុងការគ្រប់គ្រងរហ័ស"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"បញ្ចូលទៅក្នុងការគ្រប់គ្រងឧបករណ៍"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"បញ្ចូលទៅក្នុងសំណព្វ"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> បានណែនាំឱ្យបញ្ចូលការគ្រប់គ្រងនេះទៅក្នុងសំណព្វរបស់អ្នក។"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"បានធ្វើបច្ចុប្បន្នភាពការគ្រប់គ្រង"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 5c3dabb46757..3b8d86ec6d1d 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -509,7 +509,7 @@ <string name="manage_notifications_history_text" msgid="57055985396576230">"ಇತಿಹಾಸ"</string> <string name="notification_section_header_gentle" msgid="3044910806569985386">"ನಿಶ್ಶಬ್ಧ ಅಧಿಸೂಚನೆಗಳು"</string> <string name="notification_section_header_alerting" msgid="3168140660646863240">"ಎಚ್ಚರಿಸುವ ಅಧಿಸೂಚನೆಗಳು"</string> - <string name="notification_section_header_conversations" msgid="821834744538345661">"ಸಂವಾದಗಳು"</string> + <string name="notification_section_header_conversations" msgid="821834744538345661">"ಸಂಭಾಷಣೆಗಳು"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ಎಲ್ಲಾ ನಿಶ್ಶಬ್ಧ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಎನ್ನುವ ಮೂಲಕ ಅಧಿಸೂಚನೆಗಳನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"ಈಗ ಪ್ರಾರಂಭಿಸಿ"</string> @@ -712,7 +712,7 @@ <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"ಡೀಫಾಲ್ಟ್ ಆಗಿ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ನ ಎಲ್ಲಾ ಸಂಭಾಷಣೆಗಳನ್ನು ಬಬಲ್ ಆಗಿ ತೋರಿಸಿ. <xliff:g id="APP_NAME_1">%2$s</xliff:g> ನಲ್ಲಿ ನಿರ್ವಹಿಸಿ."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ಆದ್ಯತೆ"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಬಬಲ್ಗಳಿಲ್ಲ"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಇಲ್ಲ"</string> <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಮತ್ತು ವಜಾಗೊಳಿಸಿದ ಬಬಲ್ಸ್ ಇಲ್ಲಿ ಗೋಚರಿಸುತ್ತವೆ"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ಈ ಗುಂಪಿನ ಅಧಿಸೂಚನೆಗಳನ್ನು ಇಲ್ಲಿ ಕಾನ್ಫಿಗರ್ ಮಾಡಲಾಗಿರುವುದಿಲ್ಲ"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"ಮೌನಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"ಎಚ್ಚರಿಸಲಾಗುತ್ತಿದೆ"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"ಬಬಲ್ ತೋರಿಸಿ"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"ಬಬಲ್ಗಳನ್ನು ತೆಗೆದುಹಾಕಿ"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"ಬಬಲ್ಸ್ ಅನ್ನು ತೆಗೆದುಹಾಕಿ"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"ಮುಖಪುಟದ ಪರದೆಗೆ ಸೇರಿಸಿ"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳು"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"ಸಾಧನ ಸೇವೆಗಳು"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"ಯಾವುದೇ ಶೀರ್ಷಿಕೆಯಿಲ್ಲ"</string> <string name="restart_button_description" msgid="6916116576177456480">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲು ಮತ್ತು ಪೂರ್ಣ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ನೋಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಬಬಲ್ಗಳಿಗಾಗಿ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಬಬಲ್ಸ್ಗಾಗಿ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"ನಿರ್ವಹಿಸಿ"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> ಆ್ಯಪ್ನ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> ಮತ್ತು <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ಹೆಚ್ಚಿನವುಗಳ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -997,7 +997,7 @@ <string name="bubbles_user_education_title" msgid="5547017089271445797">"ಬಬಲ್ಸ್ ಬಳಸಿ ಚಾಟ್ ಮಾಡಿ"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"ಹೊಸ ಸಂಭಾಷಣೆಗಳು ತೇಲುವ ಐಕಾನ್ಗಳು ಅಥವಾ ಬಬಲ್ಸ್ ಆಗಿ ಗೋಚರಿಸುತ್ತವೆ. ಬಬಲ್ ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಅದನ್ನು ಡ್ರ್ಯಾಗ್ ಮಾಡಲು ಎಳೆಯಿರಿ."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಬಬಲ್ಸ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ಈ ಆ್ಯಪ್ನಿಂದ ಬಬಲ್ಗಳನ್ನು ಆಫ್ ಮಾಡಲು ನಿರ್ವಹಿಸಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ಈ ಆ್ಯಪ್ನಿಂದ ಬಬಲ್ಸ್ ಅನ್ನು ಆಫ್ ಮಾಡಲು ನಿರ್ವಹಿಸಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ಅರ್ಥವಾಯಿತು"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ ಅಪ್ಡೇಟ್ ಮಾಡಲಾಗಿದೆ ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ್ ಅಪ್ಡೇಟ್ ಮಾಡಲು ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"ವರ್ಧನೆಯ ಓವರ್ಲೇ ವಿಂಡೋ"</string> <string name="magnification_window_title" msgid="4863914360847258333">"ವರ್ಧನೆಯ ವಿಂಡೋ"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"ವರ್ಧನೆಯ ವಿಂಡೋ ನಿಯಂತ್ರಣಗಳು"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"ತ್ವರಿತ ನಿಯಂತ್ರಣಗಳು"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳು"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"ನಿಮ್ಮ ಸಂಪರ್ಕಿತ ಸಾಧನಗಳಿಗೆ ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"ತ್ವರಿತ ನಿಯಂತ್ರಣಗಳನ್ನು ಹೊಂದಿಸಿ"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳನ್ನು ಸೆಟಪ್ ಮಾಡಿ"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"ನಿಮ್ಮ ನಿಯಂತ್ರಣಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ಪವರ್ ಬಟನ್ ಅನ್ನು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"ನಿಯಂತ್ರಣಗಳು"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"ಪವರ್ ಮೆನುವಿನಿಂದ ಪ್ರವೇಶಿಸಲು ನಿಯಂತ್ರಣಗಳನ್ನು ಆರಿಸಿ"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"ಅದನ್ನು ಸರಿಸಲು ನಿಯಂತ್ರಣವೊಂದನ್ನು ಹಿಡಿದುಕೊಂಡು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"ಎಲ್ಲಾ ನಿಯಂತ್ರಣಗಳ ಪಟ್ಟಿಯನ್ನು ಲೋಡ್ ಮಾಡಲು ಆಗಲಿಲ್ಲ."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ಇತರ"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"ತ್ವರಿತ ನಿಯಂತ್ರಣಗಳಿಗೆ ಸೇರಿಸಿ"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳಿಗೆ ಸೇರಿಸಿ"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"ಮೆಚ್ಚಿನವುಗಳಿಗೆ ಸೇರಿಸಿ"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"ಈ ನಿಯಂತ್ರಣವನ್ನು ನಿಮ್ಮ ಮೆಚ್ಚಿನವುಗಳಿಗೆ ಸೇರಿಸಲು <xliff:g id="APP">%s</xliff:g> ಸೂಚಿಸಿದೆ."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"ನಿಯಂತ್ರಣಗಳನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index a72fe1ad8257..daa827864755 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -708,12 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"소리나 진동 없이 집중할 수 있도록 도와줍니다"</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"소리나 진동으로 알립니다."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"이 콘텐츠로 연결되는 플로팅 바로가기로 사용자의 주의를 끕니다."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"대화 섹션 상단에 버블로 표시"</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"기본적으로 <xliff:g id="APP_NAME_0">%1$s</xliff:g>의 모든 대화가 버블로 표시됩니다. <xliff:g id="APP_NAME_1">%2$s</xliff:g>에서 관리하세요."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"대화 섹션 상단에 대화창으로 표시"</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"기본적으로 <xliff:g id="APP_NAME_0">%1$s</xliff:g>의 모든 대화가 대화창으로 표시됩니다. <xliff:g id="APP_NAME_1">%2$s</xliff:g>에서 관리하세요."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"설정"</string> <string name="notification_priority_title" msgid="2079708866333537093">"우선순위"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"최근에 닫은 도움말 풍선 없음"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"최근 버블과 내가 닫은 버블이 여기 표시됩니다."</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"최근에 닫은 대화창 없음"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"최근 대화창과 내가 닫은 대화창이 여기에 표시됩니다."</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"이 알림 그룹은 여기에서 설정할 수 없습니다."</string> <string name="notification_delegate_header" msgid="1264510071031479920">"프록시를 통한 알림"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"무음으로 설정됨"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"알림"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"버블 표시"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"버블 사용 중지"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"대화창 사용 중지"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"홈 화면에 추가"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"알림 관리"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"기기 서비스"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"제목 없음"</string> <string name="restart_button_description" msgid="6916116576177456480">"탭하여 이 앱을 다시 시작하고 전체 화면으로 이동합니다."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> 알림 풍선 설정"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> 대화창 설정"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"관리"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> 외 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>개의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -993,11 +993,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"왼쪽 하단으로 이동"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"오른쪽 하단으로 이동"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"닫기"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"대화를 버블로 표시하지 않음"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"버블을 사용하여 채팅하세요"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"새로운 대화가 플로팅 아이콘인 버블로 표시됩니다. 버블을 열려면 탭하세요. 드래그하여 이동할 수 있습니다."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"언제든지 버블을 제어하세요"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"이 앱에서 버블을 사용 중지하려면 관리를 탭하세요."</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"대화를 대화창으로 표시하지 않음"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"대화창을 사용하여 채팅하세요"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"새로운 대화가 플로팅 아이콘인 대화창으로 표시됩니다. 대화창을 열려면 탭하세요. 드래그하여 이동할 수 있습니다."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"언제든지 대화창을 제어하세요"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"이 앱에서 대화창을 사용 중지하려면 관리를 탭하세요."</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"확인"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"시스템 탐색이 업데이트되었습니다. 변경하려면 설정으로 이동하세요."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"설정으로 이동하여 시스템 탐색을 업데이트하세요."</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"확대 오버레이 창"</string> <string name="magnification_window_title" msgid="4863914360847258333">"확대 창"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"확대 창 컨트롤"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"빠른 컨트롤"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"기기 컨트롤"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"연결된 기기의 컨트롤을 추가합니다."</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"빠른 컨트롤 설정"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"기기 컨트롤 설정"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"전원 버튼을 길게 눌러 컨트롤에 액세스하세요."</string> <string name="controls_providers_title" msgid="6879775889857085056">"컨트롤을 추가할 앱을 선택하세요"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"제어"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"전원 메뉴에서 액세스할 컨트롤을 선택합니다."</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"컨트롤을 길게 터치하고 드래그하여 이동"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"전체 컨트롤 목록을 로드할 수 없습니다."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"기타"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"빠른 컨트롤에 추가"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"기기 컨트롤에 추가"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"즐겨찾기에 추가"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g>에서 이 제어 기능을 즐겨찾기에 추가할 것을 제안합니다."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"컨트롤 업데이트됨"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 47c42fa5d56f..ff614e52f06a 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Уруксат берүү"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB мүчүлүштүктөрүн оңдоого уруксат жок"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Учурда бул аккаунтта USB аркылуу мүчүлүштүктөрдү оңдоо функциясын иштетүүгө болбойт. Негизги колдонуучунун аккаунтуна кириңиз."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Бул тармакта мүчүлүштүктөрдү зымсыз оңдоого уруксат берилсинби?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Бул тармакта мүчүлүштүктөрдү Wi-Fi аркылуу оңдоого уруксат берилсинби?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Тармактын аталышы (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi дареги (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Бул тармакта ар дайым уруксат берилсин"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Уруксат берүү"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Мүчүлүштүктөрдү зымсыз оңдоого уруксат берилген жок"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Учурда бул түзмөккө кирген колдонуучу мүчүлүштүктөрдү зымсыз оңдоо функциясын күйгүзө албайт. Бул функцияны колдонуу үчүн негизги колдонуучунун аккаунтуна которулуңуз."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоого уруксат берилген жок"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Учурда бул түзмөккө кирген колдонуучу мүчүлүштүктөрдү Wi-Fi аркылуу оңдоо функциясын күйгүзө албайт. Бул функцияны колдонуу үчүн негизги колдонуучунун аккаунтуна которулуңуз."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB порту өчүрүлдү"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Түзмөгүңүздүн ичине суюктук же булганч нерселер кирип кетпеши үчүн USB порту өчүрүлдү. Азырынча ал аркылуу башка түзмөктөргө туташууга болбойт.\n\nUSB портун кайра колдонуу мүмкүн болгондо, билдирме аласыз."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Кубаттагычтарды жана аксессуарларды аныктоо үчүн USB оюкчасы иштетилди"</string> @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Скриншот тартууга колдонмо же ишканаңыз тыюу салган."</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Скриншотту четке кагуу"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Скриншотту ачуу"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Экранды жаздыргыч"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"экрандан видео жаздырып алуу"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды жаздыруу сеансы боюнча учурдагы билдирме"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Жаздырып башталсынбы?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Жаздыруу учурунда Android тутуму экраныңызда көрүнүп турган жана түзмөктө ойнотулуп жаткан бардык купуя маалыматты жаздырып алат. Буга сырсөздөр, төлөм маалыматы, сүрөттөр, билдирүүлөр жана аудио файлдар кирет."</string> @@ -97,7 +97,7 @@ <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Музыка, чалуулар жана рингтондор сыяктуу түзмөгүңүздөгү добуштар"</string> <string name="screenrecord_mic_label" msgid="2111264835791332350">"Микрофон"</string> <string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Түзмөктүн аудиосу жана микрофон"</string> - <string name="screenrecord_start" msgid="330991441575775004">"Старт"</string> + <string name="screenrecord_start" msgid="330991441575775004">"Баштадык"</string> <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Экран жаздырылууда"</string> <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Экран жана аудио жаздырылууда"</string> <string name="screenrecord_taps_label" msgid="1595690528298857649">"Экранды басууларды көрсөтүү"</string> @@ -315,7 +315,7 @@ <string name="data_usage_disabled_dialog_4g_title" msgid="1490779000057752281">"4G дайындары тындырылды"</string> <string name="data_usage_disabled_dialog_mobile_title" msgid="2286843518689837719">"Мобилдик Интернет кызматы тындырылды"</string> <string name="data_usage_disabled_dialog_title" msgid="9131615296036724838">"Дайындар тындырылды"</string> - <string name="data_usage_disabled_dialog" msgid="7933201635215099780">"Трафик сиз койгон чекке жетти. Эми мобилдик Интернетти колдоно албайсыз.\n\nЭгер улантсаңыз, дайындарды өткөрүү үчүн акы алынышы мүмкүн."</string> + <string name="data_usage_disabled_dialog" msgid="7933201635215099780">"Трафик сиз койгон чекке жетти. Эми мобилдик Интернетти колдоно албайсыз.\n\nЭгер улантсаңыз, дайын-даректерди өткөрүү үчүн акы алынышы мүмкүн."</string> <string name="data_usage_disabled_dialog_enable" msgid="2796648546086408937">"Улантуу"</string> <string name="gps_notification_searching_text" msgid="231304732649348313">"GPS издөө"</string> <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS боюнча аныкталган жайгашуу"</string> @@ -394,7 +394,7 @@ <string name="quick_settings_connected" msgid="3873605509184830379">"Туташкан"</string> <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Туташып турат, батареянын деңгээли – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="quick_settings_connecting" msgid="2381969772953268809">"Туташууда…"</string> - <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Тетеринг"</string> + <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Модем режими"</string> <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Байланыш түйүнү"</string> <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Күйгүзүлүүдө…"</string> <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Трафикти үнөмдөө күйүк"</string> @@ -428,7 +428,7 @@ <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өчүрүлгөн"</string> <string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC иштетилген"</string> <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Экранды жаздыруу"</string> - <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Старт"</string> + <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Баштадык"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Токтотуу"</string> <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Колдонмолорду которуштуруу үчүн өйдө сүрүңүз"</string> <string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Колдонмолорду тез которуштуруу үчүн оңго сүйрөңүз"</string> @@ -497,11 +497,11 @@ <string name="user_remove_user_message" msgid="6702834122128031833">"Бул колдонуучунун бардык колдонмолору жана дайындары өчүрүлөт."</string> <string name="user_remove_user_remove" msgid="8387386066949061256">"Алып салуу"</string> <string name="battery_saver_notification_title" msgid="8419266546034372562">"Батареяны үнөмдөгүч режими күйүк"</string> - <string name="battery_saver_notification_text" msgid="2617841636449016951">"Иштин майнаптуулугун начарлатып, фондук дайындарды чектейт"</string> + <string name="battery_saver_notification_text" msgid="2617841636449016951">"Иштин майнаптуулугун начарлатып, фондук дайын-даректерди чектейт"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Батареяны үнөмдөгүч режимин өчүрүү"</string> <string name="media_projection_dialog_text" msgid="1755705274910034772">"Бул функцияны аткарган <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> кызматы экраныңызда көрүнүп турган бардык маалыматты же жаздыруу жана тышкы экранга чыгаруу учурунда түзмөгүңүздө ойнотулган маалыматты колдоно алат. Буга сырсөздөр, төлөмдүн чоо-жайы, сүрөттөр, билдирүүлөр жана ойнотулган аудио кирет."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Бул функцияны аткарган кызмат экраныңызда көрүнүп турган бардык маалыматты же жаздыруу жана тышкы экранга чыгаруу учурунда түзмөгүңүздө ойнотулган маалыматты колдоно алат. Буга сырсөздөр, төлөмдүн чоо-жайы, сүрөттөр, билдирүүлөр жана ойнотулган аудио кирет."</string> - <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Жаздырылып же тышкы экранга чыгарылып башталсынбы?"</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Бул функцияны аткарган кызматка экраныңыздагы бардык маалымат же түзмөктө ойнотулуп жаткан нерсе, сырсөздөр, төлөмдөрдүн чоо-жайы, сүрөттөр, билдирүүлөр жана аудио файлдар жеткиликтүү болот."</string> + <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Жаздырып же тышкы экранга чыгарып баштайсызбы?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> менен жаздырылып же тышкы экранга чыгарылып башталсынбы?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Экинчи көрсөтүлбөсүн"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Баарын тазалап салуу"</string> @@ -510,7 +510,7 @@ <string name="notification_section_header_gentle" msgid="3044910806569985386">"Үнсүз билдирмелер"</string> <string name="notification_section_header_alerting" msgid="3168140660646863240">"Эскертүүлөр"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Жазышуулар"</string> - <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Маанилүү эмес билдирмелердин баарын өчүрүү"</string> + <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Бардык үнсүз билдирмелерди өчүрүү"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\"Тынчымды алба\" режиминде билдирмелер тындырылды"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Азыр баштоо"</string> <string name="empty_shade_text" msgid="8935967157319717412">"Билдирме жок"</string> @@ -541,8 +541,8 @@ <string name="disable_vpn" msgid="482685974985502922">"VPN\'ди өчүрүү"</string> <string name="disconnect_vpn" msgid="26286850045344557">"VPN\'ди ажыратуу"</string> <string name="monitoring_button_view_policies" msgid="3869724835853502410">"Саясаттарды карап көрүү"</string> - <string name="monitoring_description_named_management" msgid="7424612629468754552">"Түзмөгүңүздү <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> башкарат.\n\nАдминистраторуңуз жөндөөлөрдү, корпоративдик мүмкүнчүлүктү, колдонмолорду, түзмөгүңүзгө байланыштуу дайындарды жана түзмөгүңүздүн жайгашкан жери тууралуу маалыматты көзөмөлдөп жана башкара алат.\n\nКөбүрөөк маалымат алуу үчүн администраторуңузга кайрылыңыз."</string> - <string name="monitoring_description_management" msgid="8081910434889677718">"Түзмөгүңүздү уюмуңуз башкарат.\n\nАдминистраторуңуз жөндөөлөрдү, корпоративдик мүмкүнчүлүктү, колдонмолорду, түзмөгүңүзгө байланыштуу дайындарды жана түзмөгүңүздүн жайгашкан жери тууралуу маалыматты көзөмөлдөп жана башкара алат.\n\nКөбүрөөк маалымат алуу үчүн администраторуңузга кайрылыңыз."</string> + <string name="monitoring_description_named_management" msgid="7424612629468754552">"Түзмөгүңүздү <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> башкарат.\n\nАдминистраторуңуз жөндөөлөрдү, корпоративдик мүмкүнчүлүктү, колдонмолорду, түзмөгүңүзгө байланыштуу дайын-даректерди жана түзмөгүңүздүн жайгашкан жери тууралуу маалыматты көзөмөлдөп жана башкара алат.\n\nКөбүрөөк маалымат алуу үчүн администраторуңузга кайрылыңыз."</string> + <string name="monitoring_description_management" msgid="8081910434889677718">"Түзмөгүңүздү уюмуңуз башкарат.\n\nАдминистраторуңуз жөндөөлөрдү, корпоративдик мүмкүнчүлүктү, колдонмолорду, түзмөгүңүзгө байланыштуу дайын-даректерди жана түзмөгүңүздүн жайгашкан жери тууралуу маалыматты көзөмөлдөп жана башкара алат.\n\nКөбүрөөк маалымат алуу үчүн администраторуңузга кайрылыңыз."</string> <string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Ишканаңыз бул түзмөккө тастыктоочу борборду орнотту. Коопсуз тармагыңыздын трафиги көзөмөлдөнүп же өзгөртүлүшү мүмкүн."</string> <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Ишканаңыз жумуш профилиңизге тастыктоочу борборду орнотту. Коопсуз тармагыңыздын трафиги көзөмөлдөнүп же өзгөртүлүшү мүмкүн."</string> <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Бул түзмөктө тастыктоочу борбор орнотулган. Коопсуз тармагыңыздын трафиги көзөмөлдөнүп же өзгөртүлүшү мүмкүн."</string> @@ -553,7 +553,7 @@ <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"Жеке профилиңиз электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы аракеттериңизди көзөмөлдөй турган <xliff:g id="VPN_APP">%1$s</xliff:g> колдонмосуна туташып турат."</string> <string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"Түзмөгүңүз <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> тарабынан башкарылат."</string> <string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"Түзмөгүңүздү башкаруу үчүн <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> уюму <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> колдонмосун колдонот."</string> - <string name="monitoring_description_do_body" msgid="7700878065625769970">"Администраторуңуз жөндөөлөрдү, корпоративдик кирүү мүмкүнчүлүгүн, колдонмолорду, уруксаттарды жана ушул түзмөкө байланыштуу дайындарды, ошондой эле түзмөгүңүздүн жайгашкан жери тууралуу маалыматты көзөмөлдөп жана башкара алат."</string> + <string name="monitoring_description_do_body" msgid="7700878065625769970">"Администраторуңуз жөндөөлөрдү, корпоративдик кирүү мүмкүнчүлүгүн, колдонмолорду, уруксаттарды жана ушул түзмөкө байланыштуу дайын-даректерди, ошондой эле түзмөгүңүздүн жайгашкан жери тууралуу маалыматты көзөмөлдөп жана башкара алат."</string> <string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string> <string name="monitoring_description_do_learn_more" msgid="645149183455573790">"Кеңири маалымат"</string> <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы аракеттериңизди тескей турган <xliff:g id="VPN_APP">%1$s</xliff:g> колдонмосуна туташып турасыз."</string> @@ -578,7 +578,7 @@ <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Жок, рахмат"</string> <string name="hidden_notifications_setup" msgid="2064795578526982467">"Орнотуу"</string> <string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string> - <string name="volume_zen_end_now" msgid="5901885672973736563">"Азыр өчүрүлсүн"</string> + <string name="volume_zen_end_now" msgid="5901885672973736563">"Өчүрүү"</string> <string name="accessibility_volume_settings" msgid="1458961116951564784">"Добуштун жөндөөлөрү"</string> <string name="accessibility_volume_expand" msgid="7653070939304433603">"Жайып көрсөтүү"</string> <string name="accessibility_volume_collapse" msgid="2746845391013829996">"Жыйнап коюу"</string> @@ -758,10 +758,10 @@ <item quantity="other">%d мүнөт</item> <item quantity="one">%d мүнөт</item> </plurals> - <string name="battery_panel_title" msgid="5931157246673665963">"Батарея колдонулушу"</string> + <string name="battery_panel_title" msgid="5931157246673665963">"Батареяны керектөө"</string> <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Батареяны үнөмдөгүч түзмөк кубатталып жатканда иштебейт"</string> <string name="battery_detail_switch_title" msgid="6940976502957380405">"Батареяны үнөмдөгүч"</string> - <string name="battery_detail_switch_summary" msgid="3668748557848025990">"Иштин майнаптуулугун начарлатып, фондук дайындарды чектейт"</string> + <string name="battery_detail_switch_summary" msgid="3668748557848025990">"Иштин майнаптуулугун начарлатып, фондук дайын-даректерди чектейт"</string> <string name="keyboard_key_button_template" msgid="8005673627272051429">"<xliff:g id="NAME">%1$s</xliff:g> баскычы"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Башкы бет"</string> <string name="keyboard_key_back" msgid="4185420465469481999">"Артка"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"Түзмөк кызматтары"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Аталышы жок"</string> <string name="restart_button_description" msgid="6916116576177456480">"Бул колдонмону өчүрүп күйгүзүп, толук экранга өтүү үчүн таптап коюңуз."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> көбүктөрүнүн жөндөөлөрү"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> калкып чыкма билдирмелер жөндөөлөрү"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"Башкаруу"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> колдонмосунан <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> жана дагы <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> колдонмодон <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -995,7 +995,7 @@ <string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабуу"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Жазышуу калкып чыкма билдирмеде көрүнбөсүн"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Калкып чыкма билдирмелер аркылуу маектешүү"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңы жазышуулар калкыма сүрөтчөлөр же билдирмелер болуп көрүнөт. Калкып чыкма билдирмени ачуу үчүн таптап коюңуз. Жылдыруу үчүн сүйрөңүз."</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңы жазышуулар калкыма сүрөтчөлөр же калкып чыкма билдирмелер болуп көрүнөт. Калкып чыкма билдирмелерди ачуу үчүн таптап коюңуз. Жылдыруу үчүн сүйрөңүз."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Калкып чыкма билдирмелерди каалаган убакта көзөмөлдөңүз"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бул колдонмодогу калкып чыкма билдирмелерди өчүрүү үчүн \"Башкарууну\" басыңыз"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Түшүндүм"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Чоңойтуу терезесин үстүнө коюу"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Чоңойтуу терезеси"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Чоңойтуу терезесин башкаруу каражаттары"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Ыкчам көзөмөлдөр"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Түзмөктү көзөмөлдөө элементтери"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Байланыштырылган түзмөктөрүңүз үчүн көзөмөлдөрдү кошуңуз"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Ыкчам көзөмөлдөрдү жөндөө"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Түзмөктү көзөмөлдөө элементтерин жөндөө"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Көзөмөлдөргө өтүү үчүн күйгүзүү/өчүрүү баскычын басып туруңуз"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Көзөмөлдөрдү кошуу үчүн колдонмо тандаңыз"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Башкаруу элементтери"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Күйгүзүү/өчүрүү баскычынын менюсу үчүн көзөмөлдөрдү тандаңыз"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Жылдыруу үчүн көзөмөлдү сүйрөп келиңиз"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Бардык көзөмөлдөрдүн тизмеси жүктөлгөн жок."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Башка"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Ыкчам көзөмөлгө кошуу"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Түзмөктү көзөмөлдөө элементтерине кошуу"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Сүйүктүүлөргө кошуу"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> бул көзөмөлдү сүйүктүүлөргө кошууну сунуштады."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Башкаруу элементтери жаңырды"</string> diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml index da5819c50a7e..2f7fbaff4ed2 100644 --- a/packages/SystemUI/res/values-land/config.xml +++ b/packages/SystemUI/res/values-land/config.xml @@ -34,4 +34,7 @@ <!-- Max number of columns for quick controls area --> <integer name="controls_max_columns">4</integer> + + <!-- Max number of columns for power menu --> + <integer name="power_menu_max_columns">4</integer> </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 8336c61095c3..2250077a5e0c 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ແອັບ ຫຼື ອົງກອນຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ຖ່າຍຮູບໜ້າຈໍ"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ປິດຮູບໜ້າຈໍ"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"ເປີດຮູບໜ້າຈໍ"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"ຕົວບັນທຶກໜ້າຈໍ"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"ໂປຣແກຣມບັນທຶກໜ້າຈໍ"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"ການແຈ້ງເຕືອນສຳລັບເຊດຊັນການບັນທຶກໜ້າຈໍໃດໜຶ່ງ"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"ເລີ່ມການບັນທຶກບໍ?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"ໃນລະຫວ່າງການບັນທຶກ, ລະບົບ Android ຈະສາມາດບັນທຶກຂໍ້ມູນທີ່ລະອຽດອ່ອນໃດກໍຕາມທີ່ສະແດງຢູ່ໜ້າຈໍຂອງທ່ານ ຫຼື ຫຼິ້ນຢູ່ອຸປະກອນທ່ານ. ນີ້ຮວມເຖິງລະຫັດຜ່ານ, ຂໍ້ມູນການຈ່າຍເງິນ, ຮູບ, ຂໍ້ຄວາມ ແລະ ສຽງນຳ."</string> @@ -708,12 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"ຊ່ວຍທ່ານມີສະມາທິໂດຍບໍ່ໃຊ້ສຽງ ຫຼື ການສັ່ນເຕືອນ."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"ດຶງຄວາມສົນໃຈຂອງທ່ານດ້ວຍສຽງ ຫຼື ການສັ່ນເຕືອນ."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ເອົາໃຈໃສ່ທາງລັດແບບລອຍໄປຫາເນື້ອຫານີ້."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"ສະແດງຢູ່ເທິງສຸດຂອງພາກສ່ວນການສົນທະນາ ແລະ ປາກົດເປັນ bubble."</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"ການສົນທະນາທັງໝົດຈາກ bubble ຂອງ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ຕາມຄ່າເລີ່ມຕົ້ນ. ຈັດການໃນ <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"ສະແດງຢູ່ເທິງສຸດຂອງພາກສ່ວນການສົນທະນາ ແລະ ສະແດງເປັນຟອງ."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"ການສົນທະນາທັງໝົດຈາກ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ທີ່ສະແດງເປັນຟອງຕາມຄ່າເລີ່ມຕົ້ນ. ຈັດການໃນ <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ຕັ້ງຄ່າ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ຄວາມສຳຄັນ"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ບໍ່ມີ bubble ຫຼ້າສຸດ"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Bubbles ຫຼ້າສຸດ ແລະ Bubbles ທີ່ປິດໄປຈະປາກົດຢູ່ບ່ອນນີ້"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ບໍ່ມີຟອງຫຼ້າສຸດ"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ຟອງຫຼ້າສຸດ ແລະ ຟອງທີ່ປິດໄປຈະປາກົດຢູ່ບ່ອນນີ້"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນເຫຼົ່ານີ້ໄດ້."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ບໍ່ສາມາດຕັ້ງຄ່າກຸ່ມການແຈ້ງເຕືອນນີ້ຢູ່ບ່ອນນີ້ໄດ້"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"ການແຈ້ງເຕືອນແບບພຣັອກຊີ"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"ປິດສຽງແລ້ວ"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"ການເຕືອນ"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"ສະແດງຟອງນ້ຳ"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"ລຶບຟອງນ້ຳອອກ"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"ລຶບຟອງອອກ"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"ເພີ່ມໃສ່ໜ້າຈໍຫຼັກ"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"ການຄວບຄຸມການແຈ້ງເຕືອນ"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"ບໍລິການອຸປະກອນ"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"ບໍ່ມີຊື່"</string> <string name="restart_button_description" msgid="6916116576177456480">"ແຕະເພື່ອຣີສະຕາດແອັບນີ້ ແລະ ໃຊ້ແບບເຕັມຈໍ."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"ການຕັ້ງຄ່າສຳລັບ bubble <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"ການຕັ້ງຄ່າສຳລັບຟອງ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"ຈັດການ"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g> ແລະ ອີກ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string> @@ -993,11 +993,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ຍ້າຍຊ້າຍລຸ່ມ"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ຍ້າຍຂວາລຸ່ມ"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"ປິດໄວ້"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ຢ່າ bubble ການສົນທະນາ"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"ສົນທະນາໂດຍໃຊ້ bubbles"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"ການສົນທະນາໃໝ່ຈະປາກົດເປັນໄອຄອນ ຫຼື bubbles ແບບລອຍ. ແຕະເພື່ອເປີດ bubble. ລາກເພື່ອຍ້າຍມັນ."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ຄວບຄຸມ bubbles ຕອນໃດກໍໄດ້"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ແຕະຈັດການເພື່ອປິດ bubble ຈາກແອັບນີ້"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ຢ່າໃຊ້ຟອງໃນການສົນທະນາ"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"ສົນທະນາໂດຍໃຊ້ຟອງ"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"ການສົນທະນາໃໝ່ຈະປາກົດເປັນໄອຄອນ ຫຼື ຟອງແບບລອຍ. ແຕະເພື່ອເປີດຟອງ. ລາກເພື່ອຍ້າຍມັນ."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ຄວບຄຸມຟອງຕອນໃດກໍໄດ້"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ແຕະຈັດການ ເພື່ອປິດຟອງຈາກແອັບນີ້"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ເຂົ້າໃຈແລ້ວ"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ອັບເດດການນຳທາງລະບົບແລ້ວ. ເພື່ອປ່ຽນແປງ, ກະລຸນາໄປທີ່ການຕັ້ງຄ່າ."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ໄປທີ່ການຕັ້ງຄ່າເພື່ອອັບເດດການນຳທາງລະບົບ"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"ໜ້າຈໍວາງທັບການຂະຫຍາຍ"</string> <string name="magnification_window_title" msgid="4863914360847258333">"ໜ້າຈໍການຂະຫຍາຍ"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"ການຄວບຄຸມໜ້າຈໍການຂະຫຍາຍ"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"ການຄວບຄຸມດ່ວນ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ການຄວບຄຸມອຸປະກອນ"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"ເພີ່ມການຄວບຄຸມສຳລັບອຸປະກອນທີ່ເຊື່ອມຕໍ່ແລ້ວຂອງທ່ານ"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"ຕັ້ງຄ່າການຄວບຄຸມດ່ວນ"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"ຕັ້ງຄ່າການຄວບຄຸມອຸປະກອນ"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"ກົດປຸ່ມເປີດປິດຄ້າງໄວ້ເພື່ອເຂົ້າເຖິງການຄວບຄຸມຂອງທ່ານ"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ເລືອກແອັບເພື່ອເພີ່ມການຄວບຄຸມ"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"ການຄວບຄຸມ"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"ເລືອກການຄວບຄຸມເພື່ອເຂົ້າເຖິງຈາກເມນູເປີດປິດ"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"ກົດຄ້າງໄວ້ແລ້ວລາກການຄວບຄຸມເພື່ອຍ້າຍມັນ"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"ບໍ່ສາມາດໂຫຼດລາຍຊື່ການຄວບຄຸມທັງໝົດໄດ້."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ອື່ນໆ"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"ເພີ່ມໃສ່ການຄວບຄຸມດ່ວນ"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"ເພີ່ມໃສ່ການຄວບຄຸມອຸປະກອນ"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"ເພີ່ມໃສ່ລາຍການທີ່ມັກ"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ແນະນຳການຄວບຄຸມນີ້ເພື່ອເພີ່ມໃສ່ລາຍການທີ່ທ່ານມັກ."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"ອັບເດດການຄວບຄຸມແລ້ວ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 2fb11bf7f8ad..ffe86199f71d 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Jūsų organizacijoje arba naudojant šią programą neleidžiama daryti ekrano kopijų"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Praleisti ekrano kopiją"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Atidaryti ekrano kopiją"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Ekrano garso įrašytuvas"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Ekrano vaizdo įrašytuvas"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Šiuo metu rodomas ekrano įrašymo sesijos pranešimas"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Pradėti įrašymą?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Įrašant „Android“ sistema gali fiksuoti bet kokią neskelbtiną informaciją, rodomą ekrane ar leidžiamą įrenginyje. Tai apima slaptažodžius, išsamią mokėjimo informaciją, nuotraukas, pranešimus ir garso įrašus."</string> @@ -714,12 +714,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"Padeda atkreipti dėmesį be garso arba vibravimo."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"Atkreipia dėmesį garsu arba vibravimu."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Naudojant slankųjį spartųjį klavišą lengviau sutelkti dėmesį į šį turinį."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Rodoma pokalbio skilties viršuje kaip debesėlis."</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Visi pokalbiai iš „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ debesėlio pagal numatytuosius nustatymus. Tvarkyti naudojant „<xliff:g id="APP_NAME_1">%2$s</xliff:g>“."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Rodoma pokalbio skilties viršuje kaip burbulas."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Visi pokalbiai iš „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ burbulo pagal numatytuosius nustatymus. Tvarkyti naudojant „<xliff:g id="APP_NAME_1">%2$s</xliff:g>“."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nustatymai"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetas"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nėra naujausių debesėlių"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Naujausi ir atsisakyti debesėliai bus rodomi čia"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nėra naujausių burbulų"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Naujausi ir atsisakyti burbulus bus rodomi čia"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Šių pranešimų keisti negalima."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Šios grupės pranešimai čia nekonfigūruojami"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Per tarpinį serverį gautas pranešimas"</string> @@ -747,7 +747,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"Nutildyta"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Įspėti"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"Rodyti debesėlį"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Pašalinti debesėlius"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Pašalinti burbulus"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Pridėti prie pagrindinio ekrano"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"pranešimų valdikliai"</string> @@ -993,7 +993,7 @@ <string name="device_services" msgid="1549944177856658705">"Įrenginio paslaugos"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Nėra pavadinimo"</string> <string name="restart_button_description" msgid="6916116576177456480">"Palieskite, kad paleistumėte iš naujo šią programą arba įjungtumėte viso ekrano režimą."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ debesėlių nustatymai"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ burbulų nustatymai"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"Tvarkyti"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“ ir dar <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string> @@ -1003,11 +1003,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Perkelti į apačią kairėje"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Perkelti į apačią dešinėje"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Atmesti"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nerodyti pokalbio debesėlyje"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Pokalbis naudojant debesėlius"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nauji pokalbiai rodomi kaip slankiosios piktogramos arba debesėliai. Palieskite, kad atidarytumėte debesėlį. Vilkite, kad perkeltumėte."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Bet kada valdyti debesėlius"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Palieskite „Tvarkyti“, kad išjungtumėte debesėlius šioje programoje"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nerodyti pokalbio burbule"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Pokalbis naudojant burbulus"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nauji pokalbiai rodomi kaip slankiosios piktogramos arba burbulus. Palieskite, kad atidarytumėte burbulą. Vilkite, kad perkeltumėte."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Bet kada valdyti burbulus"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Palieskite „Tvarkyti“, kad išjungtumėte burbulus šioje programoje"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Supratau"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemos naršymo funkcijos atnaujintos. Jei norite pakeisti, eikite į skiltį „Nustatymai“."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Eikite į skiltį „Nustatymai“, kad atnaujintumėte sistemos naršymo funkcijas"</string> @@ -1015,9 +1015,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Didinimo perdangos langas"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Didinimo langas"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Didinimo lango valdikliai"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Spartieji valdikliai"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Įrenginio valdikliai"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridėkite prijungtų įrenginių valdiklių"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Sparčiųjų valdiklių nustatymas"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Įrenginio valdiklių nustatymas"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Laikykite paspaudę maitinimo mygtuką, kad pasiektumėte valdiklius"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Pasirinkite programą, kad pridėtumėte valdiklių"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1028,10 +1028,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Valdikliai"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Pasirinkite valdiklius, kuriuos norite pasiekti įjungimo meniu"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Norėdami perkelti valdiklį, laikykite ir vilkite jį"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Nepavyko įkelti visų valdiklių sąrašo."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Kita"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Pridėj. prie sparč. valdiklių"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Pridėjimas prie įrenginio valdiklių"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Pridėjimas prie mėgstamiausių"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"„<xliff:g id="APP">%s</xliff:g>“ pasiūlė pridėti šį valdiklį prie mėgstamiausių."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Valdikliai atnaujinti"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 1ace75bdf3dc..adc7c1fad506 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -1010,9 +1010,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Palielināšanas pārklājuma logs"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Palielināšanas logs"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Palielināšanas loga vadīklas"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Ātrās piekļuves vadīklas"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Ierīces vadīklas"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Pievienojiet vadīklas pievienotajām ierīcēm"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Ātrās piekļuves vadīklu iestatīšana"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Ierīces vadīklu iestatīšana"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Turiet nospiestu barošanas pogu, lai piekļūtu vadīklām."</string> <string name="controls_providers_title" msgid="6879775889857085056">"Izvēlieties lietotni, lai pievienotu vadīklas"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1022,10 +1022,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Vadīklas"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Izvēlieties vadīklas, kurām piekļūt no barošanas izvēlnes"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Lai pārvietotu lietotni, turiet un velciet to"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Nevarēja ielādēt sarakstu ar visām vadīklām."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Cita"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Pievienošana ātrajām vadīklām"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Pievienošana ierīces vadīklām"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Pievienot izlasei"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ieteica pievienot šo vadīklu izlasei."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Vadīklas atjauninātas"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 5945fa9998f1..c41cc5ab6d22 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Апликацијата или вашата организација не дозволува снимање слики од екранот"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Отфрлете ја сликата од екранот"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Отворете ја сликата од екранот"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Снимач на екранот"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Снимач на екран"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Тековно известување за сесија за снимање на екранот"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Да се започне со снимање?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"При снимањето, системот на Android може да ги сними сите чувствителни податоци што се видливи на вашиот екран или пуштени на уредот. Ова вклучува лозинки, податоци за плаќање, фотографии, пораки и аудио."</string> @@ -394,7 +394,7 @@ <string name="quick_settings_connected" msgid="3873605509184830379">"Поврзано"</string> <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Поврзан, ниво на батеријата <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="quick_settings_connecting" msgid="2381969772953268809">"Се поврзува..."</string> - <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Поврзување"</string> + <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Врзување"</string> <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Точка на пристап"</string> <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Се вклучува…"</string> <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Вклучен штедач"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"Услуги за уредот"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Без наслов"</string> <string name="restart_button_description" msgid="6916116576177456480">"Допрете за да ја рестартирате апликацијава и да ја отворите на цел екран."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Поставки за баланчињата на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Поставки за балончињата за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"Управување"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g> и уште <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string> @@ -993,7 +993,7 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Премести долу лево"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Премести долу десно"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Отфрли"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Разговор без балончиња"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не прикажувај го разговорот во балончиња"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Разговор во балончиња"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новите разговори ќе се појавуваат како лебдечки икони или балончиња. Допрете за отворање на балончето. Повлечете за да го преместите."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Контролирајте ги балончињата во секое време"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Прозорец за преклопување на зголемувањето"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за зголемување"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Контроли на прозорец за зголемување"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Брзи контроли"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Контроли за уредите"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Додајте контроли за поврзаните уреди"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Поставете брзи контроли"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Поставете ги контролите за уредите"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Задржете го копчето за вклучување за да пристапите до контролите"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Изберете апликација во која ќе додадате контроли"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Контроли"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Изберете ги контролите до кои ќе пристапувате од менито за вклучување"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Задржете и влечете ја контролата за да ја преместите"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Не можеше да се вчита списокот со сите контроли."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друга"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Додајте во брзите контроли"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Додајте во контроли за уредите"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Додај во омилени"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> предложи да ја додадете контролава во вашите омилени."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Контролите се ажурирани"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 07c2eddb2bbd..2d53c8d9ebcf 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"അനുവദിക്കുക"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB ഡീബഗ്ഗിംഗ് അനുവദനീയമല്ല"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"ഉപകരണത്തിൽ ഇപ്പോൾ സൈൻ ഇൻ ചെയ്തിരിക്കുന്ന ഉപയോക്താവിന് USB ഡീബഗ്ഗിംഗ് ഓണാക്കാനാകില്ല. ഈ ഫീച്ചർ ഉപയോഗിക്കാൻ പ്രാഥമിക ഉപയോക്താവിലേക്ക് മാറുക."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"ഈ നെറ്റ്വർക്കിൽ വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ അനുവദിക്കണോ?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"ഈ നെറ്റ്വർക്കിൽ വയർലെസ് ഡീബഗ്ഗിംഗ് അനുവദിക്കണോ?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"നെറ്റ്വർക്കിന്റെ പേര് (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nവൈഫൈ വിലാസം (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"ഈ നെറ്റ്വർക്കിൽ എപ്പോഴും അനുവദിക്കുക"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"അനുവദിക്കൂ"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ അനുവദനീയമല്ല"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"ഉപകരണത്തിൽ ഇപ്പോൾ സൈൻ ഇൻ ചെയ്തിരിക്കുന്ന ഉപയോക്താവിന് വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ ഓണാക്കാനാകില്ല. ഈ ഫീച്ചർ ഉപയോഗിക്കാൻ പ്രാഥമിക ഉപയോക്താവിലേക്ക് മാറുക."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"വയർലെസ് ഡീബഗ്ഗിംഗ് അനുവദനീയമല്ല"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"ഉപകരണത്തിൽ ഇപ്പോൾ സൈൻ ഇൻ ചെയ്തിരിക്കുന്ന ഉപയോക്താവിന് വയർലെസ് ഡീബഗ്ഗിംഗ് ഓണാക്കാനാകില്ല. ഈ ഫീച്ചർ ഉപയോഗിക്കാൻ പ്രാഥമിക ഉപയോക്താവിലേക്ക് മാറുക."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB പോർട്ട് പ്രവർത്തനരഹിതമാക്കി"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"ദ്രാവകത്തിൽ നിന്നോ പൊടിയിൽ നിന്നോ നിങ്ങളുടെ ഉപകരണത്തെ പരിരക്ഷിക്കാനായി USB പോർട്ട് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നതിനാൽ അത് ആക്സസറികളൊന്നും തിരിച്ചറിയില്ല.\n\n USB പോർട്ട് വീണ്ടും ഉപയോഗിക്കാനാകുമ്പോൾ നിങ്ങളെ അറിയിക്കും."</string> <string name="usb_port_enabled" msgid="531823867664717018">"ആക്സസറികളും ചാർജറുകളും കണ്ടെത്താൻ USB പോർട്ട് പ്രവർത്തനക്ഷമമാക്കുക"</string> @@ -708,12 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"ശബ്ദമോ വൈബ്രേഷനോ ഇല്ലാതെ ശ്രദ്ധ കേന്ദ്രീകരിക്കാൻ നിങ്ങളെ സഹായിക്കുന്നു."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"ശബ്ദമോ വെെബ്രേഷനോ ഉപയോഗിച്ച് നിങ്ങളുടെ ശ്രദ്ധ ക്ഷണിക്കുന്നു."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ഈ ഉള്ളടക്കത്തിലേക്ക് ഒരു ഫ്ലോട്ടിംഗ് കുറുക്കുവഴി ഉപയോഗിച്ച് നിങ്ങളുടെ ശ്രദ്ധ നിലനിർത്തുന്നു."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"സംഭാഷണ വിഭാഗത്തിന് മുകളിൽ ഒരു ബബിളായി ദൃശ്യമാവുന്നു."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"സംഭാഷണ വിഭാഗത്തിന് മുകളിൽ ബബിളായി ദൃശ്യമാവുന്നു."</string> <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> എന്നതിൽ നിന്നുള്ള എല്ലാ സംഭാഷണങ്ങളും ഡിഫോൾട്ടായി ബബിളാവുന്നു. <xliff:g id="APP_NAME_1">%2$s</xliff:g> എന്നതിൽ മാനേജ് ചെയ്യുക."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ക്രമീകരണം"</string> <string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"അടുത്തിടെയുള്ള ബബിളുകൾ ഒന്നുമില്ല"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"അടുത്തിടെയുള്ള ബബിൾ, ഡിസ്മിസ് ചെയ്ത ബബിൾ എന്നിവ ഇവിടെ ദൃശ്യമാവും"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"അടുത്തിടെയുള്ള ബബിളുകൾ, ഡിസ്മിസ് ചെയ്ത ബബിളുകൾ എന്നിവ ഇവിടെ ദൃശ്യമാവും"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"അറിയിപ്പുകളുടെ ഈ ഗ്രൂപ്പ് ഇവിടെ കോണ്ഫിഗര് ചെയ്യാൻ കഴിയില്ല"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"പ്രോക്സി അറിയിപ്പ്"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"ഉപകരണ സേവനങ്ങള്"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"പേരില്ല"</string> <string name="restart_button_description" msgid="6916116576177456480">"ഈ ആപ്പ് റീസ്റ്റാർട്ട് ചെയ്യാനും പൂർണ്ണ സ്ക്രീനാവാനും ടാപ്പ് ചെയ്യുക."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനുള്ള ബബിളുകളുടെ ക്രമീകരണം"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബബിളുകളുടെ ക്രമീകരണം"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"മാനേജ് ചെയ്യുക"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>-ൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> കൂടുതലും"</string> @@ -994,10 +994,10 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"ഡിസ്മിസ് ചെയ്യുക"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"സംഭാഷണം ബബിൾ ചെയ്യരുത്"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"ബബിൾ ഉപയോഗിച്ച് ചാറ്റ് ചെയ്യുക"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"പുതിയ സംഭാഷണങ്ങൾ ഫ്ലോട്ടിംഗ് ഐക്കണുകളോ ബബിളോ ആയി ദൃശ്യമാവുന്നു. ബബിൾ തുറക്കാൻ ടാപ്പ് ചെയ്യു. ഇത് നീക്കാൻ വലിച്ചിടുക."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ബബിൾ ഏതുസമയത്തും നിയന്ത്രിക്കുക"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ഈ ആപ്പിൽ നിന്നുള്ള ബബിളുകൾ ഓഫാക്കാൻ \'മാനേജ് ചെയ്യുക\' ടാപ്പ് ചെയ്യുക"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"ബബിളുകൾ ഉപയോഗിച്ച് ചാറ്റ് ചെയ്യുക"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"പുതിയ സംഭാഷണങ്ങൾ ഫ്ലോട്ടിംഗ് ഐക്കണുകളോ ബബിളുകളോ ആയി ദൃശ്യമാവുന്നു. ബബിൾ തുറക്കാൻ ടാപ്പ് ചെയ്യു. ഇത് നീക്കാൻ വലിച്ചിടുക."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ബബിളുകൾ ഏതുസമയത്തും നിയന്ത്രിക്കുക"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ഈ ആപ്പിൽ നിന്നുള്ള ബബിളുകൾ ഓഫാക്കാൻ മാനേജ് ചെയ്യുക ടാപ്പ് ചെയ്യുക"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ലഭിച്ചു"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"സിസ്റ്റം നാവിഗേഷൻ അപ്ഡേറ്റ് ചെയ്തു. മാറ്റങ്ങൾ വരുത്താൻ ക്രമീകരണത്തിലേക്ക് പോവുക."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"സിസ്റ്റം നാവിഗേഷൻ അപ്ഡേറ്റ് ചെയ്യാൻ ക്രമീകരണത്തിലേക്ക് പോവുക"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"മാഗ്നിഫിക്കേഷൻ ഓവർലേ വിൻഡോ"</string> <string name="magnification_window_title" msgid="4863914360847258333">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ നിയന്ത്രണങ്ങൾ"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"ദ്രുത നിയന്ത്രണങ്ങൾ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ഉപകരണ നിയന്ത്രണങ്ങൾ"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"നിങ്ങളുടെ കണക്റ്റ് ചെയ്ത ഉപകരണങ്ങൾക്ക് നിയന്ത്രണങ്ങൾ ചേർക്കുക"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"ദ്രുത നിയന്ത്രണങ്ങൾ സജ്ജീകരിക്കുക"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"ഉപകരണ നിയന്ത്രണങ്ങൾ സജ്ജീകരിക്കുക"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"നിങ്ങളുടെ നിയന്ത്രണങ്ങൾ ആക്സസ് ചെയ്യാൻ പവർ ബട്ടണിൽ പിടിക്കുക"</string> <string name="controls_providers_title" msgid="6879775889857085056">"നിയന്ത്രണങ്ങൾ ചേർക്കാൻ ആപ്പ് തിരഞ്ഞെടുക്കുക"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"നിയന്ത്രണങ്ങൾ"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"പവർ മെനുവിൽ നിന്ന് ആക്സസ് ചെയ്യേണ്ട നിയന്ത്രണങ്ങൾ തിരഞ്ഞെടുക്കുക"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"ഇത് നീക്കാൻ, നിയന്ത്രണം പിടിച്ച് വലിച്ചിടുക"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"എല്ലാ നിയന്ത്രണങ്ങളുടെയും ലിസ്റ്റ് ലോഡ് ചെയ്യാനായില്ല."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"മറ്റുള്ളവ"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"ദ്രുത നിയന്ത്രണങ്ങളിലേക്ക് ചേർക്കൂ"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"ഉപകരണ നിയന്ത്രണങ്ങളിലേക്ക് ചേർക്കുക"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"പ്രിയപ്പെട്ടവയിലേക്ക് ചേർക്കുക"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"ഈ നിയന്ത്രണത്തെ നിങ്ങളുടെ പ്രിയപ്പെട്ടവയിലേക്ക് ചേർക്കാൻ <xliff:g id="APP">%s</xliff:g> ശുപാർശ ചെയ്തു."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"നിയന്ത്രണങ്ങൾ അപ്ഡേറ്റ് ചെയ്തു"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 52c0581d7d39..b4bac5f07ca0 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Зөвшөөрөх"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB алдаа засалт хийх боломжгүй"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Энэ төхөөрөмжид нэвтэрсэн хэрэглэгч USB дебаг хийх онцлогийг асаах боломжгүй байна. Энэ онцлогийг ашиглахын тулд үндсэн хэрэглэгч рүү сэлгэнэ үү."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Энэ сүлжээн дээр утасгүй дебагийг зөвшөөрөх үү?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Энэ сүлжээн дээр wireless debugging-г зөвшөөрөх үү?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Сүлжээний нэр (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi хаяг (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Энэ сүлжээн дээр үргэлж зөвшөөрөх"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Зөвшөөрөх"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Утасгүй дебагийг зөвшөөрөөгүй байна"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Энэ төхөөрөмжид одоогоор нэвтэрсэн байгаа хэрэглэгч утасгүй дебагийг асаах боломжгүй. Энэ онцлогийг ашиглахын тулд үндсэн хэрэглэгч рүү сэлгэнэ үү."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Wireless debugging-г зөвшөөрөөгүй байна"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Энэ төхөөрөмжид одоогоор нэвтэрсэн байгаа хэрэглэгч wireless debugging-г асаах боломжгүй. Энэ онцлогийг ашиглахын тулд үндсэн хэрэглэгч рүү сэлгэнэ үү."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB портыг идэвхгүй болгосон"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Таны төхөөрөмжийг шингэн зүйл эсвэл бохирдлоос хамгаалахын тулд USB портыг идэвхгүй болгосон бөгөөд энэ нь ямар ч дагалдах хэрэгслийг илрүүлэхгүй.\n\nТанд USB портыг дахин ашиглахад аюулгүй болох үед мэдэгдэх болно."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Цэнэглэгч болон нэмэлт хэрэгслийг илрүүлэхийн тулд USB портыг идэвхжүүлсэн"</string> @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Таны апп, байгууллагад дэлгэцийн зураг авахыг зөвшөөрдөггүй"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Дэлгэцийн агшныг хаах"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Дэлгэцийн агшныг нээх"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Дэлгэцийн бичигч"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Дэлгэцийн үйлдэл бичигч"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Дэлгэц бичих горимын үргэлжилж буй мэдэгдэл"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Бичлэгийг эхлүүлэх үү?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Бичих үед Андройд систем нь таны дэлгэц дээр харагдах эсвэл төхөөрөмж дээрээ тоглуулсан аливаа эмзэг мэдээллийг авах боломжтой. Үүнд нууц үг, төлбөрийн мэдээлэл, зураг, зурвас болон аудио багтана."</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"Дуугүй болгосон"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Сэрэмжлүүлж байна"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"Хөөсийг харуулах"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Хөөсийг хасах"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Бөмбөлгүүдийг хасах"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Үндсэн нүүрэнд нэмэх"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"мэдэгдлийн удирдлага"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"Төхөөрөмжийн үйлчилгээ"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Гарчиггүй"</string> <string name="restart_button_description" msgid="6916116576177456480">"Энэ аппыг дахин эхлүүлж, бүтэн дэлгэцэд орохын тулд товшино уу."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н хөөсний тохиргоо"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н бөмбөлгүүдийн тохиргоо"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"Удирдах"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>-н <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g>-н <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> болон бусад <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Томруулалтыг давхарласан цонх"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Томруулалтын цонх"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Томруулалтын цонхны хяналт"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Шуурхай хяналт"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Төхөөрөмжийн хяналт"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Холбогдсон төхөөрөмжүүд дээрээ хяналт нэмэх"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Шуурхай хяналтыг тохируулах"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Төхөөрөмжийн хяналтыг тохируулах"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Хяналтууддаа хандахын тулд Асаах товчийг удаан дарна уу"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Хяналтууд нэмэхийн тулд аппыг сонгоно уу"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Хяналт"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Тэжээлийн цэсээс хандах хяналтуудыг сонгоно уу"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Хяналтыг зөөхийн тулд дараад чирнэ үү"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Бүх хяналтын жагсаалтыг ачаалж чадсангүй."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Бусад"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Шуурхай хяналтад нэмэх"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Төхөөрөмжийн хяналт руу нэмэх"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Дуртайд нэмэх"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> нь энэ хяналтыг дуртайдаа нэмэхийг санал болгосон."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Хяналтуудыг шинэчиллээ"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index c2ebfcd3d779..de4f39f02bad 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -997,7 +997,7 @@ <string name="bubbles_user_education_title" msgid="5547017089271445797">"बबल वापरून चॅट करा"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"नवीन संभाषणे फ्लोटिंग आयकन किंवा बबल म्हणून दिसतात. बबल उघडण्यासाठी टॅप करा. हे हलवण्यासाठी ड्रॅग करा."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"बबल कधीही नियंत्रित करा"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"या अॅपमधून बुडबुडे बंद करण्यासाठी व्यवस्थापित करा वर टॅप करा"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"या अॅपमधून बबल बंद करण्यासाठी व्यवस्थापित करा वर टॅप करा"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"समजले"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेव्हिगेशन अपडेट केले. बदल करण्यासाठी, सेटिंग्जवर जा."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेव्हिगेशन अपडेट करण्यासाठी सेटिंग्जवर जा"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"मॅग्निफिकेशन ओव्हरले विंडो"</string> <string name="magnification_window_title" msgid="4863914360847258333">"मॅग्निफिकेशन विंडो"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"मॅग्निफिकेशन विंडो नियंत्रणे"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"क्विक नियंत्रणे"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"डिव्हाइस नियंत्रणे"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"तुमच्या कनेक्ट केलेल्या डिव्हाइससाठी नियंत्रणे जोडा"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"क्विक नियंत्रणे सेट करा"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"डिव्हाइस नियंत्रणे सेट करा"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"तुमची नियंत्रणे अॅक्सेस करण्यासाठी पॉवर बटण दाबून ठेवा"</string> <string name="controls_providers_title" msgid="6879775889857085056">"नियंत्रणे जोडण्यासाठी ॲप निवडा"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"नियंत्रणे"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"पॉवर मेनूमधून अॅक्सेस करण्यासाठी नियंत्रणे निवडा"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"हे हलवण्यासाठी नियंत्रण धरून ठेवा आणि ड्रॅग करा"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"सर्व नियंत्रणांची सूची लोड करता आली नाही."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"इतर"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"क्विक नियंत्रणांमध्ये जोडा"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"डिव्हाइस नियंत्रणांमध्ये जोडा"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"आवडीचे यामध्ये जोडा"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ने तुमच्या आवडीचे मध्ये जोडण्यासाठी या नियंत्रणाची शिफारस केली आहे."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"नियंत्रणे अपडेट केली आहेत"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index f61bc46da3ab..94334a6812db 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Tetingkap Tindanan Pembesaran"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Tetingkap Pembesaran"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Kawalan Tetingkap Pembesaran"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Kawalan pantas"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kawalan peranti"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Tambah kawalan untuk peranti yang disambungkan"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Sediakan kawalan pantas"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Sediakan kawalan peranti"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Tahan butang Kuasa untuk mengakses kawalan anda"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Pilih apl untuk menambah kawalan"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kawalan"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Pilih kawalan untuk diakses daripada menu kuasa"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Tahan dan seret kawalan untuk mengalih"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Senarai semua kawalan tidak dapat dimuatkan."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lain-lain"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Tambahkan pada kawalan pantas"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Tambahkan pada kawalan peranti"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Tambahkan pada kegemaran"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> mencadangkan kawalan ini untuk ditambahkan pada kegemaran anda."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kawalan dikemas kini"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index e3184f42d956..3dd9c8b915bc 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -67,7 +67,7 @@ <string name="wifi_debugging_message" msgid="5461204211731802995">"ကွန်ရက်အမည် (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi လိပ်စာ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"ဤကွန်ရက်ကို အမြဲခွင့်ပြုပါ"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"ခွင့်ပြုရန်"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"ကြိုးမဲ့ အမှားပြင်ဆင်ခြင်းကို ခွင့်မပြုပါ"</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"ကြိုးမဲ့ အမှားရှာပြင်ခြင်းကို ခွင့်မပြုပါ"</string> <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"ဤစက်ပစ္စည်းသို့ လက်ရှိဝင်ရောက်ထားသည့် အသုံးပြုသူသည် ကြိုးမဲ့ အမှားပြင်ဆင်ခြင်းကို ဖွင့်၍မရပါ။ ဤဝန်ဆောင်မှုကို အသုံးပြုရန် အဓိကအသုံးပြုသူအဖြစ်သို့ ပြောင်းပါ။"</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB ပို့တ် ပိတ်ပြီးပြီ"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"USB ပို့တ်ကို ပိတ်၍ သင့်ကိရိယာသို့ အရည် သို့မဟုတ် အမှိုက်စများ မဝင်စေရန် ကာကွယ်ပါ၊ မည်သည့် အပိုပစ္စည်းကိုမျှ အာရုံခံသိရှိနိုင်တော့မည် မဟုတ်ပါ။\n\nUSB ပို့တ်ကို ပြန်အသုံးပြုနိုင်သည့်အခါ သင့်ကိုအကြောင်းကြားပါမည်။"</string> @@ -500,7 +500,7 @@ <string name="battery_saver_notification_text" msgid="2617841636449016951">"လုပ်ကိုင်မှုကို လျှော့ချလျက် နောက်ခံ ဒေတာကို ကန့်သတ်သည်"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ဘက်ထရီ အားထိန်းကို ပိတ်ရန်"</string> <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> သည် အသံဖမ်းနေစဉ် (သို့) ကာစ်လုပ်နေစဉ် သင့်မျက်နှာပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်မှန်သမျှကို သုံးနိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ဤလုပ်ဆောင်ချက်ကို ပေးအပ်သည့် ဝန်ဆောင်မှုသည် အသံဖမ်းနေစဉ် (သို့) ကာစ်လုပ်နေစဉ် သင့်မျက်နှာပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်မှန်သမျှကို သုံးနိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ဤလုပ်ရပ်အတွက် ဝန်ဆောင်မှုသည် အသံဖမ်းနေစဉ် (သို့) ကာစ်လုပ်နေစဉ် သင့်မျက်နှာပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်မှန်သမျှကို သုံးနိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ဖမ်းယူခြင်း သို့မဟုတ် ကာစ်လုပ်ခြင်း စတင်မလား။"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> နှင့် ဖမ်းယူခြင်း သို့မဟုတ် ကာစ်လုပ်ခြင်း စတင်မလား။"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"နောက်ထပ် မပြပါနှင့်"</string> @@ -712,7 +712,7 @@ <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"မူရင်းသတ်မှတ်ချက်အဖြစ် <xliff:g id="APP_NAME_0">%1$s</xliff:g> စကားဝိုင်းအားလုံးကို ပူဖောင်းကွက်ပြုလုပ်သည်။ <xliff:g id="APP_NAME_1">%2$s</xliff:g> တွင် စီမံခန့်ခွဲပါ။"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ဆက်တင်များ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ဦးစားပေး"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"မကြာမီက ပူဖောင်းကွက်များ မရှိပါ"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"လတ်တလော ပူဖောင်းကွက်များ မရှိပါ"</string> <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"လတ်တလော ပူဖောင်းကွက်များနှင့် ပိတ်လိုက်သော ပူဖောင်းကွက်များကို ဤနေရာတွင် မြင်ရပါမည်"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ဤအကြောင်းကြားချက်များကို ပြုပြင်၍ မရပါ။"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ဤအကြောင်းကြားချက်အုပ်စုကို ဤနေရာတွင် စီစဉ်သတ်မှတ်၍ မရပါ"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"အသံတိတ်ထားသည်"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"သတိပေးခြင်း"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"ပူဖောင်းကွက်ကို ပြရန်"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"ပူဖောင်းကွက်ကို ဖယ်ရှားရန်"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"ပူဖောင်းကွက် ဖယ်ရှားရန်"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"ပင်မစာမျက်နှာတွင် ထည့်ရန်"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"အကြောင်းကြားချက် ထိန်းချုပ်မှုများ"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"စက်ပစ္စည်းဝန်ဆောင်မှုများ"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"ခေါင်းစဉ် မရှိပါ"</string> <string name="restart_button_description" msgid="6916116576177456480">"ဤအက်ပ်ကို ပြန်စတင်ပြီး မျက်နှာပြင်အပြည့်လုပ်ရန် တို့ပါ။"</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ပူဖောင်းကွက်များအတွက် ဆက်တင်များ"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ပူဖောင်းကွက်အတွက် ဆက်တင်များ"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"စီမံရန်"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> မှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> နှင့် နောက်ထပ် <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ခုမှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -994,9 +994,9 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ညာအောက်ခြေသို့ ရွှေ့ပါ"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"ပယ်ရန်"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"စကားဝိုင်းကို ပူဖောင်းကွက် မပြုလုပ်ပါနှင့်"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"ပူဖောင်းကွက်များ အသုံးပြုပြီး ချတ်လုပ်ခြင်း"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"ပူဖောင်းကွက် သုံး၍ ချတ်လုပ်ခြင်း"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"စကားဝိုင်းအသစ်များကို မျောနေသည့် သင်္ကေတများ သို့မဟုတ် ပူဖောင်းကွက်များအဖြစ် မြင်ရပါမည်။ ပူဖောင်းကွက်ကိုဖွင့်ရန် တို့ပါ။ ရွှေ့ရန် ၎င်းကို ဖိဆွဲပါ။"</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ပူဖောင်းကွက်ကို အချိန်မရွေး ထိန်းချုပ်ခြင်း"</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ပူဖောင်းကွက်ကို အချိန်မရွေး ထိန်းချုပ်ရန်"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ဤအက်ပ်မှနေ၍ ပူဖောင်းများကို ပိတ်ရန်အတွက် \'စီမံရန်\' ကို တို့ပါ"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ရပါပြီ"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"စနစ်လမ်းညွှန်ခြင်း အပ်ဒိတ်လုပ်ပြီးပါပြီ။ အပြောင်းအလဲများ ပြုလုပ်ရန် \'ဆက်တင်များ\' သို့သွားပါ။"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"ဝင်းဒိုး ထပ်ပိုးလွှာ ချဲ့ခြင်း"</string> <string name="magnification_window_title" msgid="4863914360847258333">"ဝင်းဒိုး ချဲ့ခြင်း"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"ဝင်းဒိုး ထိန်းချုပ်မှုများ ချဲ့ခြင်း"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"အမြန်ထိန်းချုပ်မှုများ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"စက်ပစ္စည်း ထိန်းချုပ်မှုများ"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"သင့်ချိတ်ဆက်ထားသော စက်များအတွက် ထိန်းချုပ်မှုများ ထည့်ပါ"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"အမြန်ထိန်းချုပ်မှုများကို စနစ်ထည့်သွင်းခြင်း"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"စက်ပစ္စည်းထိန်းချုပ်မှုများကို စနစ်ထည့်သွင်းခြင်း"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"သင့်ထိန်းချုပ်မှုများကို အသုံးပြုရန် \'ပါဝါ\' ခလုတ်ကို ဖိထားပါ"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ထိန်းချုပ်မှုများထည့်ရန် အက်ပ်ရွေးခြင်း"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"ထိန်းချုပ်မှုများ"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"ဖွင့်ပိတ်မီနူးမှ သုံးရန် ထိန်းချုပ်မှုများ ရွေးပါ"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"ထိန်းချုပ်မှုတစ်ခု ရွှေ့ရန် ၎င်းကိုဖိဆွဲပါ"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"ထိန်းချုပ်မှုများ ပြန်စီစဉ်ရန် ဖိပြီးဆွဲပါ"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"ထိန်းချုပ်မှုအားလုံး ဖယ်ရှားလိုက်သည်"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"ထိန်းချုပ်မှုအားလုံး၏ စာရင်းကို ဖွင့်၍မရပါ။"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"အခြား"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"အမြန်ထိန်းချုပ်မှု သို့ထည့်ခြင်း"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"စက်ပစ္စည်းထိန်းချုပ်မှုများသို့ ထည့်ရန်"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"အကြိုက်ဆုံးများသို့ ထည့်ရန်"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> သည် ဤခလုတ်ကို သင့်အကြိုက်ဆုံးများသို့ ထည့်ရန် အကြံပြုထားသည်။"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"ထိန်းချုပ်မှု အပ်ဒိတ်လုပ်ပြီးပြီ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 1614139d91f8..da8654847650 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -709,7 +709,7 @@ <string name="notification_channel_summary_default" msgid="3539949463907902037">"Får oppmerksomheten din med lyd eller vibrering."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Holder deg oppmerksom med en svevende snarvei til dette innholdet."</string> <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Vises øverst i en samtaledel og vises som en boble."</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Alle samtaler fra <xliff:g id="APP_NAME_0">%1$s</xliff:g> legges til i bobler som standard. Administrer i <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Alle samtaler fra <xliff:g id="APP_NAME_0">%1$s</xliff:g> vises i bobler som standard. Administrer i <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Innstillinger"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ingen nylige bobler"</string> @@ -993,7 +993,7 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flytt til nederst til venstre"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flytt til nederst til høyre"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Avvis"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ikke lag bobler for samtaler"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ikke vis samtaler i bobler"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat med bobler"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som flytende ikoner, eller bobler. Trykk for å åpne bobler. Dra for å flytte dem."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrollér bobler når som helst"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Overleggsvindu for forstørring"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Forstørringsvindu"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Kontroller for forstørringsvindu"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Hurtigkontroller"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Enhetskontroller"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Legg til kontroller for de tilkoblede enhetene dine"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Konfigurer hurtigkontroller"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurer enhetskontroller"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Hold inne av/på-knappen for å få tilgang til kontrollene"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Velg en app for å legge til kontroller"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kontroller"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Velg kontroller som er tilgjengelige fra av/på-menyen"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Hold og dra en kontroll for å flytte den"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Listen over alle kontroller kunne ikke lastes inn."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annet"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Legg til i hurtigkontroller"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Legg til i enhetskontroller"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Legg til som favoritt"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> har foreslått at du legger denne kontrollen til i favorittene dine."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrollene er oppdatert"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index e9f2c07ba18a..0fca63cfc813 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"अनुमति दिनुहोस्"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB डिबग गर्न अनुमति छैन"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"हाल यस यन्त्रमा साइन इन हुनुभएको प्रयोगकर्ताले USB डिबग सक्रिय गर्न सक्नुहुन्न। यो सुविधाको प्रयोग गर्न प्राथमिक प्रयोगकर्तामा बदल्नुहोस्।"</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"यस नेटवर्कमा वायरलेस डिबग गर्न दिने हो?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"यस नेटवर्कमा वायरलेस डिबगिङ सेवा प्रयोग गर्न दिने हो?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"नेटवर्कको नाम (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi ठेगाना (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"यस नेटवर्कमा सधैँ अनुमति दिनुहोस्"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"अनुमति दिनुहोस्"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"वायरलेस डिबग प्रक्रियाका लागि अनुमति छैन"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"हाल यस यन्त्रमा साइन इन हुनुभएका प्रयोगकर्ता वायरलेस डिबग प्रक्रिया सक्रिय गर्न सक्नुहुन्न। यो सुविधाको प्रयोग गर्न प्राथमिक प्रयोगकर्ताको खातामार्फत साइन इन गर्नुहोस्।"</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"वायरलेस डिबगिङ सेवालाई अनुमति दिइएको छैन"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"हाल यस यन्त्रमा साइन इन हुनुभएका प्रयोगकर्ता वायरलेस डिबगिङ सक्रिय गर्न सक्नुहुन्न। यो सुविधाको प्रयोग गर्न प्राथमिक प्रयोगकर्ताको खातामार्फत साइन इन गर्नुहोस्।"</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB पोर्ट असक्षम पारियो"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"तपाईंको यन्त्रलाई तरल पदार्थ वा धुलोबाट जोगाउन यसको USB पोर्ट असक्षम पारिएको छ र यसले कुनै पनि सहायक उपकरणहरू पहिचान गर्ने छैन।\n\nउक्त USB पोर्ट फेरि प्रयोग गर्दा हुन्छ भने तपाईंलाई यसबारे सूचित गरिने छ।"</string> <string name="usb_port_enabled" msgid="531823867664717018">"चार्जर तथा सामानहरू पत्ता लगाउन सक्षम पारिएको USB पोर्ट"</string> @@ -151,7 +151,7 @@ <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"ढाँचा प्रयोग गर्नुहोस्"</string> <string name="biometric_dialog_use_password" msgid="3445033859393474779">"पासवर्ड प्रयोग गर्नुहोस्"</string> <string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"PIN मिलेन"</string> - <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"ढाँचा मिलेन"</string> + <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"प्याटर्न मिलेन"</string> <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"पासवर्ड मिलेन"</string> <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"अत्यन्तै धेरै पटक गलत प्रयास गरिए। \n <xliff:g id="NUMBER">%d</xliff:g>सेकेन्ड पछि पुनः प्रयास गर्नुहोस्।"</string> <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"फेरि प्रयास गर्नुहोस्। <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> मध्ये <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> प्रयास।"</string> @@ -174,7 +174,7 @@ <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"तपाईंलाई खोज्दै…"</string> <string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"अनुहारको आइकन"</string> <string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"मिलाउने जुम बटन।"</string> - <string name="accessibility_compatibility_zoom_example" msgid="2617218726091234073">"स्क्रिनलाई सानोबाट ठूलो पार्नुहोस्।"</string> + <string name="accessibility_compatibility_zoom_example" msgid="2617218726091234073">"स्क्रिनलाई सानोबाट ठुलो पार्नुहोस्।"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लुटुथ जडान भयो।"</string> <string name="accessibility_bluetooth_disconnected" msgid="7195823280221275929">"ब्लुटुथसँग विच्छेद गरियो।"</string> <string name="accessibility_no_battery" msgid="3789287732041910804">"कुनै ब्याट्री छैन।"</string> @@ -712,7 +712,7 @@ <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> मार्फत भएका सबै वार्तालापहरू पूर्वनिर्धारित रूपमा बबलमा देखिन्छन्। <xliff:g id="APP_NAME_1">%2$s</xliff:g> मा गई व्यवस्थापन गर्नुहोस्।"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिङ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"हालसालै खारेज गरिएको कुनै पनि बबल छैन"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"हालैका बबलहरू छैनन्"</string> <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"हालैका बबल र खारेज गरिएका बबलहरू यहाँ देखिने छन्"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"यी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"यहाँबाट सूचनाहरूको यो समूह कन्फिगर गर्न सकिँदैन"</string> @@ -866,16 +866,16 @@ <string name="tuner_low_priority" msgid="8412666814123009820">"कम प्राथमिकताका सूचना आइकनहरू देखाउनुहोस्"</string> <string name="other" msgid="429768510980739978">"अन्य"</string> <string name="accessibility_divider" msgid="2830785970889237307">"विभाजित-स्क्रिन छुट्याउने"</string> - <string name="accessibility_action_divider_left_full" msgid="7598733539422375847">"बायाँ भाग पूर्ण स्क्रिन"</string> + <string name="accessibility_action_divider_left_full" msgid="7598733539422375847">"बायाँ भाग फुल स्क्रिन"</string> <string name="accessibility_action_divider_left_70" msgid="4919312892541727761">"बायाँ भाग ७०%"</string> <string name="accessibility_action_divider_left_50" msgid="3664701169564893826">"बायाँ भाग ५०%"</string> <string name="accessibility_action_divider_left_30" msgid="4358145268046362088">"बायाँ भाग ३०%"</string> - <string name="accessibility_action_divider_right_full" msgid="8576057422864896305">"दायाँ भाग पूर्ण स्क्रिन"</string> - <string name="accessibility_action_divider_top_full" msgid="4243901660795169777">"माथिल्लो भाग पूर्ण स्क्रिन"</string> + <string name="accessibility_action_divider_right_full" msgid="8576057422864896305">"दायाँ भाग फुल स्क्रिन"</string> + <string name="accessibility_action_divider_top_full" msgid="4243901660795169777">"माथिल्लो भाग फुल स्क्रिन"</string> <string name="accessibility_action_divider_top_70" msgid="6941226213260515072">"माथिल्लो भाग ७०%"</string> <string name="accessibility_action_divider_top_50" msgid="6275211443706497621">"माथिल्लो भाग ५०%"</string> <string name="accessibility_action_divider_top_30" msgid="5780597635887574916">"माथिल्लो भाग ३०%"</string> - <string name="accessibility_action_divider_bottom_full" msgid="7352434720610115395">"तल्लो भाग पूर्ण स्क्रिन"</string> + <string name="accessibility_action_divider_bottom_full" msgid="7352434720610115395">"तल्लो भाग फुल स्क्रिन"</string> <string name="accessibility_qs_edit_tile_label" msgid="9079791448815232967">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>। सम्पादन गर्नाका लागि डबल ट्याप गर्नुहोस्।"</string> <string name="accessibility_qs_edit_add_tile_label" msgid="8292218072049068613">"<xliff:g id="TILE_NAME">%1$s</xliff:g>। थप्नका लागि डबल ट्याप गर्नुहोस्।"</string> <string name="accessibility_qs_edit_move_tile" msgid="6027997446473163426">"<xliff:g id="TILE_NAME">%1$s</xliff:g> लाई सार्नुहोस्"</string> @@ -982,7 +982,7 @@ <string name="sensor_privacy_mode" msgid="4462866919026513692">"सेन्सरहरू निष्क्रिय छन्"</string> <string name="device_services" msgid="1549944177856658705">"यन्त्रका सेवाहरू"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक छैन"</string> - <string name="restart_button_description" msgid="6916116576177456480">"यो अनुप्रयोग पुनः सुरु गर्न ट्याप गर्नुहोस् र पूर्ण स्क्रिन मोडमा जानुहोस्।"</string> + <string name="restart_button_description" msgid="6916116576177456480">"यो अनुप्रयोग पुनः सुरु गर्न ट्याप गर्नुहोस् र फुल स्क्रिन मोडमा जानुहोस्।"</string> <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> का बबलसम्बन्धी सेटिङहरू"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"व्यवस्थापन गर्नुहोस्"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> को <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -993,11 +993,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"पुछारमा बायाँतिर सार्नुहोस्"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"पुछारमा दायाँतिर सार्नुहोस्"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"हटाउनुहोस्"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"वार्तालाप बबलमा नदेखाइयोस्"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"वार्तालाप बबलको रूपमा नदेखाइयोस्"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"बबलहरू प्रयोग गरी कुराकानी गर्नुहोस्"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"नयाँ वार्तालापहरू तैरने आइकन वा बबलका रूपमा देखिन्छन्। बबल खोल्न ट्याप गर्नुहोस्। बबल सार्न त्यसलाई ड्र्याग गर्नुहोस्।"</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"जुनसुकै बेला बबलहरू व्यवस्थापन गर्नुहोस्"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"यो अनुप्रयोगमा बबल निष्क्रिय पार्न व्यवस्थापन गर्नुहोस् नामक बटन ट्याप गर्नुहोस्"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"नयाँ वार्तालापहरू तैरने आइकन वा बबलका रूपमा देखिन्छन्। बबल खोल्न ट्याप गर्नुहोस्। बबल सार्न सो बबललाई ड्र्याग गर्नुहोस्।"</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"जुनसुकै बेला बबलहरू नियन्त्रण गर्नुहोस्"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"यो अनुप्रयोगबाट आएका बबलहरू निष्क्रिय पार्न व्यवस्थापन गर्नुहोस् नामक बटनमा ट्याप गर्नुहोस्"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"बुझेँ"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"प्रणालीको नेभिगेसन अद्यावधिक गरियो। परिवर्तन गर्न सेटिङमा जानुहोस्।"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"प्रणालीको नेभिगेसन अद्यावधिक गर्न सेटिङमा जानुहोस्"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"म्याग्निफिकेसन ओभरले विन्डो"</string> <string name="magnification_window_title" msgid="4863914360847258333">"म्याग्निफिकेसन विन्डो"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"म्याग्निफिकेसन विन्डोका नियन्त्रणहरू"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"द्रुत नियन्त्रणहरू"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"यन्त्रले नियन्त्रण गर्न सक्ने कुराहरू"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"आफ्ना जोडिएका यन्त्रहरूका लागि नियन्त्रण सुविधाहरू थप्नुहोस्"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"द्रुत नियन्त्रणहरू सेटअप गर्नुहोस्"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"यन्त्रले नियन्त्रण गर्न सक्ने कुराहरू सेटअप गर्नुहोस्"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"आफ्ना नियन्त्रणहरूमाथि पहुँच राख्न पावर बटन थिचिराख्नुहोस्"</string> <string name="controls_providers_title" msgid="6879775889857085056">"नियन्त्रणहरू थप्न अनुप्रयोग छनौट गर्नुहोस्"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"नियन्त्रणहरू"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"पावर मेनुबाट प्रयोग गर्न चाहेका नियन्त्रण सुविधाहरू छान्नुहोस्"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"कुनै नियन्त्रण सुविधा सार्न त्यसलाई थिचेर ड्र्याग गर्नुहोस्"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"सबै नियन्त्रणहरूको सूची लोड गर्न सकिएन।"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"द्रुत नियन्त्रणहरूमा थप्नुहोस्"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"यन्त्रले नियन्त्रण गर्न सक्ने कुराहरूको सूचीमा थप्नुहोस्"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"मन पर्ने कुराहरूमा थप्नुहोस्"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ले यो नियन्त्रण तपाईंका मन पर्ने कुराहरूमा थप्न सुझाव सिफारिस गरेको छ।"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"नियन्त्रण सुविधाहरू अद्यावधिक गरिए"</string> diff --git a/packages/SystemUI/res/values-ne/strings_tv.xml b/packages/SystemUI/res/values-ne/strings_tv.xml index 6998f39cec2b..20411351b549 100644 --- a/packages/SystemUI/res/values-ne/strings_tv.xml +++ b/packages/SystemUI/res/values-ne/strings_tv.xml @@ -22,7 +22,7 @@ <string name="notification_channel_tv_pip" msgid="844249465483874817">"Picture-in-Picture"</string> <string name="pip_notification_unknown_title" msgid="4413256731340767259">"(शीर्षकविहीन कार्यक्रम)"</string> <string name="pip_close" msgid="5775212044472849930">"PIP लाई बन्द गर्नुहोस्"</string> - <string name="pip_fullscreen" msgid="3877997489869475181">"पूर्ण स्क्रिन"</string> + <string name="pip_fullscreen" msgid="3877997489869475181">"फुल स्क्रिन"</string> <string name="mic_active" msgid="5766614241012047024">"माइक्रोफोन सक्रिय छ"</string> <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ले तपाईंको माइक्रोफोनमाथि पहुँच राख्यो"</string> </resources> diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index 9b0fe465deee..93aa2701ad07 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -86,4 +86,15 @@ <color name="GM2_red_500">#E25142</color> <color name="GM2_yellow_500">#F5C518</color> + <!-- Icon color for user avatars in keyguard user switcher --> + <color name="kg_user_switcher_avatar_icon_color">@android:color/background_light</color> + <!-- Icon color for selected user avatars in keyguard user switcher --> + <color name="kg_user_switcher_selected_avatar_icon_color">#202124</color> + <!-- Icon color for user avatars in quick settings user switcher --> + <color name="qs_user_switcher_avatar_icon_color">@android:color/background_light</color> + <!-- Icon color for selected user avatars in quick settings user switcher --> + <color name="qs_user_switcher_selected_avatar_icon_color">#202124</color> + <!-- Color of background circle of user avatars in quick settings user switcher --> + <color name="qs_user_switcher_avatar_background">#3C4043</color> + </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index baeca5b145b7..5b021969f385 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Het maken van screenshots wordt niet toegestaan door de app of je organisatie"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Screenshot sluiten"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Screenshot openen"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Schermrecorder"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Schermopname"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Doorlopende melding voor een schermopname-sessie"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Opname starten?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Tijdens de opname kan het Android-systeem gevoelige informatie opnemen die zichtbaar is op je scherm of wordt afgespeeld op je apparaat. Dit omvat wachtwoorden, betalingsgegevens, foto\'s, berichten en audio."</string> @@ -712,7 +712,7 @@ <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Alle gesprekken uit <xliff:g id="APP_NAME_0">%1$s</xliff:g> worden standaard als bubbels weergegeven. Beheer dit in <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Instellingen"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Geen recente ballonnen"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Geen recente bubbels"</string> <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recente bubbels en gesloten bubbels worden hier weergegeven"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Deze meldingen kunnen niet worden aangepast."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Deze groep meldingen kan hier niet worden geconfigureerd"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"Zonder geluid"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Waarschuwen"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"Ballon weergeven"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Ballonnen verwijderen"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Bubbels verwijderen"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Toevoegen aan startscherm"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"beheeropties voor meldingen"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"Apparaatservices"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Geen titel"</string> <string name="restart_button_description" msgid="6916116576177456480">"Tik om deze app opnieuw te starten en te openen op het volledige scherm."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Instellingen voor <xliff:g id="APP_NAME">%1$s</xliff:g>-ballonnen"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Instellingen voor <xliff:g id="APP_NAME">%1$s</xliff:g>-bubbels"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"Beheren"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g> en nog <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Overlay voor vergrotingsvenster"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingsvenster"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Bediening van vergrotingsvenster"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Snelle bedieningselementen"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Apparaatopties"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Bedieningselementen voor je gekoppelde apparaten toevoegen"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Snelle bedieningselementen instellen"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Apparaatopties instellen"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Houd de aan/uit-knop ingedrukt voor toegang tot de bedieningselementen"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Kies de app waaraan je bedieningselementen wilt toevoegen"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Bedieningselementen"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Kies bedieningselementen die je vanaf het menu Voeding wilt kunnen gebruiken"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Houd een bedieningselement vast en sleep om het te verplaatsen"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Kan lijst met alle bedieningselementen niet laden."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Overig"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Toevoegen aan snelle bediening"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Toevoegen aan apparaatopties"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Toevoegen aan favorieten"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> heeft voorgesteld dit bedieningselement toe te voegen aan je favorieten."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Bedieningselementen geüpdated"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index d4796d69dd9e..cf15c83ea416 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -209,7 +209,7 @@ <string name="accessibility_two_bars" msgid="1335676987274417121">"ଦୁଇଟି ବାର୍ ଅଛି।"</string> <string name="accessibility_three_bars" msgid="819417766606501295">"ତିନୋଟି ବାର୍ ଅଛି।"</string> <string name="accessibility_signal_full" msgid="5920148525598637311">"ସିଗ୍ନାଲ୍ ଫୁଲ୍ ଅଛି।"</string> - <string name="accessibility_desc_on" msgid="2899626845061427845">"ଅନ୍।"</string> + <string name="accessibility_desc_on" msgid="2899626845061427845">"ଚାଲୁ।"</string> <string name="accessibility_desc_off" msgid="8055389500285421408">"ଅଫ୍।"</string> <string name="accessibility_desc_connected" msgid="3082590384032624233">"ସଂଯୁକ୍ତ।"</string> <string name="accessibility_desc_connecting" msgid="8011433412112903614">"ସଂଯୋଗ କରୁଛି।"</string> @@ -232,7 +232,7 @@ <string name="cell_data_off_content_description" msgid="9165555931499878044">"ମୋବାଇଲ୍ ଡାଟା ବନ୍ଦ ଅଛି"</string> <string name="not_default_data_content_description" msgid="6757881730711522517">"ବ୍ୟବହୃତ ଡାଟା ପାଇଁ ସେଟ୍ ହୋଇନାହିଁ"</string> <string name="cell_data_off" msgid="4886198950247099526">"ଅଫ୍ ଅଛି"</string> - <string name="accessibility_bluetooth_tether" msgid="6327291292208790599">"ବ୍ଲୁଟୂଥ୍ ଟିଥରିଙ୍ଗ।"</string> + <string name="accessibility_bluetooth_tether" msgid="6327291292208790599">"ବ୍ଲୁଟୁଥ ଟିଥରିଂ।"</string> <string name="accessibility_airplane_mode" msgid="1899529214045998505">"ଏରୋପ୍ଲେନ୍ ମୋଡ୍।"</string> <string name="accessibility_vpn_on" msgid="8037549696057288731">"VPN ଅନ୍।"</string> <string name="accessibility_no_sims" msgid="5711270400476534667">"କୌଣସି SIM କାର୍ଡ ନାହିଁ।"</string> @@ -276,7 +276,7 @@ <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ।"</string> <string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\"କୁ ବନ୍ଦ କରାଯାଇଛି।"</string> <string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଚାଲୁ ଅଛି।"</string> - <string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ବ୍ଲୁଟୂଥ୍।"</string> + <string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"ବ୍ଲୁଟୁଥ।"</string> <string name="accessibility_quick_settings_bluetooth_off" msgid="3795983516942423240">"ବ୍ଲୁଟୂଥ୍ ଅଫ୍ ଅଛି।"</string> <string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"ବ୍ଲୁଟୂଥ୍ ଅନ୍ ଅଛି।"</string> <string name="accessibility_quick_settings_bluetooth_connecting" msgid="7362294657419149294">"ବ୍ଲୁଟୂଥ୍ ସଂଯୋଗ ହେଉଛି।"</string> @@ -344,7 +344,7 @@ <string name="quick_settings_dnd_priority_label" msgid="6251076422352664571">"କେବଳ ପ୍ରାଥମିକତା"</string> <string name="quick_settings_dnd_alarms_label" msgid="1241780970469630835">"କେବଳ ଆଲାର୍ମ"</string> <string name="quick_settings_dnd_none_label" msgid="8420869988472836354">"ସମ୍ପୂର୍ଣ୍ଣ ନୀରବ"</string> - <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ବ୍ଲୁଟୂଥ୍"</string> + <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ବ୍ଲୁଟୁଥ"</string> <string name="quick_settings_bluetooth_multiple_devices_label" msgid="6595808498429809855">"ବ୍ଲୁଟୂଥ୍ (<xliff:g id="NUMBER">%d</xliff:g>ଟି ଡିଭାଇସ୍)"</string> <string name="quick_settings_bluetooth_off_label" msgid="6375098046500790870">"ବ୍ଲୁଟୂଥ୍ ଅଫ୍"</string> <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ପେୟାର୍ ହୋଇଥିବା କୌଣସି ଡିଭାଇସ୍ ଉପଲବ୍ଧ ନାହିଁ"</string> @@ -394,7 +394,7 @@ <string name="quick_settings_connected" msgid="3873605509184830379">"ସଂଯୁକ୍ତ"</string> <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"କନେକ୍ଟ ରହିଛି, ବ୍ୟାଟେରୀ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="quick_settings_connecting" msgid="2381969772953268809">"ସଂଯୋଗ କରୁଛି..."</string> - <string name="quick_settings_tethering_label" msgid="5257299852322475780">"ଟିଥରିଙ୍ଗ"</string> + <string name="quick_settings_tethering_label" msgid="5257299852322475780">"ଟିଥରିଂ"</string> <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"ହଟସ୍ପଟ୍"</string> <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"ଅନ୍ ହେଉଛି…"</string> <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"ଡାଟା ସେଭର୍ ଅନ୍ ଅଛି"</string> @@ -597,7 +597,7 @@ <string name="screen_pinning_toast" msgid="2083944237147005811">"ଏହି ସ୍କ୍ରୀନ୍କୁ ଅନପିନ୍ କରିବା ପାଇଁ, ବ୍ୟାକ୍ ଏବଂ ଓଭରଭ୍ୟୁ ବଟନ୍କୁ ଦାବିଧରନ୍ତୁ"</string> <string name="screen_pinning_toast_recents_invisible" msgid="6343770487795352573">"ଏହି ସ୍କ୍ରୀନ୍କୁ ଅନପିନ୍ କରିବା ପାଇଁ, ବ୍ୟାକ୍ ଏବଂ ହୋମ୍ ବଟନ୍କୁ ଦାବିଧରନ୍ତୁ"</string> <string name="screen_pinning_toast_gesture_nav" msgid="2884536903398445645">"ଏହି ସ୍କ୍ରୀନ୍କୁ ଅନପିନ୍ କରିବା ପାଇଁ, ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ ଏବଂ ଧରି ରଖନ୍ତୁ"</string> - <string name="screen_pinning_positive" msgid="3285785989665266984">"ବୁଝିଲି"</string> + <string name="screen_pinning_positive" msgid="3285785989665266984">"ବୁଝିଗଲି"</string> <string name="screen_pinning_negative" msgid="6882816864569211666">"ନାହିଁ, ଥାଉ"</string> <string name="screen_pinning_start" msgid="5695091877402422575">"ସ୍କ୍ରୀନ୍କୁ ପିନ୍ କରାଗଲା"</string> <string name="screen_pinning_exit" msgid="5114993350662745840">"ସ୍କ୍ରୀନ୍ ଅନପିନ୍ ହୋଇଗଲା"</string> @@ -633,7 +633,7 @@ <string name="output_calls_title" msgid="7085583034267889109">"ଫୋନ୍ କଲ୍ ଆଉଟପୁଟ୍"</string> <string name="output_none_found" msgid="5488087293120982770">"କୌଣସି ଡିଭାଇସ୍ ମିଳିଲା ନାହିଁ"</string> <string name="output_none_found_service_off" msgid="935667567681386368">"କୌଣସି ଡିଭାଇସ୍ ମିଳିଲା ନାହିଁ। <xliff:g id="SERVICE">%1$s</xliff:g> ଅନ୍ କରି ଦେଖନ୍ତୁ"</string> - <string name="output_service_bt" msgid="4315362133973911687">"ବ୍ଲୁଟୂଥ୍"</string> + <string name="output_service_bt" msgid="4315362133973911687">"ବ୍ଲୁଟୁଥ"</string> <string name="output_service_wifi" msgid="9003667810868222134">"ୱାଇ-ଫାଇ"</string> <string name="output_service_bt_wifi" msgid="7186882540475524124">"ବ୍ଲୁଟୂଥ୍ ଓ ୱାଇ-ଫାଇ"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"ସିଷ୍ଟମ୍ UI ଟ୍ୟୁନର୍"</string> @@ -679,7 +679,7 @@ <string name="do_not_silence" msgid="4982217934250511227">"ନିରବ କରନ୍ତୁ ନାହିଁ"</string> <string name="do_not_silence_block" msgid="4361847809775811849">"ନିରବ କିମ୍ବା ବ୍ଲକ୍ କରନ୍ତୁ ନାହିଁ"</string> <string name="tuner_full_importance_settings" msgid="1388025816553459059">"ପାୱାର୍ ବିଜ୍ଞପ୍ତି କଣ୍ଟ୍ରୋଲ୍"</string> - <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"ଅନ୍"</string> + <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"ଚାଲୁ"</string> <string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"ଅଫ୍"</string> <string name="power_notification_controls_description" msgid="1334963837572708952">"ପାୱାର୍ ବିଜ୍ଞପ୍ତି କଣ୍ଟ୍ରୋଲ୍ରେ, ଆପଣ ଏକ ଆପ୍ ବିଜ୍ଞପ୍ତି ପାଇଁ 0 ରୁ 5 ଗୁରୁତ୍ୱ ସ୍ତର ସେଟ୍ କରିହେବେ। \n\n"<b>"ସ୍ତର 5"</b>" \n- ବିଜ୍ଞପ୍ତି ତାଲିକାର ଶୀର୍ଷରେ ଦେଖାନ୍ତୁ \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ \n- ସର୍ବଦା ପିକ୍ କରନ୍ତୁ \n\n"<b>"ସ୍ତର 4"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- ସର୍ବଦା ପିକ୍ କରନ୍ତୁ \n\n"<b>"ସ୍ତର 3"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- କଦାପି ପିକ୍ କରନ୍ତୁ ନାହିଁ \n\n"<b>"ସ୍ତର 2"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- କଦାପି ପିକ୍ କରନ୍ତୁ ନାହିଁ \n- କଦାପି ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେଟ୍ କରନ୍ତୁ ନାହିଁ \n\n"<b>"ସ୍ତର 1"</b>" \n- ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ବାଧା ଦେବା ବ୍ଲକ୍ କରନ୍ତୁ \n- କଦାପି ପିକ୍ କରନ୍ତୁ ନାହିଁ \n- କଦାପି ସାଉଣ୍ଡ ଓ ଭାଇବ୍ରେଟ୍ କରନ୍ତୁ ନାହିଁ \n- ଲକ୍ ସ୍କ୍ରୀନ୍ ଓ ଷ୍ଟାଟସ୍ ବାର୍ରୁ ଲୁଚାନ୍ତୁ \n- ବିଜ୍ଞପ୍ତି ତାଲିକାର ନିମ୍ନରେ ଦେଖାନ୍ତୁ \n\n"<b>"ସ୍ତର 0"</b>" \n- ଆପରୁ ସମସ୍ତ ବିଜ୍ଞପ୍ତି ବ୍ଲକ୍ କରନ୍ତୁ"</string> <string name="notification_header_default_channel" msgid="225454696914642444">"ବିଜ୍ଞପ୍ତି"</string> @@ -977,7 +977,7 @@ <string name="auto_saver_enabled_title" msgid="4294726198280286333">"ଆଗରୁ ସେଟ୍ କରିଥିବା ସମୟ ଅନୁସାରେ ବ୍ୟାଟେରୀ ସେଭର୍ ଅନ୍ ହୋଇଛି"</string> <string name="auto_saver_enabled_text" msgid="7889491183116752719">"ଚାର୍ଜ <xliff:g id="PERCENTAGE">%d</xliff:g>%%ରୁ କମ୍ ହେଲେ ବ୍ୟାଟେରୀ ସେଭର୍ ଆପେ ଅନ୍ ହୋଇଯିବ।"</string> <string name="open_saver_setting_action" msgid="2111461909782935190">"ସେଟିଙ୍ଗ"</string> - <string name="auto_saver_okay_action" msgid="7815925750741935386">"ବୁଝିଲି"</string> + <string name="auto_saver_okay_action" msgid="7815925750741935386">"ବୁଝିଗଲି"</string> <string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ହିପ୍ ଡମ୍ପ୍ କରନ୍ତୁ"</string> <string name="sensor_privacy_mode" msgid="4462866919026513692">"ସେନ୍ସର୍ଗୁଡ଼ିକ ବନ୍ଦ ଅଛି"</string> <string name="device_services" msgid="1549944177856658705">"ଡିଭାଇସ୍ ସେବାଗୁଡିକ"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ଓଭର୍ଲେ ୱିଣ୍ଡୋ"</string> <string name="magnification_window_title" msgid="4863914360847258333">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"ଦ୍ରୁତ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"ଆପଣଙ୍କ ସଂଯୁକ୍ତ ଥିବା ଡିଭାଇସଗୁଡ଼ିକ ପାଇଁ ନିୟନ୍ତ୍ରଣ ଯୋଗ କରନ୍ତୁ"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"ଦ୍ରୁତ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"ଆପଣଙ୍କ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଆକ୍ସେସ୍ କରିବାକୁ ପାୱାର ବଟନକୁ ଧରି ରଖନ୍ତୁ"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଯୋଗ କରିବାକୁ ଆପ୍ ବାଛନ୍ତୁ"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"ପାୱାର ମେନୁରୁ ଆକ୍ସେସ୍ କରିବାକୁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ବାଛନ୍ତୁ"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"ଏକ ନିୟନ୍ତ୍ରଣକୁ ମୁଭ୍ କରିବାକୁ ଏହାକୁ ଧରି ଟାଣନ୍ତୁ"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"ସବୁ ନିୟନ୍ତ୍ରଣର ତାଲିକା ଲୋଡ୍ କରିପାରିଲା ନାହିଁ।"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ଅନ୍ୟ"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"ଦ୍ରୁତ ନିୟନ୍ତ୍ରଣରେ ଯୋଗ କରନ୍ତୁ"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକରେ ଯୋଗ କରନ୍ତୁ"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"ପସନ୍ଦଗୁଡ଼ିକରେ ଯୋଗ କରନ୍ତୁ"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"ଏହି ନିୟନ୍ତ୍ରଣକୁ ଆପଣଙ୍କ ପସନ୍ଦଗୁଡ଼ିକରେ ଯୋଗ କରିବାକୁ <xliff:g id="APP">%s</xliff:g> ପ୍ରସ୍ତାବ ଦେଇଛି।"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଅପଡେଟ୍ କରାଯାଇଛି"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 9a7201bdbec1..1b78d13df43e 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -20,7 +20,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4811759950673118541">"ਸਿਸਟਮ UI"</string> - <string name="status_bar_clear_all_button" msgid="2491321682873657397">"ਹਟਾਓ"</string> + <string name="status_bar_clear_all_button" msgid="2491321682873657397">"ਕਲੀਅਰ ਕਰੋ"</string> <string name="status_bar_no_notifications_title" msgid="7812479124981107507">"ਕੋਈ ਸੂਚਨਾਵਾਂ ਨਹੀਂ"</string> <string name="status_bar_ongoing_events_title" msgid="3986169317496615446">"ਜਾਰੀ"</string> <string name="status_bar_latest_events_title" msgid="202755896454005436">"ਸੂਚਨਾਵਾਂ"</string> @@ -708,12 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"ਤੁਹਾਨੂੰ ਬਿਨਾਂ ਧੁਨੀ ਅਤੇ ਥਰਥਰਾਹਟ ਦੇ ਫੋਕਸ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰਦਾ ਹੈ।"</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"ਧੁਨੀ ਅਤੇ ਥਰਥਰਾਹਟ ਨਾਲ ਤੁਹਾਡਾ ਧਿਆਨ ਖਿੱਚਦੀ ਹੈ।"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ਇਸ ਸਮੱਗਰੀ ਦੇ ਅਸਥਿਰ ਸ਼ਾਰਟਕੱਟ ਨਾਲ ਆਪਣਾ ਧਿਆਨ ਕੇਂਦਰਿਤ ਰੱਖੋ।"</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਦੇ ਉੱਪਰ ਅਤੇ ਬੁਲਬੁਲਿਆਂ ਦੇ ਤੌਰ \'ਤੇ ਦਿਖਾਉਂਦਾ ਹੈ।"</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਵੱਲੋਂ ਸਾਰੀਆਂ ਗੱਲਾਂਬਾਤਾਂ \'ਤੇ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਤੌਰ \'ਤੇ ਬੁਲਬੁਲੇ ਲਾਏ ਜਾਂਦੇ ਹਨ। <xliff:g id="APP_NAME_1">%2$s</xliff:g> ਵਿੱਚ ਪ੍ਰਬੰਧਨ ਕਰੋ।"</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਦੇ ਉੱਪਰ ਅਤੇ ਬਬਲ ਦੇ ਤੌਰ \'ਤੇ ਦਿਖਾਉਂਦਾ ਹੈ।"</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਵੱਲੋਂ ਸਾਰੀਆਂ ਗੱਲਾਂਬਾਤਾਂ \'ਤੇ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਤੌਰ \'ਤੇ ਬਬਲ ਲਾਏ ਜਾਂਦੇ ਹਨ। <xliff:g id="APP_NAME_1">%2$s</xliff:g> ਵਿੱਚ ਪ੍ਰਬੰਧਨ ਕਰੋ।"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ਸੈਟਿੰਗਾਂ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ਤਰਜੀਹ"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ਕੋਈ ਹਾਲੀਆ ਬੁਲਬੁਲਾ ਨਹੀਂ"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ਹਾਲੀਆ ਬੁਲਬੁਲੇ ਅਤੇ ਖਾਰਜ ਕੀਤੇ ਬੁਲਬੁਲੇ ਇੱਥੇ ਦਿਸਣਗੇ"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ਕੋਈ ਹਾਲੀਆ ਬਬਲ ਨਹੀਂ"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ਹਾਲੀਆ ਬਬਲ ਅਤੇ ਖਾਰਜ ਕੀਤੇ ਬਬਲ ਇੱਥੇ ਦਿਸਣਗੇ"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ਇਹ ਸੂਚਨਾਵਾਂ ਦਾ ਗਰੁੱਪ ਇੱਥੇ ਸੰਰੂਪਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"ਇੱਕ ਐਪ ਦੀ ਥਾਂ \'ਤੇ ਦੂਜੀ ਐਪ ਰਾਹੀਂ ਦਿੱਤੀ ਗਈ ਸੂਚਨਾ"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"ਚੁੱਪ ਕਰਵਾਈਆਂ ਗਈਆਂ"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"ਸੁਚੇਤਨਾ"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"ਬੁਲਬੁਲਾ ਦਿਖਾਓ"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"ਬੁਲਬੁਲੇ ਹਟਾਓ"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"ਬਬਲ ਹਟਾਓ"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"ਸੂਚਨਾ ਕੰਟਰੋਲ"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string> <string name="restart_button_description" msgid="6916116576177456480">"ਇਸ ਐਪ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਅਤੇ ਪੂਰੀ-ਸਕ੍ਰੀਨ ਮੋਡ \'ਤੇ ਜਾਓ।"</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਬੁਲਬੁਲਿਆਂ ਲਈ ਸੈਟਿੰਗਾਂ"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਬਬਲ ਲਈ ਸੈਟਿੰਗਾਂ"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਅਤੇ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ਹੋਰਾਂ ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -993,11 +993,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ਹੇਠਾਂ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ਹੇਠਾਂ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"ਖਾਰਜ ਕਰੋ"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ਗੱਲਬਾਤ \'ਤੇ ਬੁਲਬੁਲੇ ਨਾ ਲਾਓ"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"ਬੁਲਬੁਲੇ ਵਰਤਦੇ ਹੋਏ ਚੈਟ ਕਰੋ"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"ਨਵੀਆਂ ਗੱਲਾਂਬਾਤਾਂ ਫਲੋਟਿੰਗ ਪ੍ਰਤੀਕਾਂ ਜਾਂ ਬੁਲਬੁਲਿਆਂ ਦੇ ਰੂਪ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ। ਬੁਲਬੁਲਿਆਂ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਇਸਨੂੰ ਲਿਜਾਣ ਲਈ ਘਸੀਟੋ।"</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ਬੁਲਬੁਲਿਆਂ ਨੂੰ ਕਿਸੇ ਵੇਲੇ ਵੀ ਕੰਟਰੋਲ ਕਰੋ"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ਇਸ ਐਪ \'ਤੇ ਬੁਲਬੁਲੇ ਬੰਦ ਕਰਨ ਲਈ \'ਪ੍ਰਬੰਧਨ ਕਰੋ\' \'ਤੇ ਟੈਪ ਕਰੋ"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ਗੱਲਬਾਤ \'ਤੇ ਬਬਲ ਨਾ ਲਾਓ"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"ਬਬਲ ਵਰਤਦੇ ਹੋਏ ਚੈਟ ਕਰੋ"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"ਨਵੀਆਂ ਗੱਲਾਂਬਾਤਾਂ ਫਲੋਟਿੰਗ ਪ੍ਰਤੀਕਾਂ ਜਾਂ ਬਬਲ ਦੇ ਰੂਪ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ। ਬਬਲ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਇਸਨੂੰ ਲਿਜਾਣ ਲਈ ਘਸੀਟੋ।"</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ਬਬਲ ਨੂੰ ਕਿਸੇ ਵੇਲੇ ਵੀ ਕੰਟਰੋਲ ਕਰੋ"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ਇਸ ਐਪ \'ਤੇ ਬਬਲ ਬੰਦ ਕਰਨ ਲਈ \'ਪ੍ਰਬੰਧਨ ਕਰੋ\' \'ਤੇ ਟੈਪ ਕਰੋ"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ਸਮਝ ਲਿਆ"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਅੱਪਡੇਟ ਹੋ ਗਿਆ। ਤਬਦੀਲੀਆਂ ਕਰਨ ਲਈ, ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ।"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"ਵੱਡਦਰਸ਼ੀਕਰਨ ਓਵਰਲੇ Window"</string> <string name="magnification_window_title" msgid="4863914360847258333">"ਵੱਡਦਰਸ਼ੀਕਰਨ Window"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"ਵੱਡਦਰਸ਼ੀਕਰਨ Window ਦੇ ਕੰਟਰੋਲ"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"ਤਤਕਾਲ ਕੰਟਰੋਲ"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"ਡੀਵਾਈਸ ਕੰਟਰੋਲ"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"ਆਪਣੇ ਕਨੈਕਟ ਕੀਤੇ ਡੀਵਾਈਸਾਂ ਲਈ ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"ਤਤਕਾਲ ਕੰਟਰੋਲਾਂ ਦਾ ਸੈੱਟਅੱਪ ਕਰੋ"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"ਡੀਵਾਈਸ ਕੰਟਰੋਲਾਂ ਦਾ ਸੈੱਟਅੱਪ ਕਰੋ"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"ਆਪਣੇ ਕੰਟਰੋਲਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ ਪਾਵਰ ਬਟਨ ਦਬਾ ਕੇ ਰੱਖੋ"</string> <string name="controls_providers_title" msgid="6879775889857085056">"ਕੰਟਰੋਲਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਐਪ ਚੁਣੋ"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"ਕੰਟਰੋਲ"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"ਪਹੁੰਚ ਕਰਨ ਲਈ ਪਾਵਰ ਮੀਨੂ ਤੋਂ ਕੰਟਰੋਲ ਚੁਣੋ"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"ਕਿਸੇ ਕੰਟਰੋਲ ਨੂੰ ਇੱਕ ਥਾਂ ਤੋਂ ਦੂਜੀ ਥਾਂ \'ਤੇ ਲਿਜਾਣ ਲਈ ਫੜ੍ਹ ਕੇ ਰੱਖੋ ਅਤੇ ਘਸੀਟੋ"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"ਸਾਰੇ ਕੰਟਰੋਲਾਂ ਦੀ ਸੂਚੀ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ਹੋਰ"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"ਤਤਕਾਲ ਕੰਟਰੋਲ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"ਡੀਵਾਈਸ ਕੰਟਰੋਲਾਂ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"ਮਨਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ਨੇ ਇਸ ਕੰਟਰੋਲ ਨੂੰ ਤੁਹਾਡੇ ਮਨਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਸੁਝਾਅ ਦਿੱਤਾ ਹੈ।"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"ਕੰਟਰੋਲ ਅੱਪਡੇਟ ਕੀਤੇ ਗਏ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index bf5a581d050e..3d243b22dca4 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -566,7 +566,7 @@ <string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string> <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"Otwórz ustawienia VPN"</string> <string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string> - <string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Otwórz zaufane dane logowania"</string> + <string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Otwórz zaufane certyfikaty"</string> <string name="monitoring_description_network_logging" msgid="577305979174002252">"Administrator włączył rejestrowanie sieciowe, które pozwala monitorować ruch na Twoim urządzeniu.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem."</string> <string name="monitoring_description_vpn" msgid="1685428000684586870">"Aplikacja otrzymała od Ciebie uprawnienia do konfigurowania połączenia VPN.\n\nMoże ona monitorować Twoją aktywność na urządzeniu i w sieci, w tym e-maile, aplikacje i strony internetowe."</string> <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem.\n\nŁączysz się też z siecią VPN, która może monitorować Twoją aktywność w sieci."</string> @@ -1015,9 +1015,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Okno nakładki powiększenia"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Okno powiększenia"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Elementy sterujące okna powiększenia"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Szybkie sterowanie"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Sterowanie urządzeniem"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodaj elementy sterujące do połączonych urządzeń"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Skonfiguruj szybkie sterowanie"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurowanie sterowania urządzeniem"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Przytrzymaj przycisk zasilania, aby uzyskać dostęp do elementów sterujących"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Wybierz aplikację, do której chcesz dodać elementy sterujące"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1028,10 +1028,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Elementy sterujące"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Wybierz elementy sterujące dostępne w menu zasilania"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Przytrzymaj i przeciągnij element sterujący, by go przenieść"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Nie udało się wczytać listy elementów sterujących."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Inne"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Dodaj do Szybkiego sterowania"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Dodaj do sterowania urządzeniem"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Dodaj do ulubionych"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikacja <xliff:g id="APP">%s</xliff:g> zaproponowała dodanie tego elementu sterującego do ulubionych."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Zaktualizowano elementy sterujące"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 6565cd0fdcb0..6e1266bf018e 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Permitir"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Depuração USB não permitida"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"O usuário conectado a este dispositivo não pode ativar a depuração USB. Para usar esse recurso, mude para o usuário principal \"NAME\"."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Permitir a depuração sem fio nesta rede?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Permitir a depuração por Wi-Fi nesta rede?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Nome da rede (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nEndereço do Wi-Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Sempre permitir nesta rede"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Permitir"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Depuração sem fio não permitida"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"O usuário conectado a este dispositivo não pode ativar a depuração sem fio. Para usar esse recurso, conecte-se como o usuário principal."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Depuração por Wi-Fi não permitida"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"O usuário conectado a este dispositivo não pode ativar a depuração por Wi-Fi. Para usar esse recurso, conecte-se como o usuário principal."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"Porta USB desativada"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Para proteger seu dispositivo de líquidos e detritos, a porta USB está desativada e não detectará nenhum acessório.\n\nVocê receberá uma notificação quando for seguro usar a porta USB novamente."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Porta USB ativada para detectar carregadores e acessórios"</string> @@ -500,7 +500,7 @@ <string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduz o desempenho e os dados em segundo plano"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desativar a Economia de bateria"</string> <string name="media_projection_dialog_text" msgid="1755705274910034772">"O app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo, como gravação ou transmissão Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e áudio que você toca."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo durante uma gravação ou transmissão. Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e áudio que você toca."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou reproduzidas durante uma gravação ou transmissão. Isso inclui senhas, detalhes de pagamento, fotos, mensagens e áudio."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Iniciar gravação ou transmissão?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Iniciar gravação ou transmissão com o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Não mostrar novamente"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Janela de sobreposição de ampliação"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Controles da janela de ampliação"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Controles rápidos"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles para os dispositivos conectados"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Configurar controles rápidos"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles do dispositivo"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Toque no botão liga/desliga e mantenha-o pressionado para acessar seus controles"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controles"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Escolha os controles para acessar pelo menu do botão liga/desliga"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Segure e arraste um controle para movê-lo"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Adic. aos controles rápidos"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Adicionar aos controles do dispositivo"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Adicionar aos favoritos"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> sugeriu a adição desse controle aos seus favoritos."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles atualizados"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index c73b90146f9c..1137a77e12c2 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -46,9 +46,9 @@ <string name="bluetooth_tethered" msgid="4171071193052799041">"Bluetooth ligado"</string> <string name="status_bar_input_method_settings_configure_input_methods" msgid="2972273031043777851">"Configurar métodos introdução"</string> <string name="status_bar_use_physical_keyboard" msgid="4849251850931213371">"Teclado físico"</string> - <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Pretende permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao dispositivo <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string> - <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Pretende permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> aceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta aplicação não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string> - <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"Pretende permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao acessório <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string> + <string name="usb_device_permission_prompt" msgid="4414719028369181772">"Permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao dispositivo <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string> + <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> aceda a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta aplicação não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string> + <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"Permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao acessório <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string> <string name="usb_device_confirm_prompt" msgid="4091711472439910809">"Pretende abrir a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> para controlar o acessório <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string> <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"Pretende abrir a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> para controlar o acessório <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta aplicação não recebeu autorização de gravação, mas pode capturar áudio através deste dispositivo USB."</string> <string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"Pretende abrir a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> para controlar o acessório <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string> @@ -63,7 +63,7 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Permitir"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Depuração USB não permitida"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"O utilizador com sessão iniciada atualmente neste dispositivo não pode ativar a depuração USB. Para utilizar esta funcionalidade, mude para o utilizador principal."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Pretende permitir a depuração sem fios nesta rede?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Permitir a depuração sem fios nesta rede?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Nome da rede (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nEndereço Wi-Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Permitir sempre nesta rede"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Permitir"</string> @@ -473,7 +473,7 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string> <string name="user_add_user" msgid="4336657383006913022">"Adicionar utilizador"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novo utilizador"</string> - <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Pretende remover o convidado?"</string> + <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover o convidado?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as aplicações e dados desta sessão serão eliminados."</string> <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo de volta, caro(a) convidado(a)!"</string> @@ -493,7 +493,7 @@ <item quantity="other">Pode adicionar até <xliff:g id="COUNT">%d</xliff:g> utilizadores.</item> <item quantity="one">Apenas é possível criar um utilizador.</item> </plurals> - <string name="user_remove_user_title" msgid="9124124694835811874">"Pretende remover o utilizador?"</string> + <string name="user_remove_user_title" msgid="9124124694835811874">"Remover o utilizador?"</string> <string name="user_remove_user_message" msgid="6702834122128031833">"Serão eliminados todos os dados e todas as aplicações deste utilizador."</string> <string name="user_remove_user_remove" msgid="8387386066949061256">"Remover"</string> <string name="battery_saver_notification_title" msgid="8419266546034372562">"Poupança de bateria ativada"</string> @@ -664,7 +664,7 @@ <string name="got_it" msgid="477119182261892069">"OK"</string> <string name="tuner_toast" msgid="3812684836514766951">"Parabéns! O Sintonizador da interface do sistema foi adicionado às Definições"</string> <string name="remove_from_settings" msgid="633775561782209994">"Remover das Definições"</string> - <string name="remove_from_settings_prompt" msgid="551565437265615426">"Pretende remover o Sintonizador da interface do sistema das Definições e deixar de utilizar todas as respetivas funcionalidades?"</string> + <string name="remove_from_settings_prompt" msgid="551565437265615426">"Remover o Sintonizador da interface do sistema das Definições e deixar de utilizar todas as respetivas funcionalidades?"</string> <string name="activity_not_found" msgid="8711661533828200293">"A aplicação não está instalada no dispositivo"</string> <string name="clock_seconds" msgid="8709189470828542071">"Mostrar segundos do relógio"</string> <string name="clock_seconds_desc" msgid="2415312788902144817">"Mostrar segundos do relógio na barra de estado. Pode afetar a autonomia da bateria."</string> @@ -708,7 +708,7 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"Ajuda-o a focar-se sem som ou vibração."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"Chama a sua atenção com som ou vibração."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Mantém a sua atenção com um atalho flutuante para este conteúdo."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Aparece na parte superior da secção da conversa e surge como um balão."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Aparece na parte superior da secção de conversas e surge como um balão."</string> <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Todas as conversas da app <xliff:g id="APP_NAME_0">%1$s</xliff:g> aparecem como um balão por predefinição. Faça a gestão na app <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Definições"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string> @@ -965,7 +965,7 @@ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Não terá acesso a dados ou à Internet através do operador <xliff:g id="CARRIER">%s</xliff:g>. A Internet estará disponível apenas por Wi-Fi."</string> <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"o seu operador"</string> <string name="touch_filtered_warning" msgid="8119511393338714836">"Uma vez que uma aplicação está a ocultar um pedido de autorização, as Definições não conseguem validar a sua resposta."</string> - <string name="slice_permission_title" msgid="3262615140094151017">"Pretende permitir que a aplicação <xliff:g id="APP_0">%1$s</xliff:g> mostre partes da aplicação <xliff:g id="APP_2">%2$s</xliff:g>?"</string> + <string name="slice_permission_title" msgid="3262615140094151017">"Permitir que a aplicação <xliff:g id="APP_0">%1$s</xliff:g> mostre partes da aplicação <xliff:g id="APP_2">%2$s</xliff:g>?"</string> <string name="slice_permission_text_1" msgid="6675965177075443714">"- Pode ler informações da aplicação <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="slice_permission_text_2" msgid="6758906940360746983">"- Pode realizar ações na aplicação <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="slice_permission_checkbox" msgid="4242888137592298523">"Permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> mostre partes de qualquer aplicação"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Janela de sobreposição da ampliação"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Controlos da janela de ampliação"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Controlos rápidos"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adicione controlos para os seus dispositivos associados."</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Configure controlos rápidos"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configure os controlos de dispositivos"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Prima sem soltar o botão ligar/desligar para aceder aos controlos."</string> <string name="controls_providers_title" msgid="6879775889857085056">"Escolha uma app para adicionar controlos"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controlos"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Escolha os controlos a que pretende aceder a partir do menu ligar/desligar."</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Toque sem soltar e arraste um controlo para o mover."</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista dos controlos."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Adicione aos controlos rápidos"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Adicione aos controlos de dispositivos"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Adicionar aos favoritos"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"A app <xliff:g id="APP">%s</xliff:g> sugeriu este controlo para adicionar aos seus favoritos."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controlos atualizados"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 6565cd0fdcb0..6e1266bf018e 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Permitir"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Depuração USB não permitida"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"O usuário conectado a este dispositivo não pode ativar a depuração USB. Para usar esse recurso, mude para o usuário principal \"NAME\"."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Permitir a depuração sem fio nesta rede?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Permitir a depuração por Wi-Fi nesta rede?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Nome da rede (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nEndereço do Wi-Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Sempre permitir nesta rede"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Permitir"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Depuração sem fio não permitida"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"O usuário conectado a este dispositivo não pode ativar a depuração sem fio. Para usar esse recurso, conecte-se como o usuário principal."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Depuração por Wi-Fi não permitida"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"O usuário conectado a este dispositivo não pode ativar a depuração por Wi-Fi. Para usar esse recurso, conecte-se como o usuário principal."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"Porta USB desativada"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Para proteger seu dispositivo de líquidos e detritos, a porta USB está desativada e não detectará nenhum acessório.\n\nVocê receberá uma notificação quando for seguro usar a porta USB novamente."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Porta USB ativada para detectar carregadores e acessórios"</string> @@ -500,7 +500,7 @@ <string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduz o desempenho e os dados em segundo plano"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desativar a Economia de bateria"</string> <string name="media_projection_dialog_text" msgid="1755705274910034772">"O app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo, como gravação ou transmissão Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e áudio que você toca."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo durante uma gravação ou transmissão. Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e áudio que você toca."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou reproduzidas durante uma gravação ou transmissão. Isso inclui senhas, detalhes de pagamento, fotos, mensagens e áudio."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Iniciar gravação ou transmissão?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Iniciar gravação ou transmissão com o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Não mostrar novamente"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Janela de sobreposição de ampliação"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Controles da janela de ampliação"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Controles rápidos"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adiciona controles para os dispositivos conectados"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Configurar controles rápidos"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurar controles do dispositivo"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Toque no botão liga/desliga e mantenha-o pressionado para acessar seus controles"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Controles"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Escolha os controles para acessar pelo menu do botão liga/desliga"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Segure e arraste um controle para movê-lo"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Adic. aos controles rápidos"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Adicionar aos controles do dispositivo"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Adicionar aos favoritos"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> sugeriu a adição desse controle aos seus favoritos."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Controles atualizados"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index a52f402f391b..f7b1f076531f 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Permiteți"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Remedierea erorilor prin USB nu este permisă"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Utilizatorul conectat momentan pe acest dispozitiv nu poate activa remedierea erorilor prin USB. Pentru a folosi această funcție, comutați la utilizatorul principal."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Permiteți remedierea erorilor prin wireless în această rețea?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Permiteți remedierea erorilor wireless în această rețea?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Numele rețelei (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Permiteți întotdeauna în această rețea"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Permiteți"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Remedierea erorilor prin wireless nu este permisă"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Utilizatorul conectat momentan pe acest dispozitiv nu poate activa remedierea erorilor prin wireless. Pentru a folosi această funcție, comutați la utilizatorul principal."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Remedierea erorilor wireless nu este permisă"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Utilizatorul conectat momentan pe acest dispozitiv nu poate activa remedierea erorilor wireless. Pentru a folosi această funcție, comutați la utilizatorul principal."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"Portul USB a fost dezactivat"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Pentru a vă proteja dispozitivul de lichide sau reziduuri, portul USB este dezactivat și nu va detecta niciun accesoriu.\n\nVeți primi o notificare când puteți folosi din nou portul USB."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Portul USB a fost activat pentru a detecta încărcătoarele și accesoriile"</string> @@ -1010,9 +1010,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Fereastra de suprapunere pentru mărire"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Fereastra de mărire"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Comenzi pentru fereastra de mărire"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Comenzi rapide"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Comenzile dispozitivului"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Adăugați comenzi pentru dispozitivele conectate"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Configurați comenzi rapide"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurați comenzile dispozitivului"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Apăsați butonul de pornire pentru a accesa comenzile"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Alegeți aplicația pentru a adăuga comenzi"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1022,10 +1022,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Comenzi"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Alegeți comenzile de accesat din meniul de alimentare"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Țineți apăsat și trageți o comandă pentru a o muta"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Lista cu toate comenzile nu a putut fi încărcată."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altul"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Adăugați la comenzi rapide"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Adăugați la comenzile dispozitivului"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Adăugați la preferate"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> a sugerat adăugarea acestei comenzi la preferate."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"S-au actualizat comenzile"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 27e9dc3c00a6..db37b0363766 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Не удалось сделать скриншот: нет разрешения от приложения или организации."</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Закрыть скриншот"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Открыть скриншот"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Запись видео с экрана"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Создание скриншотов"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущее уведомление для записи видео с экрана"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Начать запись?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Во время записи система Android может получить доступ к конфиденциальной информации, которая видна на экране или воспроизводится на устройстве, в том числе к паролям, сведениям о платежах, фотографиям, сообщениям и аудиозаписям."</string> @@ -515,7 +515,7 @@ <string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string> <string name="notification_section_header_gentle" msgid="3044910806569985386">"Беззвучные уведомления"</string> <string name="notification_section_header_alerting" msgid="3168140660646863240">"Оповещения"</string> - <string name="notification_section_header_conversations" msgid="821834744538345661">"Чаты"</string> + <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговоры"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Отклонить все беззвучные уведомления"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"В режиме \"Не беспокоить\" уведомления заблокированы"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Начать"</string> @@ -714,12 +714,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"Уведомления приходят без звука и вибрации"</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"Уведомления приходят со звуком или вибрацией"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Привлекает ваше внимание к контенту с помощью плавающего ярлыка"</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Появляется в верхней части раздела чатов в виде всплывающего уведомления."</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Все сообщения из сервиса \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" по умолчанию появляются в виде всплывающих уведомлений. Изменить настройки можно в приложении \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\"."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Появляется в верхней части списка разговоров и в виде всплывающего чата."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Все разговоры из сервиса \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" по умолчанию появляются в виде всплывающих чатов. Изменить настройки можно в приложении \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\"."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Настройки"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нет недавних подсказок"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Здесь будут появляться недавние и закрытые всплывающие уведомления."</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нет недавних всплывающих чатов"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Здесь будут появляться недавние и закрытые всплывающие чаты."</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Эти уведомления нельзя изменить."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Эту группу уведомлений нельзя настроить здесь."</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Уведомление отправлено через прокси-сервер."</string> @@ -747,7 +747,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"Уведомления отключены"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Включить звук уведомлений"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"Показывать всплывающее уведомление"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Не показывать всплывающие уведомления"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Не показывать всплывающие чаты"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Добавить на главный экран"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g>: <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"настройки уведомлений"</string> @@ -993,7 +993,7 @@ <string name="device_services" msgid="1549944177856658705">"Сервисы устройства"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Без названия"</string> <string name="restart_button_description" msgid="6916116576177456480">"Нажмите, чтобы перезапустить приложение и перейти в полноэкранный режим."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Настройки всплывающих уведомлений от приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Настройки всплывающих чатов от приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"Настроить"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> из приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> от приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" и ещё <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string> @@ -1003,11 +1003,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перенести в левый нижний угол"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перенести в правый нижний угол"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрыть"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не показывать всплывающие уведомления"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Всплывающие уведомления для сообщений"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новые сообщения будут появляться в виде плавающих значков или всплывающих уведомлений. Чтобы открыть сообщение, нажмите на уведомление. Чтобы переместить уведомление, перетащите его."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Настройки всплывающих уведомлений"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Чтобы отключить всплывающие уведомления от приложения, нажмите \"Настроить\"."</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не показывать всплывающие чаты для разговоров"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Всплывающие чаты для разговоров"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новые разговоры будут появляться в виде плавающих значков, или всплывающих чатов. Чтобы открыть чат, нажмите на него, а чтобы переместить – перетащите."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Настройки всплывающих чатов"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Чтобы отключить всплывающие чаты от приложения, нажмите \"Настроить\"."</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ОК"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Параметры навигации в системе обновлены. Чтобы изменить их, перейдите в настройки."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Чтобы обновить параметры навигации в системе, перейдите в настройки."</string> @@ -1015,9 +1015,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Наложение окна увеличения"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Окно увеличения"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Настройки окна увеличения"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Управление умным домом"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Элементы управления"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Добавьте элементы управления для подключенных устройств"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Настройка элементов управления умным домом"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Настройте элементы управления"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Чтобы перейти к элементам управления, удерживайте кнопку питания."</string> <string name="controls_providers_title" msgid="6879775889857085056">"Чтобы добавить элементы управления, выберите приложение"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1028,10 +1028,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Элементы управления"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Выберите элементы управления, которые будут доступны в меню кнопки питания."</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Чтобы перенести элемент, нажмите на него и удерживайте, а затем перетащите в нужное место."</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Не удалось загрузить список элементов управления."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Другое"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Добавить в быстрое управление"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Добавьте элементы управления"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Добавить в избранное"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"Приложение \"<xliff:g id="APP">%s</xliff:g>\" предлагает добавить этот элемент управления в избранное."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Элементы управления обновлены."</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 48461ba1566b..6baa7e1a62e4 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"විශාලන උඩැතිරි කවුළුව"</string> <string name="magnification_window_title" msgid="4863914360847258333">"විශාලන කවුළුව"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"විශාලනය කිරීමේ කවුළු පාලන"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"ඉක්මන් පාලන"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"උපාංග පාලන"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"ඔබේ සම්බන්ධිත උපාංග සඳහා පාලන එක් කරන්න"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"ඉක්මන් පාලන පිහිටුවන්න"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"උපාංග පාලන පිහිටුවන්න"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"ඔබේ පාලන වෙත ප්රවේශ වීමට බල බොත්තම අල්ලාගෙන සිටින්න"</string> <string name="controls_providers_title" msgid="6879775889857085056">"පාලන එක් කිරීමට යෙදුම තෝරා ගන්න"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"පාලන"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"බල මෙනුවෙන් ප්රවේශ වීමට පාලන තෝරා ගන්න"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"පාලනයක් එය ගෙන යාමට අල්ලා අදින්න"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"සියලු පාලනවල ලැයිස්තුව පූරණය කළ නොහැකි විය."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"වෙනත්"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"ඉක්මන් පාලන වෙත එක් කරන්න"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"උපාංග පාලන වෙත එක් කරන්න"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"ප්රියතම වෙත එක් කරන්න"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ඔබේ ප්රියතම වෙත එක් කිරීමට මෙම පාලනය යෝජනා කරන ලදී."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"පාලන යාවත්කාලීනයි"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index e742ec0f9a7e..e7c15d436235 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -1015,9 +1015,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Okno prekrytia priblíženia"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Okno priblíženia"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Ovládacie prvky okna priblíženia"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Rýchle ovládacie prvky"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Ovládacie prvky zariadenia"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Pridajte ovládacie prvky pre svoje pripojené zariadenia"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Nastavenie rýchlych ovládacích prvkov"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavenie ovládacích prvkov zariadenia"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Pridržaním vypínača získate prístup k ovládacím prvkom"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Výberom aplikácie pridajte ovládacie prvky"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1028,10 +1028,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Ovládacie prvky"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Vyberte si ovládacie prvky, ku ktorým chcete mať prístup v ponuke vypínača"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Ovládací prvok premiestnite pridržaním a presunutím"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Zoznam všetkých ovl. prvkov sa nepodarilo načítať."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iné"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Pridanie do rýchleho ovládania"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Pridanie do ovládacích prvkov zariadenia"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Pridať do obľúbených"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikácia <xliff:g id="APP">%s</xliff:g> vám odporučila pridať tento ovládací prvok do obľúbených."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Ovládanie bolo aktualizované"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 6620dff79daa..1ab62e753b8f 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -24,19 +24,19 @@ <string name="status_bar_no_notifications_title" msgid="7812479124981107507">"Ni obvestil"</string> <string name="status_bar_ongoing_events_title" msgid="3986169317496615446">"Trenutno"</string> <string name="status_bar_latest_events_title" msgid="202755896454005436">"Obvestila"</string> - <string name="battery_low_title" msgid="6891106956328275225">"Akumulator bo morda kmalu izpraznjen"</string> + <string name="battery_low_title" msgid="6891106956328275225">"Baterija bo morda kmalu izpraznjena"</string> <string name="battery_low_percent_format" msgid="4276661262843170964">"Še <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"Še <xliff:g id="PERCENTAGE">%1$s</xliff:g>, glede na način uporabe imate na voljo še približno <xliff:g id="TIME">%2$s</xliff:g>"</string> <string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"Še <xliff:g id="PERCENTAGE">%1$s</xliff:g>, na voljo imate še približno <xliff:g id="TIME">%2$s</xliff:g>"</string> - <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"Še <xliff:g id="PERCENTAGE">%s</xliff:g>. Vklopljeno je varčevanje z energijo akumulatorja."</string> + <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"Še <xliff:g id="PERCENTAGE">%s</xliff:g>. Vklopljeno je varčevanje z energijo baterije."</string> <string name="invalid_charger" msgid="4370074072117767416">"Ni mogoče polniti prek USB-ja. Uporabite polnilnik, ki je bil priložen napravi."</string> <string name="invalid_charger_title" msgid="938685362320735167">"Ni mogoče polniti prek USB-ja"</string> <string name="invalid_charger_text" msgid="2339310107232691577">"Uporabite polnilnik, ki je bil priložen napravi"</string> <string name="battery_low_why" msgid="2056750982959359863">"Nastavitve"</string> - <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Želite vklopiti varčevanje z energijo akumulatorja?"</string> - <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"O varčevanju z energijo akumulatorja"</string> + <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Želite vklopiti varčevanje z energijo baterije?"</string> + <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"O varčevanju z energijo baterije"</string> <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Vklopi"</string> - <string name="battery_saver_start_action" msgid="4553256017945469937">"Vklop varčevanja z energijo akumulatorja"</string> + <string name="battery_saver_start_action" msgid="4553256017945469937">"Vklop varčevanja z energijo baterije"</string> <string name="status_bar_settings_settings_button" msgid="534331565185171556">"Nastavitve"</string> <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string> <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Samodejno zasukaj zaslon"</string> @@ -237,9 +237,9 @@ <string name="accessibility_vpn_on" msgid="8037549696057288731">"Omrežje VPN je vklopljeno."</string> <string name="accessibility_no_sims" msgid="5711270400476534667">"Ni kartice SIM."</string> <string name="carrier_network_change_mode" msgid="5174141476991149918">"Spreminjanje omrežja operaterja"</string> - <string name="accessibility_battery_details" msgid="6184390274150865789">"Odpiranje podrobnosti o akumulatorju"</string> + <string name="accessibility_battery_details" msgid="6184390274150865789">"Odpiranje podrobnosti o bateriji"</string> <string name="accessibility_battery_level" msgid="5143715405241138822">"Baterija <xliff:g id="NUMBER">%d</xliff:g> odstotkov."</string> - <string name="accessibility_battery_level_with_estimate" msgid="4843119982547599452">"Napolnjenost akumulatorja je <xliff:g id="PERCENTAGE">%1$s</xliff:g>, glede na način uporabe imate na voljo še približno <xliff:g id="TIME">%2$s</xliff:g>"</string> + <string name="accessibility_battery_level_with_estimate" msgid="4843119982547599452">"Napolnjenost baterije je <xliff:g id="PERCENTAGE">%1$s</xliff:g>, glede na način uporabe imate na voljo še približno <xliff:g id="TIME">%2$s</xliff:g>"</string> <string name="accessibility_battery_level_charging" msgid="8892191177774027364">"Baterija se polni, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> odstotkov."</string> <string name="accessibility_settings_button" msgid="2197034218538913880">"Sistemske nastavitve."</string> <string name="accessibility_notifications_button" msgid="3960913924189228831">"Obvestila."</string> @@ -350,7 +350,7 @@ <string name="quick_settings_bluetooth_multiple_devices_label" msgid="6595808498429809855">"Bluetooth (št. naprav: <xliff:g id="NUMBER">%d</xliff:g>)"</string> <string name="quick_settings_bluetooth_off_label" msgid="6375098046500790870">"Bluetooth izklopljen"</string> <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Na voljo ni nobene seznanjene naprave"</string> - <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akumulator na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string> + <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string> <string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvok"</string> <string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalke z mikrofonom"</string> <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vhodna naprava"</string> @@ -394,7 +394,7 @@ <string name="quick_settings_more_settings" msgid="2878235926753776694">"Več nastavitev"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Končano"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Povezava je vzpostavljena"</string> - <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Povezava je vzpostavljena, raven napolnjenosti akumulatorja je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> + <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Povezava je vzpostavljena, raven napolnjenosti baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="quick_settings_connecting" msgid="2381969772953268809">"Vzpostavljanje povezave ..."</string> <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Internet prek mobilne naprave"</string> <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Dostopna točka"</string> @@ -413,7 +413,7 @@ <string name="quick_settings_cellular_detail_data_usage" msgid="6105969068871138427">"Poraba podatkov"</string> <string name="quick_settings_cellular_detail_remaining_data" msgid="1136599216568805644">"Preostala količina podatkov"</string> <string name="quick_settings_cellular_detail_over_limit" msgid="4561921367680636235">"Omejitev prekoračena"</string> - <string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"Porabljeno: <xliff:g id="DATA_USED">%s</xliff:g>"</string> + <string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"Preneseno: <xliff:g id="DATA_USED">%s</xliff:g>"</string> <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Omejitev: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string> <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Opozorilo – <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string> <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Delovni profil"</string> @@ -423,7 +423,7 @@ <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Vklop ob <xliff:g id="TIME">%s</xliff:g>"</string> <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"Do <xliff:g id="TIME">%s</xliff:g>"</string> <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Temna tema"</string> - <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Varč. z ener. bater."</string> + <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Varčevanje z baterijo"</string> <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Ob sončnem zahodu"</string> <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Do sončnega vzhoda"</string> <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Vklop ob <xliff:g id="TIME">%s</xliff:g>"</string> @@ -502,9 +502,9 @@ <string name="user_remove_user_title" msgid="9124124694835811874">"Želite odstraniti uporabnika?"</string> <string name="user_remove_user_message" msgid="6702834122128031833">"Vse aplikacije in podatki tega uporabnika bodo izbrisani."</string> <string name="user_remove_user_remove" msgid="8387386066949061256">"Odstrani"</string> - <string name="battery_saver_notification_title" msgid="8419266546034372562">"Varčevanje z energijo akumulatorja je vklopljeno"</string> + <string name="battery_saver_notification_title" msgid="8419266546034372562">"Varčevanje z energijo baterije je vklopljeno"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Omeji zmogljivost delovanja in prenos podatkov v ozadju"</string> - <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Izklop varčevanja z energijo akumulatorja"</string> + <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Izklop varčevanja z energijo baterije"</string> <string name="media_projection_dialog_text" msgid="1755705274910034772">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bo imela dostop do vseh podatkov, ki so med snemanjem ali predvajanjem prikazani na vašem zaslonu ali se predvajajo iz vaše naprave. To vključuje podatke, kot so gesla, podrobnosti o plačilu, fotografije, sporočila in zvok, ki ga predvajate."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Storitev, ki zagotavlja to funkcijo, bo imela dostop do vseh podatkov, ki so med snemanjem ali predvajanjem prikazani na vašem zaslonu ali se predvajajo iz vaše naprave. To vključuje podatke, kot so gesla, podrobnosti o plačilu, fotografije, sporočila in zvok, ki ga predvajate."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Želite začeti snemati ali predvajati?"</string> @@ -643,8 +643,8 @@ <string name="output_service_wifi" msgid="9003667810868222134">"Wi-Fi"</string> <string name="output_service_bt_wifi" msgid="7186882540475524124">"Bluetooth in Wi-Fi"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Uglaševalnik uporabniškega vmesnika sistema"</string> - <string name="show_battery_percentage" msgid="6235377891802910455">"Prikaži odstotek napolnjenosti vgraj. akumulatorja"</string> - <string name="show_battery_percentage_summary" msgid="9053024758304102915">"Prikaz odstotka napolnjenosti akumulatorja znotraj ikone v vrstici stanja, ko se ne polni"</string> + <string name="show_battery_percentage" msgid="6235377891802910455">"Prikaži odstotek napolnjenosti vgrajene baterije"</string> + <string name="show_battery_percentage_summary" msgid="9053024758304102915">"Prikaz odstotka napolnjenosti baterije znotraj ikone v vrstici stanja, ko se ne polni"</string> <string name="quick_settings" msgid="6211774484997470203">"Hitre nastavitve"</string> <string name="status_bar" msgid="4357390266055077437">"Vrstica stanja"</string> <string name="overview" msgid="3522318590458536816">"Pregled"</string> @@ -768,9 +768,9 @@ <item quantity="few">%d minute</item> <item quantity="other">%d minut</item> </plurals> - <string name="battery_panel_title" msgid="5931157246673665963">"Poraba akumulatorja"</string> - <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Varčevanje z energijo akumulatorja med polnjenjem ni na voljo"</string> - <string name="battery_detail_switch_title" msgid="6940976502957380405">"Varčevanje z energijo akumulatorja"</string> + <string name="battery_panel_title" msgid="5931157246673665963">"Poraba baterije"</string> + <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Varčevanje z energijo baterije med polnjenjem ni na voljo"</string> + <string name="battery_detail_switch_title" msgid="6940976502957380405">"Varčevanje z energijo baterije"</string> <string name="battery_detail_switch_summary" msgid="3668748557848025990">"Omeji zmogljivost delovanja in prenos podatkov v ozadju"</string> <string name="keyboard_key_button_template" msgid="8005673627272051429">"Gumb <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="keyboard_key_home" msgid="3734400625170020657">"Začetek"</string> @@ -818,7 +818,7 @@ <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne moti"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Bližnjica z gumboma za glasnost"</string> <string name="volume_up_silent" msgid="1035180298885717790">"Zapustitev načina »ne moti« pri povečanju glasnosti"</string> - <string name="battery" msgid="769686279459897127">"Akumulator"</string> + <string name="battery" msgid="769686279459897127">"Baterija"</string> <string name="clock" msgid="8978017607326790204">"Ura"</string> <string name="headset" msgid="4485892374984466437">"Slušalke z mikrofonom"</string> <string name="accessibility_long_click_tile" msgid="210472753156768705">"Odpri nastavitve"</string> @@ -946,7 +946,7 @@ <string name="tuner_menu" msgid="363690665924769420">"Meni"</string> <string name="tuner_app" msgid="6949280415826686972">"Aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="notification_channel_alerts" msgid="3385787053375150046">"Opozorila"</string> - <string name="notification_channel_battery" msgid="9219995638046695106">"Akumulator"</string> + <string name="notification_channel_battery" msgid="9219995638046695106">"Baterija"</string> <string name="notification_channel_screenshot" msgid="7665814998932211997">"Posnetki zaslona"</string> <string name="notification_channel_general" msgid="4384774889645929705">"Splošna sporočila"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Shramba"</string> @@ -970,7 +970,7 @@ <string name="qs_dnd_keep" msgid="3829697305432866434">"Obdrži"</string> <string name="qs_dnd_replace" msgid="7712119051407052689">"Zamenjaj"</string> <string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikacije, ki se izvajajo v ozadju"</string> - <string name="running_foreground_services_msg" msgid="3009459259222695385">"Dotaknite se za prikaz podrobnosti porabe akumulatorja in prenosa podatkov"</string> + <string name="running_foreground_services_msg" msgid="3009459259222695385">"Dotaknite se za prikaz podrobnosti porabe baterije in prenosa podatkov"</string> <string name="mobile_data_disable_title" msgid="5366476131671617790">"Želite izklopiti prenos podatkov v mobilnih omrežjih?"</string> <string name="mobile_data_disable_message" msgid="8604966027899770415">"Prek operaterja <xliff:g id="CARRIER">%s</xliff:g> ne boste imeli dostopa do podatkovne povezave ali interneta. Internet bo na voljo samo prek povezave Wi-Fi."</string> <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"svojega operaterja"</string> @@ -981,8 +981,8 @@ <string name="slice_permission_checkbox" msgid="4242888137592298523">"Dovoli, da aplikacija <xliff:g id="APP">%1$s</xliff:g> prikaže izreze iz poljubne aplikacije"</string> <string name="slice_permission_allow" msgid="6340449521277951123">"Dovoli"</string> <string name="slice_permission_deny" msgid="6870256451658176895">"Zavrni"</string> - <string name="auto_saver_title" msgid="6873691178754086596">"Dotaknite se za načrtovanje varčevanja z energijo akumulatorja"</string> - <string name="auto_saver_text" msgid="3214960308353838764">"Vklop, če je verjetno, da se bo akumulator izpraznil"</string> + <string name="auto_saver_title" msgid="6873691178754086596">"Dotaknite se za načrtovanje varčevanja z energijo baterije"</string> + <string name="auto_saver_text" msgid="3214960308353838764">"Vklop, če je verjetno, da se bo baterija izpraznila"</string> <string name="no_auto_saver_action" msgid="7467924389609773835">"Ne, hvala"</string> <string name="auto_saver_enabled_title" msgid="4294726198280286333">"Urnik varčevanja z energijo akumulatorja je vklopljen"</string> <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Varčevanje z energijo akumulatorja se bo samodejno vklopilo, ko bo energija akumulatorja pod <xliff:g id="PERCENTAGE">%d</xliff:g> %%."</string> @@ -1015,9 +1015,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Prekrivno povečevalno okno"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Povečevalno okno"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Kontrolniki povečevalnega okna"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Hitri kontrolniki"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kontrolniki naprave"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Dodajte kontrolnike za povezane naprave"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Nastavitev hitrih kontrolnikov"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Nastavitev kontrolnikov naprave"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Za dostop do kontrolnikov pridržite gumb za vklop"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Izberite aplikacijo za dodajanje kontrolnikov"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1028,10 +1028,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrolniki"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Izberite kontrolnike, do katerih želite imeti dostop prek menija za vklop/izklop"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Pridržite in povlecite kontrolnik, da ga premaknete"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Seznama vseh kontrolnikov ni bilo mogoče naložiti."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Dodaj med hitre kontrolnike"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Dodajanje med kontrolnike naprave"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Dodaj med priljubljene"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"Aplikacija <xliff:g id="APP">%s</xliff:g> je predlagala, da ta kontrolnik dodate med priljubljene."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrolniki so posodobljeni"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 074f63bbd27f..c95232c52d56 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Lejo"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Korrigjimi i USB-së nuk lejohet"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Përdoruesi i identifikuar aktualisht në këtë pajisje nuk mund ta aktivizojë korrigjimin e USB-së. Për ta përdorur këtë funksion, kalo te përdoruesi parësor."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Do ta lejosh korrigjimin me lidhjen pa tel në këtë rrjet?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Do ta lejosh korrigjimin përmes Wi-Fi në këtë rrjet?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Emri i rrjetit (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Shfaq gjithmonë në këtë rrjet"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Lejo"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Korrigjimi me lidhjen pa tel nuk lejohet"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Përdoruesi i identifikuar aktualisht në këtë pajisje nuk mund ta aktivizojë korrigjimin me lidhjen pa tel. Për ta përdorur këtë veçori, kalo te përdoruesi parësor."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Korrigjimi përmes Wi-Fi nuk lejohet"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Përdoruesi i identifikuar aktualisht në këtë pajisje nuk mund ta aktivizojë korrigjimin përmes Wi-Fi. Për ta përdorur këtë veçori, kalo te përdoruesi parësor."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"Porta e USB-së është çaktivizuar"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Për të mbrojtur pajisjen tënde nga lëngjet apo papastërtitë, porta e USB-së është çaktivizuar dhe nuk do t\'i dallojë aksesorët.\n\nDo të njoftohesh kur të mos jetë problem përdorimi përsëri i portës USB."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Porta USB është aktivizuar për të zbuluar karikuesit dhe aksesorët"</string> @@ -708,8 +708,8 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"Të ndihmon të fokusohesh pa tinguj ose dridhje."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"Të tërheq vëmendjen me tinguj ose dridhje."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Mban vëmendjen tënde me një shkurtore pluskuese te kjo përmbajtje."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Shfaq në krye të seksionit të bashkëbisedimit dhe shfaqe si flluskë."</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Të gjitha bashkëbisedimet nga flluska e <xliff:g id="APP_NAME_0">%1$s</xliff:g> si parazgjedhje. Menaxho në <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"Shfaqet në krye të seksionit të bisedës dhe shfaqet si flluskë."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Të gjitha bisedat nga flluska e <xliff:g id="APP_NAME_0">%1$s</xliff:g> si parazgjedhje. Menaxho në <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cilësimet"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Përparësia"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nuk ka flluska të fundit"</string> @@ -993,9 +993,9 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Zhvendos poshtë majtas"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Lëvize poshtë djathtas"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Hiq"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Mos e vendos bashkëbisedimin në flluskë"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Mos e vendos bisedën në flluskë"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bisedo duke përdorur flluskat"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"Bashkëbisedimet e reja shfaqen si ikona pluskuese ose flluska. Trokit për të hapur flluskën. Zvarrit për ta zhvendosur."</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"Bisedat e reja shfaqen si ikona pluskuese ose flluska. Trokit për të hapur flluskën. Zvarrit për ta zhvendosur."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrollo flluskat në çdo moment"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Trokit \"Menaxho\" për të çaktivizuar flluskat nga ky aplikacion"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"E kuptova"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Dritarja e mbivendosjes së zmadhimit"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Dritarja e zmadhimit"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Kontrollet e dritares së zmadhimit"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Kontrollet e shpejta"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Kontrollet e pajisjes"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Shto kontrolle për pajisjet e tua të lidhura"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Konfiguro kontrollet e shpejta"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfiguro kontrollet e pajisjes"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Mbaj shtypur butonin e energjisë për të pasur qasje te kontrollet e tua"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Zgjidh aplikacionin për të shtuar kontrollet"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrollet"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Zgjidh kontrollet për të pasur qasje nga menyja e energjisë"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Mbaj dhe zvarrit një kontroll për ta zhvendosur"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Lista e të gjitha kontrolleve nuk mund të ngarkohej."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Tjetër"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Shto te kontrollet e shpejta"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Shto te kontrollet e pajisjes"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Shto te të preferuarat"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> sugjeroi këtë kontroll për ta shtuar te të preferuarat e tua."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Kontrollet u përditësuan"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 38d2c75281bc..3e2482df5f63 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -1010,9 +1010,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Преклопни прозор за увећање"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Прозор за увећање"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Контроле прозора за увећање"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Брзе контроле"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Контроле уређаја"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Додајте контроле за повезане уређаје"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Подесите брзе контроле"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Подесите контроле уређаја"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Задржите дугме за укључивање да бисте приступили контролама"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Одаберите апликацију за додавање контрола"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1022,10 +1022,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Контроле"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Одаберите контроле којима ћете приступати из менија напајања"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Задржите и превуците контролу да бисте је преместили"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Учитавање листе свих контрола није успело."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Додајте у брзе контроле"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Додајте у контроле уређаја"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Додајте у омиљене"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> предлаже да додате ову контролу у омиљене."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Контроле су ажуриране"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 089910ce3cdf..509b97c4c8f3 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -712,7 +712,7 @@ <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Alla konversationer från <xliff:g id="APP_NAME_0">%1$s</xliff:g> visas i bubblor som standard. Hantera detta i <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Inställningar"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Inga senaste bubblor"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Inga nya bubblor"</string> <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"De senaste bubblorna och ignorerade bubblor visas här"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Det går inte att ändra de här aviseringarna."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Den här aviseringsgruppen kan inte konfigureras här"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Överlagrat förstoringsfönster"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Förstoringsfönster"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Inställningar för förstoringsfönster"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Snabbinställningar"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Enhetsinställningar"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Lägg till snabbkontroller för anslutna enheter"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Konfigurera snabbinställningar"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Konfigurera enhetsinställningar"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Håll strömbrytaren nedtryckt för att få åtkomst till snabbkontrollerna"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Välj en app om du vill lägga till snabbkontroller"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kontroller"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Välj snabbkontroller som ska visas i strömbrytarmenyn"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Dra en snabbkontroll om du vill flytta den"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Listan med alla kontroller kunde inte läsas in."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Övrigt"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Lägg till snabbkontroll"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Lägg till i enhetsinställningar"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Lägg till i Favoriter"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> föreslår att du lägger till kontrollen i dina favoriter."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Snabbkontroller uppdaterade"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 6beb752bc71e..a23e390c25ef 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -713,7 +713,7 @@ <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Mipangilio"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Kipaumbele"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Hakuna viputo vya hivi majuzi"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Viputo vya hivi karibuni na viputo vilivyoondolewa vitaonekana hapa"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Viputo vya hivi karibuni na vile vilivyoondolewa vitaonekana hapa"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Arifa hizi haziwezi kubadilishwa."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Kikundi hiki cha arifa hakiwezi kuwekewa mipangilio hapa"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Arifa wakilishi"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Dirisha la Kuwekelea Linalokuza"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Dirisha la Ukuzaji"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Vidhibiti vya Dirisha la Ukuzaji"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Vidhibiti vya haraka"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Vidhibiti vya kifaa"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Weka vidhibiti vya vifaa vyako vilivyounganishwa"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Weka mipangilio ya vidhibiti vya haraka"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Weka mipangilio ya vidhibiti vya kifaa"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Shikilia Kitufe cha kuwasha/kuzima ili ufikie vidhibiti vyako"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Chagua programu ili uweke vidhibiti"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Vidhibiti"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Chagua vidhibiti vya kufikia ukitumia menyu ya kuwasha/kuzima"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Shikilia na uburute kidhibiti ili ukisogeze"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Shikilia na uburute ili upange upya vidhibiti"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"Umeondoa vidhibiti vyote"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Imeshindwa kupakia orodha ya vidhibiti vyote."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Nyingine"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Weka kwenye vidhibiti vya haraka"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Weka kwenye vidhibiti vya kifaa"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Ongeza kwenye vipendwa"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> imependekeza kidhibiti hiki ili ukiongeze kwenye vipendwa vyako."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Umesasisha vidhibiti"</string> diff --git a/packages/SystemUI/res/values-sw320dp/dimens.xml b/packages/SystemUI/res/values-sw320dp/dimens.xml index 47a2a093302f..c110113e91f4 100644 --- a/packages/SystemUI/res/values-sw320dp/dimens.xml +++ b/packages/SystemUI/res/values-sw320dp/dimens.xml @@ -31,6 +31,6 @@ <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen> <!-- Home Controls --> - <dimen name="controls_list_side_margin">10dp</dimen> + <dimen name="global_actions_side_margin">10dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw360dp/dimens.xml b/packages/SystemUI/res/values-sw360dp/dimens.xml index 35a653608a90..fc510bf03efd 100644 --- a/packages/SystemUI/res/values-sw360dp/dimens.xml +++ b/packages/SystemUI/res/values-sw360dp/dimens.xml @@ -27,6 +27,6 @@ <dimen name="navigation_side_padding">40dip</dimen> <!-- Home Controls --> - <dimen name="controls_list_side_margin">12dp</dimen> + <dimen name="global_actions_side_margin">12dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw392dp/dimens.xml b/packages/SystemUI/res/values-sw392dp/dimens.xml index 308bc69656da..4c9d02e30bfa 100644 --- a/packages/SystemUI/res/values-sw392dp/dimens.xml +++ b/packages/SystemUI/res/values-sw392dp/dimens.xml @@ -31,6 +31,6 @@ <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen> <!-- Home Controls --> - <dimen name="controls_list_side_margin">16dp</dimen> + <dimen name="global_actions_side_margin">16dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 89341838f3e3..8f73d231c732 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -45,6 +45,11 @@ <!-- Height of the status bar header bar when on Keyguard --> <dimen name="status_bar_header_height_keyguard">60dp</dimen> + <!-- Size of user icon + frame in the qs user picker (incl. frame) --> + <dimen name="qs_framed_avatar_size">60dp</dimen> + <!-- Size of user icon + frame in the keyguard user picker (incl. frame) --> + <dimen name="kg_framed_avatar_size">48dp</dimen> + <!-- The width of user avatar when on Keyguard --> <dimen name="multi_user_switch_width_keyguard">48dp</dimen> @@ -88,4 +93,7 @@ <!-- Keyboard shortcuts helper --> <dimen name="ksh_layout_width">488dp</dimen> + + <!-- Text size for user name in user switcher --> + <dimen name="kg_user_switcher_text_size">18sp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml index b375364fdab9..02bd60210e81 100644 --- a/packages/SystemUI/res/values-sw600dp/styles.xml +++ b/packages/SystemUI/res/values-sw600dp/styles.xml @@ -30,20 +30,10 @@ <item name="android:textColor">?attr/wallpaperTextColor</item> </style> - <style name="TextAppearance.StatusBar.Expanded.UserSwitcher.Activated"> - <item name="android:fontWeight">700</item> - <item name="android:textStyle">bold</item> - <item name="android:textColor">?android:attr/textColorPrimaryInverse</item> - </style> - <style name="TextAppearance.QS.UserSwitcher"> - <item name="android:textSize">@dimen/qs_detail_item_primary_text_size</item> + <item name="android:textSize">@dimen/kg_user_switcher_text_size</item> <item name="android:textColor">?android:attr/textColorSecondary</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> </style> - <style name="TextAppearance.QS.UserSwitcher.Activated"> - <item name="android:fontWeight">700</item> - <item name="android:textStyle">bold</item> - </style> </resources> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 2d904e7e4ebe..420706605c7e 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"அனுமதி"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB பிழைதிருத்தம் அனுமதிக்கப்படவில்லை"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"தற்போது இந்தச் சாதனத்தில் உள்நுழைந்துள்ள பயனரால் USB பிழைதிருத்தத்தை இயக்க முடியாது. இந்த அம்சத்தை இயக்க, முதன்மைப் பயனருக்கு மாறவும்."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"இந்த நெட்வொர்க்கில் வயர்லெஸ் பிழைதிருத்தத்தை அனுமதிக்கவா?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"இந்த நெட்வொர்க்கில் வைஃபை பிழைதிருத்தத்தை அனுமதிக்கவா?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"நெட்வொர்க் பெயர் (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nவைஃபை முகவரி (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"இந்த நெட்வொர்க்கில் எப்போதும் அனுமதி"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"அனுமதி"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"வயர்லெஸ் பிழைதிருத்தம் அனுமதிக்கப்படவில்லை"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"தற்போது இந்தச் சாதனத்தில் உள்நுழைந்துள்ள பயனரால் வயர்லெஸ் பிழைதிருத்தத்தை இயக்க முடியாது. இந்த அம்சத்தை இயக்க முதன்மைப் பயனருக்கு மாறவும்."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"வைஃபை பிழைதிருத்தம் அனுமதிக்கப்படவில்லை"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"தற்போது இந்தச் சாதனத்தில் உள்நுழைந்துள்ள பயனரால் வைஃபை பிழைதிருத்தத்தை இயக்க முடியாது. இந்த அம்சத்தை இயக்க முதன்மைப் பயனருக்கு மாறவும்."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB போர்ட் முடக்கப்பட்டது"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"தேவையற்றவையில் இருந்து உங்கள் சாதனத்தைப் பாதுகாக்க USB போர்ட் முடக்கப்பட்டுள்ளது. மேலும் எந்தத் துணைக் கருவிகளையும் அது கண்டறியாது.\n\nUSB போர்ட்டை மீண்டும் எப்போது பயன்படுத்தலாம் என்பதைப் பற்றி உங்களுக்குத் தெரிவிக்கப்படும்."</string> <string name="usb_port_enabled" msgid="531823867664717018">"சார்ஜர்களையும் துணைக்கருவிகளையும் கண்டறிவதற்காக USB போர்ட் இயக்கப்பட்டுள்ளது"</string> @@ -154,36 +154,21 @@ <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"தவறான பேட்டர்ன்"</string> <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"தவறான கடவுச்சொல்"</string> <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"பல தவறான முயற்சிகள்.\n<xliff:g id="NUMBER">%d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string> - <!-- no translation found for biometric_dialog_credential_attempts_before_wipe (6751859711975516999) --> - <skip /> - <!-- no translation found for biometric_dialog_last_attempt_before_wipe_dialog_title (2874250099278693477) --> - <skip /> - <!-- no translation found for biometric_dialog_last_pattern_attempt_before_wipe_device (6562299244825817598) --> - <skip /> - <!-- no translation found for biometric_dialog_last_pin_attempt_before_wipe_device (9151756675698215723) --> - <skip /> - <!-- no translation found for biometric_dialog_last_password_attempt_before_wipe_device (2363778585575998317) --> - <skip /> - <!-- no translation found for biometric_dialog_last_pattern_attempt_before_wipe_user (8400180746043407270) --> - <skip /> - <!-- no translation found for biometric_dialog_last_pin_attempt_before_wipe_user (4159878829962411168) --> - <skip /> - <!-- no translation found for biometric_dialog_last_password_attempt_before_wipe_user (4695682515465063885) --> - <skip /> - <!-- no translation found for biometric_dialog_last_pattern_attempt_before_wipe_profile (6045224069529284686) --> - <skip /> - <!-- no translation found for biometric_dialog_last_pin_attempt_before_wipe_profile (545567685899091757) --> - <skip /> - <!-- no translation found for biometric_dialog_last_password_attempt_before_wipe_profile (8538032972389729253) --> - <skip /> - <!-- no translation found for biometric_dialog_failed_attempts_now_wiping_device (6585503524026243042) --> - <skip /> - <!-- no translation found for biometric_dialog_failed_attempts_now_wiping_user (7015008539146949115) --> - <skip /> - <!-- no translation found for biometric_dialog_failed_attempts_now_wiping_profile (5239378521440749682) --> - <skip /> - <!-- no translation found for biometric_dialog_now_wiping_dialog_dismiss (7189432882125106154) --> - <skip /> + <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"மீண்டும் முயலவும். <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>/<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> முறை முயன்றுவிட்டீர்கள்."</string> + <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"உங்கள் தரவு நீக்கப்படும்"</string> + <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"அடுத்த முறை தவறான பேட்டர்னை வரைந்தால் இந்தச் சாதனத்தின் தரவு நீக்கப்படும்."</string> + <string name="biometric_dialog_last_pin_attempt_before_wipe_device" msgid="9151756675698215723">"அடுத்த முறை தவறான பின்னை உள்ளிட்டால் இந்தச் சாதனத்தின் தரவு நீக்கப்படும்."</string> + <string name="biometric_dialog_last_password_attempt_before_wipe_device" msgid="2363778585575998317">"அடுத்த முறை தவறான கடவுச்சொல்லை உள்ளிட்டால் இந்தச் சாதனத்தின் தரவு நீக்கப்படும்."</string> + <string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"அடுத்த முறை தவறான பேட்டர்னை வரைந்தால் இந்தப் பயனர் நீக்கப்படுவார்."</string> + <string name="biometric_dialog_last_pin_attempt_before_wipe_user" msgid="4159878829962411168">"அடுத்த முறை தவறான பின்னை உள்ளிட்டால் இந்தப் பயனர் நீக்கப்படுவார்."</string> + <string name="biometric_dialog_last_password_attempt_before_wipe_user" msgid="4695682515465063885">"அடுத்த முறை தவறான கடவுச்சொல்லை உள்ளிட்டால் இந்தப் பயனர் நீக்கப்படுவார்."</string> + <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"அடுத்த முறை தவறான பேட்டர்னை வரைந்தால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string> + <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"அடுத்த முறை தவறான பின்னை உள்ளிட்டால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string> + <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"அடுத்த முறை தவறான கடவுச்சொல்லை உள்ளிட்டால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string> + <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"பலமுறை தவறாக முயன்ற காரணத்தால் இந்தச் சாதனத்தின் தரவு நீக்கப்படும்."</string> + <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"பலமுறை தவறாக முயன்ற காரணத்தால் இந்தப் பயனர் நீக்கப்படுவார்."</string> + <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"பலமுறை தவறாக முயன்ற காரணத்தால் இந்தப் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string> + <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"நிராகரி"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"கைரேகை சென்சாரைத் தொடவும்"</string> <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"கைரேகை ஐகான்"</string> <string name="face_dialog_looking_for_face" msgid="2656848512116189509">"உங்கள் முகத்தைத் தேடுகிறது…"</string> @@ -723,17 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"ஒலியோ அதிர்வோ இல்லாமல் முழு கவனம் செலுத்த உதவும்."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"ஒலியோ அதிர்வோ ஏற்படுத்தி உங்கள் கவனத்தை ஈர்க்கும்."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"இந்த உள்ளடக்கத்திற்கான மிதக்கும் ஷார்ட்கட் மூலம் உங்கள் கவனத்தைப் பெற்றிருக்கும்."</string> - <!-- no translation found for notification_channel_summary_priority (7415770044553264622) --> - <skip /> - <!-- no translation found for notification_conversation_channel_all_bubble (5389290797101635297) --> - <skip /> - <!-- no translation found for notification_conversation_channel_settings (2409977688430606835) --> - <skip /> - <!-- no translation found for notification_priority_title (2079708866333537093) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"உரையாடல் பிரிவின் மேற்பகுதியில் ஒரு குமிழாகக் காட்டப்படும்."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ஆப்ஸில் இருக்கும் அனைத்து உரையாடல்களும் இயல்பாகக் குமிழாகவே இருக்கும். <xliff:g id="APP_NAME_1">%2$s</xliff:g> ஆப்ஸில் நிர்வகிக்கலாம்."</string> + <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"அமைப்புகள்"</string> + <string name="notification_priority_title" msgid="2079708866333537093">"முன்னுரிமை"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"சமீபத்திய குமிழ்கள் இல்லை"</string> - <!-- no translation found for bubble_overflow_empty_subtitle (2030874469510497397) --> - <skip /> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"சமீபத்திய குமிழ்களும் நிராகரிக்கப்பட்ட குமிழ்களும் இங்கே தோன்றும்"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"இந்த அறிவுப்புக் குழுக்களை இங்கே உள்ளமைக்க இயலாது"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"ப்ராக்ஸியான அறிவிப்பு"</string> @@ -1013,77 +993,53 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"கீழே இடப்புறமாக நகர்த்து"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"கீழே வலதுபுறமாக நகர்த்து"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"மூடுக"</string> - <!-- no translation found for bubbles_dont_bubble_conversation (1033040343437428822) --> - <skip /> - <!-- no translation found for bubbles_user_education_title (5547017089271445797) --> - <skip /> - <!-- no translation found for bubbles_user_education_description (1160281719576715211) --> - <skip /> - <!-- no translation found for bubbles_user_education_manage_title (2848511858160342320) --> - <skip /> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"உரையாடலைக் குமிழாக்காதே"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"குமிழ்களைப் பயன்படுத்தி அரட்டையடியுங்கள்"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"புதிய உரையாடல்கள் மிதக்கும் ஐகான்களாகவோ குமிழ்களாகவோ தோன்றும். குமிழைத் திறக்க தட்டவும். நகர்த்த இழுக்கவும்."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"குமிழ்களை எப்போது வேண்டுமானாலும் கட்டுப்படுத்தலாம்"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"இந்த ஆப்ஸிலிருந்து வரும் குமிழ்களை முடக்க, நிர்வகி என்பதைத் தட்டவும்"</string> - <!-- no translation found for bubbles_user_education_got_it (8282812431953161143) --> - <skip /> + <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"சரி"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"சிஸ்டம் நேவிகேஷன் மாற்றப்பட்டது. மாற்றங்களைச் செய்ய ‘அமைப்புகளுக்குச்’ செல்லவும்."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"சிஸ்டம் நேவிகேஷனை மாற்ற ’அமைப்புகளுக்குச்’ செல்லவும்"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"இயக்க நேரம்"</string> <string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification Overlay Window"</string> <string name="magnification_window_title" msgid="4863914360847258333">"பெரிதாக்கல் சாளரம்"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"பெரிதாக்கல் சாளரக் கட்டுப்பாடுகள்"</string> - <!-- no translation found for quick_controls_title (1686913115679255053) --> - <skip /> - <!-- no translation found for quick_controls_subtitle (1667408093326318053) --> - <skip /> - <!-- no translation found for quick_controls_setup_title (9079435969373471268) --> - <skip /> - <!-- no translation found for quick_controls_setup_subtitle (1681506617879773824) --> - <skip /> - <!-- no translation found for controls_providers_title (6879775889857085056) --> - <skip /> + <string name="quick_controls_title" msgid="6839108006171302273">"சாதனக் கட்டுப்பாடுகள்"</string> + <string name="quick_controls_subtitle" msgid="1667408093326318053">"இணைக்கப்பட்ட சாதனங்களில் கட்டுப்பாடுகளைச் சேர்க்கலாம்"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"சாதனக் கட்டுப்பாடுகளை அமைத்தல்"</string> + <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"கட்டுப்பாடுகளை அணுக பவர் பட்டனை அழுத்திப் பிடித்திருக்கவும்"</string> + <string name="controls_providers_title" msgid="6879775889857085056">"கட்டுப்பாடுகளைச் சேர்க்க உதவும் ஆப்ஸைத் தேர்ந்தெடுங்கள்"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> கட்டுப்பாடுகள் சேர்க்கப்பட்டன.</item> <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> கட்டுப்பாடு சேர்க்கப்பட்டது.</item> </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"கட்டுப்பாடுகள்"</string> - <!-- no translation found for controls_favorite_subtitle (6604402232298443956) --> + <string name="controls_favorite_subtitle" msgid="6604402232298443956">"பவர் மெனுவில் இருந்து அணுகுவதற்கான கட்டுப்பாடுகளைத் தேர்ந்தெடுக்கலாம்"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> <skip /> - <!-- no translation found for controls_favorite_rearrange (7364147066539766260) --> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"எல்லா கட்டுப்பாடுகளின் பட்டியலை ஏற்ற முடியவில்லை."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"பிற"</string> - <!-- no translation found for controls_dialog_title (3475025327938684220) --> - <skip /> + <string name="controls_dialog_title" msgid="2343565267424406202">"சாதனக் கட்டுப்பாடுகளில் சேர்த்தல்"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"விருப்பமானவையில் சேர்"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"இந்தக் கட்டுப்பாட்டை உங்களுக்கு விருப்பமானவையில் சேர்க்கும்படி <xliff:g id="APP">%s</xliff:g> பரிந்துரைக்கிறார்."</string> - <!-- no translation found for controls_dialog_confirmation (586517302736263447) --> - <skip /> + <string name="controls_dialog_confirmation" msgid="586517302736263447">"கட்டுப்பாடுகள் மாற்றப்பட்டன"</string> <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"பின்னில் எழுத்துகள் அல்லது குறிகள் உள்ளன"</string> - <!-- no translation found for controls_pin_verify (3452778292918877662) --> - <skip /> - <!-- no translation found for controls_pin_verifying (3755045989392131746) --> - <skip /> + <string name="controls_pin_verify" msgid="3452778292918877662">"<xliff:g id="DEVICE">%s</xliff:g> ஐச் சரிபார்த்தல்"</string> + <string name="controls_pin_verifying" msgid="3755045989392131746">"சரிபார்க்கிறது…"</string> <string name="controls_pin_instructions" msgid="6363309783822475238">"பின்னை உள்ளிடுக"</string> - <!-- no translation found for controls_pin_instructions_retry (1566667581012131046) --> - <skip /> - <!-- no translation found for controls_confirmation_confirming (2596071302617310665) --> - <skip /> - <!-- no translation found for controls_confirmation_message (7744104992609594859) --> - <skip /> - <!-- no translation found for controls_structure_tooltip (4355922222944447867) --> - <skip /> + <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"வேறு பின்னைப் பயன்படுத்தவும்"</string> + <string name="controls_confirmation_confirming" msgid="2596071302617310665">"உறுதிப்படுத்துகிறது…"</string> + <string name="controls_confirmation_message" msgid="7744104992609594859">"<xliff:g id="DEVICE">%s</xliff:g> ஐ மாற்றுவதை உறுதிப்படுத்தவும்"</string> + <string name="controls_structure_tooltip" msgid="4355922222944447867">"மேலும் பார்க்க ஸ்வைப் செய்யவும்"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"பரிந்துரைகளை ஏற்றுகிறது"</string> - <!-- no translation found for controls_media_close_session (9023534788828414585) --> - <skip /> - <!-- no translation found for controls_error_timeout (794197289772728958) --> - <skip /> - <!-- no translation found for controls_error_failed (960228639198558525) --> - <skip /> - <!-- no translation found for controls_in_progress (4421080500238215939) --> - <skip /> - <!-- no translation found for controls_added_tooltip (4842812921719153085) --> - <skip /> - <!-- no translation found for controls_menu_add (4447246119229920050) --> - <skip /> - <!-- no translation found for controls_menu_edit (890623986951347062) --> - <skip /> + <string name="controls_media_close_session" msgid="9023534788828414585">"இந்த மீடியா அமர்வை மூடுக"</string> + <string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string> + <string name="controls_error_failed" msgid="960228639198558525">"பிழை, மீண்டும் முயலவும்"</string> + <string name="controls_in_progress" msgid="4421080500238215939">"செயல்பாட்டிலுள்ளது"</string> + <string name="controls_added_tooltip" msgid="4842812921719153085">"புதிய கட்டுப்பாடுகளைப் பார்க்க பவர் பட்டனைப் பிடித்திருக்கவும்"</string> + <string name="controls_menu_add" msgid="4447246119229920050">"கட்டுப்பாடுகளைச் சேர்த்தல்"</string> + <string name="controls_menu_edit" msgid="890623986951347062">"கட்டுப்பாடுகளை மாற்றுதல்"</string> </resources> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 92162aeea3a2..2fd229d553f6 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -712,8 +712,8 @@ <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> నుండి అన్ని సంభాషణలు డిఫాల్ట్గా బబుల్గా ఉంటాయి. <xliff:g id="APP_NAME_1">%2$s</xliff:g>లో మేనేజ్ చేయండి"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"సెట్టింగ్లు"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ఇటీవల బబుల్లు ఏవీ లేవు"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ఇటీవలి బబుల్లు, తీసివేసిన బబుల్లు ఇక్కడ కనిపిస్తాయి"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ఇటీవలి బబుల్స్ ఏవీ లేవు"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ఇటీవలి బబుల్స్, తీసివేసిన బబుల్స్ ఇక్కడ కనిపిస్తాయి"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ఈ నోటిఫికేషన్లను సవరించడం వీలుపడదు."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ఈ నోటిఫికేషన్ల సమూహాన్ని ఇక్కడ కాన్ఫిగర్ చేయలేము"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"ప్రాక్సీ చేయబడిన నోటిఫికేషన్"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"నిశ్శబ్దం చేయబడింది"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"అలర్ట్ చేయడం"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"బబుల్ను చూపించు"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"బబుల్ను తీసివేయి"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"బబుల్స్ తీసివేయి"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"హోమ్ స్క్రీన్కు జోడించు"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"నోటిఫికేషన్ నియంత్రణలు"</string> @@ -798,7 +798,7 @@ <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"అప్లికేషన్లు"</string> <string name="keyboard_shortcut_group_applications_assist" msgid="771606231466098742">"సహాయకం"</string> <string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"బ్రౌజర్"</string> - <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"పరిచయాలు"</string> + <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"కాంటాక్ట్లు"</string> <string name="keyboard_shortcut_group_applications_email" msgid="7852376788894975192">"ఇమెయిల్"</string> <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string> <string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"సంగీతం"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"పరికర సేవలు"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"శీర్షిక లేదు"</string> <string name="restart_button_description" msgid="6916116576177456480">"ఈ యాప్ను పునఃప్రారంభించేలా నొక్కి, ఆపై పూర్తి స్క్రీన్లోకి వెళ్లండి."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> బబుల్ల సెట్టింగ్లు"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> బబుల్స్ సెట్టింగ్లు"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"నిర్వహించండి"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> మరియు మరో <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string> @@ -994,10 +994,10 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"దిగవు కుడివైపునకు జరుపు"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"విస్మరించు"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"సంభాషణను బబుల్ చేయవద్దు"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"బబుల్లను ఉపయోగించి చాట్ చేయండి"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"కొత్త సంభాషణలు తేలియాడే చిహ్నాలుగా లేదా బబుల్లు లాగా కనిపిస్తాయి. బబుల్ని తెరవడానికి నొక్కండి. తరలించడానికి లాగండి."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"బబుల్లను ఎప్పుడైనా నియంత్రించండి"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ఈ యాప్ నుండి వచ్చే బబుల్లను ఆఫ్ చేయడానికి మేనేజ్ బటన్ను ట్యాప్ చేయండి"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"బబుల్స్ను ఉపయోగించి చాట్ చేయండి"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"కొత్త సంభాషణలు తేలియాడే చిహ్నాలుగా లేదా బబుల్స్ లాగా కనిపిస్తాయి. బబుల్ని తెరవడానికి నొక్కండి. తరలించడానికి లాగండి."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"బబుల్స్ను ఎప్పుడైనా నియంత్రించండి"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ఈ యాప్ నుండి వచ్చే బబుల్స్ను ఆఫ్ చేయడానికి మేనేజ్ బటన్ను ట్యాప్ చేయండి"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"అర్థమైంది"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"సిస్టమ్ నావిగేషన్ అప్డేట్ చేయబడింది. మార్పులు చేయడానికి, సెట్టింగ్లకు వెళ్లండి."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"సిస్టమ్ నావిగేషన్ను అప్డేట్ చేయడానికి సెట్టింగ్లకు వెళ్లండి"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"మాగ్నిఫికేషన్ ఓవర్లే విండో"</string> <string name="magnification_window_title" msgid="4863914360847258333">"మాగ్నిఫికేషన్ విండో"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"మాగ్నిఫికేషన్ నియంత్రణల విండో"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"త్వరిత నియంత్రణలు"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"పరికర నియంత్రణలు"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"మీ కనెక్ట్ అయిన పరికరాలకు నియంత్రణలను జోడించండి"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"త్వరిత నియంత్రణలను సెటప్ చేయండి"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"పరికర నియంత్రణలను సెటప్ చేయడం"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"మీ నియంత్రణలను యాక్సెస్ చేయడానికి పవర్ బటన్ను నొక్కి పట్టుకోండి"</string> <string name="controls_providers_title" msgid="6879775889857085056">"నియంత్రణలను యాడ్ చేయడానికి యాప్ను ఎంచుకోండి"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"నియంత్రణలు"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"పవర్ మెనూ నుండి యాక్సెస్ చేయడానికి నియంత్రణలను ఎంచుకోండి"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"తరలించడానికి నియంత్రణను పట్టుకొని, లాగండి"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"అన్ని నియంత్రణలు గల జాబితాను లోడ్ చేయలేకపోయాము."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ఇతరం"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"త్వరిత నియంత్రణలకు జోడించండి"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"పరికర నియంత్రణలకు జోడించడం"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"ఇష్టమైనవాటికి జోడించు"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"మీ ఇష్టమైనవాటికి జోడించడానికి <xliff:g id="APP">%s</xliff:g> ఈ కంట్రోల్ను సూచించింది."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"నియంత్రణలు అప్డేట్ అయ్యాయి"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 87bbec580555..1604d1555683 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"แอปหรือองค์กรของคุณไม่อนุญาตให้จับภาพหน้าจอ"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ปิดภาพหน้าจอ"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"เปิดภาพหน้าจอ"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"โปรแกรมบันทึกหน้าจอ"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"โปรแกรมอัดหน้าจอ"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"การแจ้งเตือนต่อเนื่องสำหรับเซสชันการบันทึกหน้าจอ"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"เริ่มบันทึกเลยไหม"</string> <string name="screenrecord_description" msgid="1123231719680353736">"ขณะบันทึก ระบบ Android จะบันทึกข้อมูลที่ละเอียดอ่อนที่ปรากฏบนหน้าจอหรือเล่นในอุปกรณ์ได้ ซึ่งรวมถึงรหัสผ่าน ข้อมูลการชำระเงิน รูปภาพ ข้อความ และเสียง"</string> @@ -961,7 +961,7 @@ <string name="qs_dnd_replace" msgid="7712119051407052689">"แทนที่"</string> <string name="running_foreground_services_title" msgid="5137313173431186685">"แอปที่กำลังทำงานในเบื้องหลัง"</string> <string name="running_foreground_services_msg" msgid="3009459259222695385">"แตะเพื่อดูรายละเอียดเกี่ยวกับแบตเตอรี่และปริมาณการใช้อินเทอร์เน็ต"</string> - <string name="mobile_data_disable_title" msgid="5366476131671617790">"ปิดเน็ตมือถือไหม"</string> + <string name="mobile_data_disable_title" msgid="5366476131671617790">"ปิดอินเทอร์เน็ตมือถือไหม"</string> <string name="mobile_data_disable_message" msgid="8604966027899770415">"คุณจะใช้เน็ตมือถือหรืออินเทอร์เน็ตผ่าน <xliff:g id="CARRIER">%s</xliff:g> ไม่ได้ แต่จะใช้ผ่าน Wi-Fi ได้เท่านั้น"</string> <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ผู้ให้บริการของคุณ"</string> <string name="touch_filtered_warning" msgid="8119511393338714836">"เนื่องจากแอปหนึ่งได้บดบังคำขอสิทธิ์ ระบบจึงไม่สามารถยืนยันคำตอบของคุณสำหรับการตั้งค่าได้"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"บริการของอุปกรณ์"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"ไม่มีชื่อ"</string> <string name="restart_button_description" msgid="6916116576177456480">"แตะเพื่อรีสตาร์ทแอปนี้และแสดงแบบเต็มหน้าจอ"</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"การตั้งค่าลูกโป่ง <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"การตั้งค่าบับเบิล <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"จัดการ"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g> และอีก <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> รายการ"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"หน้าต่างการขยายที่วางซ้อน"</string> <string name="magnification_window_title" msgid="4863914360847258333">"หน้าต่างการขยาย"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"การควบคุมหน้าต่างการขยาย"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"การควบคุมด่วน"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"การควบคุมอุปกรณ์"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"เพิ่มตัวควบคุมของอุปกรณ์ที่เชื่อมต่อ"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"ตั้งค่าการควบคุมด่วน"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"ตั้งค่าการควบคุมอุปกรณ์"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"กดปุ่มเปิด/ปิดค้างไว้เพื่อเข้าถึงการควบคุม"</string> <string name="controls_providers_title" msgid="6879775889857085056">"เลือกแอปเพื่อเพิ่มตัวควบคุม"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"การควบคุม"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"เลือกตัวควบคุมที่ต้องการให้เข้าถึงได้จากเมนูเปิด/ปิด"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"กดตัวควบคุมค้างไว้แล้วลากเพื่อย้ายที่"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"โหลดรายการตัวควบคุมทั้งหมดไม่ได้"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"อื่นๆ"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"เพิ่มไปยังตัวควบคุมด่วน"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"เพิ่มไปยังการควบคุมอุปกรณ์"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"เพิ่มในรายการโปรด"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> แนะนำให้เพิ่มการควบคุมนี้ในรายการโปรด"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"อัปเดตตัวควบคุมแล้ว"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 83e1d68d27f2..d5c20996e9ad 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Hindi pinahihintulutan ng app o ng iyong organisasyon ang pagkuha ng mga screenshot"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"I-dismiss ang screenshot"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Buksan ang screenshot"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Recorder ng Screen"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Kasalukuyang notification para sa session ng pag-record ng screen"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Simulang Mag-record?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Habang nagre-record, puwedeng ma-capture ng Android System ang anumang sensitibong impormasyong nakikita sa iyong screen o nagpe-play sa device mo. Kasama dito ang mga password, impormasyon sa pagbabayad, mga larawan, mensahe, at audio."</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Window ng Overlay sa Pag-magnify"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Window ng Pag-magnify"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Mga Kontrol sa Pag-magnify ng Window"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Mga mabilisang kontrol"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Mga kontrol ng device"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Magdagdag ng mga kontrol para sa iyong mga nakakonektang device"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Mag-set up ng mga mabilisang kontrol"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"I-set up ang mga kontrol ng device"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Pindutin nang matagal ang Power button para ma-access ang iyong mga kontrol"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Pumili ng app para magdagdag ng mga kontrol"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Mga Kontrol"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Pumili ng mga kontrol na maa-access mula sa power menu"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Pindutin nang matagal at i-drag ang isang kontrol para ilipat ito"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Hindi ma-load ang listahan ng lahat ng control."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iba pa"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Idagdag sa mabilisang kontrol"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Idagdag sa mga kontrol ng device"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Idagdag sa mga paborito"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"Iminungkahi ng <xliff:g id="APP">%s</xliff:g> ang kontrol na ito na idagdag sa iyong mga paborito."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Na-update na ang mga kontrol"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 2f46f8b19d61..5f5968ec635c 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -68,7 +68,7 @@ <string name="wifi_debugging_always" msgid="2968383799517975155">"Bu ağda her zaman izin ver"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"İzin ver"</string> <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Kablosuz hata ayıklamaya izin verilmiyor"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Bu cihazda geçerli olarak oturum açmış olan kullanıcı, kablosuz hata ayıklama özelliğini açamaz. Bu özelliği kullanmak için birincil kullanıcıya geçin."</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Bu cihazda şu anda oturum açmış olan kullanıcı, kablosuz hata ayıklama özelliğini açamaz. Bu özelliği kullanmak için birincil kullanıcıya geçin."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB bağlantı noktası devre dışı bırakıldı"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Cihazınızı sıvılardan veya tozlardan korumak için USB bağlantı noktası devre dışı bırakıldı ve aksesuarları algılamayacak.\n\nUSB bağlantı noktasını tekrar sorunsuz kullanabileceğiniz zaman bilgilendirileceksiniz."</string> <string name="usb_port_enabled" msgid="531823867664717018">"USB bağlantı noktası, şarj cihazlarını ve aksesuarları algılamak üzere etkinleştirildi"</string> @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Uygulama veya kuruluşunuz, ekran görüntüsü alınmasına izin vermiyor."</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ekran görüntüsünü kapat"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Ekran görüntüsünü aç"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Ekran Kaydedici"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Ekran Kaydedicisi"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekran kaydı oturumu için devam eden bildirim"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Kayıt Başlatılsın mı?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Kayıt sırasında Android Sistemi, ekranınızda görünen veya cihazınızda oynatılan hassas bilgileri yakalayabilir. Buna şifreler, ödeme bilgileri, fotoğraflar, mesajlar ve sesler dahildir."</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"Sesi kapatıldı"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Uyarı"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"Balon olarak göster"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Balonları kaldır"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Baloncukları kaldır"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Ana ekrana ekle"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"Bildirim kontrolleri"</string> @@ -997,7 +997,7 @@ <string name="bubbles_user_education_title" msgid="5547017089271445797">"Baloncukları kullanarak sohbet edin"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yeni görüşmeler kayan simgeler veya baloncuk olarak görünür. Açmak için baloncuğa dokunun. Baloncuğu taşımak için sürükleyin."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Baloncukları istediğiniz zaman kontrol edin"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu uygulamanın balonlarını kapatmak için Yönet\'e dokunun"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu uygulamanın baloncuklarını kapatmak için Yönet\'e dokunun"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Anladım"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemde gezinme yöntemi güncellendi. Değişiklik yapmak için Ayarlar\'a gidin."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemde gezinme yöntemini güncellemek için Ayarlar\'a gidin"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Yer Paylaşımlı Büyütme Penceresi"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Büyütme Penceresi"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Büyütme Penceresi Kontrolleri"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Hızlı denetimler"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Cihaz kontrolleri"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Bağlı cihazlarınız için denetimler ekleyin"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Hızlı denetimleri kurun"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Cihaz kontrollerini kur"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Denetimlerinize erişmek için Güç düğmesini basılı tutun"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Denetim eklemek için uygulama seçin"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Kontroller"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Güç menüsünden erişmek için denetimleri seçin"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Bir denetimi taşımak için basılı tutup sürükleyin"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Kontrolleri yeniden düzenlemek için basılı tutup sürükleyin"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"Tüm kontroller kaldırıldı"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Tüm kontrollerin listesi yüklenemedi."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Diğer"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Hızlı denetimlere ekle"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Cihaz kontrollerine ekle"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Favorilere ekle"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g>, bu kontrolü favorilerinize eklemenizi önerdi."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Denetimler güncellendi"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 1a3cf65a51d9..15658f330327 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Дозволити"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Ви не можете вмикати налагодження USB"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Користувач поточного облікового запису не може вмикати налагодження USB. Щоб увімкнути цю функцію, увійдіть в обліковий запис основного користувача."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Дозволити бездротове налагодження в цій мережі?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Дозволити налагодження через Wi-Fi у цій мережі?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Ім\'я мережі (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nАдреса Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Завжди дозволяти в цій мережі"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Дозволити"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Бездротове налагодження заборонено"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Користувач поточного облікового запису не може вмикати бездротове налагодження. Щоб активувати цю функцію, увійдіть в обліковий запис основного користувача."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Налагодження через Wi-Fi заборонене"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Користувач поточного облікового запису не може вмикати налагодження через Wi-Fi. Щоб активувати цю функцію, увійдіть в обліковий запис основного користувача."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB-порт вимкнено"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Щоб захистити ваш пристрій від рідини та сміття, USB-порт вимкнено. Він не виявлятиме жодних аксесуарів.\n\nКоли USB-порт можна буде використовувати, ви отримаєте сповіщення."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Порт USB виявлятиме зарядні пристрої та аксесуари"</string> @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Додаток або адміністратор вашої організації не дозволяють робити знімки екрана"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Закрити знімок екрана"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Відкрити знімок екрана"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Засіб запису екрана"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Створення знімків екрана"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Сповіщення про сеанс запису екрана"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Почати запис?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Під час запису система Android може фіксувати будь-яку конфіденційну інформацію, яка з\'являється на екрані або відтворюється на пристрої, зокрема паролі, платіжну інформацію, фотографії, повідомлення та звуки."</string> @@ -515,7 +515,7 @@ <string name="manage_notifications_history_text" msgid="57055985396576230">"Історія"</string> <string name="notification_section_header_gentle" msgid="3044910806569985386">"Беззвучні сповіщення"</string> <string name="notification_section_header_alerting" msgid="3168140660646863240">"Сповіщення зі звуком чи вібрацією"</string> - <string name="notification_section_header_conversations" msgid="821834744538345661">"Чати"</string> + <string name="notification_section_header_conversations" msgid="821834744538345661">"Розмови"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Очистити всі беззвучні сповіщення"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Режим \"Не турбувати\" призупинив сповіщення"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Почати зараз"</string> @@ -714,12 +714,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"Не відволікає увагу звуковим сигналом або вібрацією."</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"Привертає увагу звуковим сигналом або вібрацією."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Привертає увагу до контенту плаваючим ярликом."</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"З\'являється вгорі розділу з чатами у вигляді спливаючого сповіщення."</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Усі чати з додатка <xliff:g id="APP_NAME_0">%1$s</xliff:g> за умовчанням з\'являються у вигляді спливаючих сповіщень. Керувати в додатку <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"З\'являється вгорі розділу з розмовами у вигляді спливаючого чату."</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Усі чати з додатка <xliff:g id="APP_NAME_0">%1$s</xliff:g> за умовчанням з\'являються у вигляді спливаючих сповіщень. Налаштувати їх можна в додатку <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налаштування"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Пріоритет"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Немає нещодавніх спливаючих сповіщень"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Тут з\'являтимуться нещодавні й закриті спливаючі сповіщення"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Немає нещодавніх спливаючих чатів"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Тут з\'являтимуться нещодавні й закриті спливаючі чати"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ці сповіщення не можна змінити."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Цю групу сповіщень не можна налаштувати тут"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Проксі-сповіщення"</string> @@ -747,7 +747,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"Сповіщення вимкнено"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"Увімкнути сповіщення"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"Показувати як спливаюче сповіщення"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Вимкнути спливаючі сповіщення"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"Вимкнути спливаючі чати"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"Додати на головний екран"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"елементи керування сповіщеннями"</string> @@ -993,8 +993,8 @@ <string name="device_services" msgid="1549944177856658705">"Сервіси на пристрої"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Без назви"</string> <string name="restart_button_description" msgid="6916116576177456480">"Натисніть, щоб перезапустити додаток і перейти в повноекранний режим."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Налаштування спливаючих підказок від додатка <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> - <string name="manage_bubbles_text" msgid="6856830436329494850">"Керувати"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Налаштування спливаючих чатів від додатка <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="manage_bubbles_text" msgid="6856830436329494850">"Налаштувати"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"Cповіщення \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" від додатка <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"Сповіщення \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" від додатка <xliff:g id="APP_NAME">%2$s</xliff:g> (і ще <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>)"</string> <string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Перемістити"</string> @@ -1003,11 +1003,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перемістити ліворуч униз"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перемістити праворуч униз"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрити"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Заборонити спливаючі сповіщення в чатах"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Чат у вигляді спливаючих сповіщень"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"Нові повідомлення чату з\'являються у вигляді плаваючих значків або спливаючих сповіщень. Натисніть, щоб відкрити спливаюче сповіщення. Перетягніть його, щоб перемістити."</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Керуйте спливаючими сповіщеннями будь-коли"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Натисніть \"Керувати\", щоб вимкнути спливаючі сповіщення для цього додатка"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не показувати спливаючі чати для розмов"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Чат зі спливаючими сповіщеннями"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"Нові повідомлення чату з\'являються у вигляді спливаючих значків. Щоб відкрити чат, натисніть його, а щоб перемістити – перетягніть."</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Налаштовуйте спливаючі чати будь-коли"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Натисніть \"Налаштувати\", щоб вимкнути спливаючі чати від цього додатка"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Зрозуміло"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацію в системі оновлено. Щоб внести зміни, перейдіть у налаштування."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перейдіть у налаштування, щоб оновити навігацію в системі"</string> @@ -1015,9 +1015,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Вікно збільшення з накладанням"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Вікно збільшення"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Елементи керування вікна збільшення"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Елементи швидкого керування"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Елементи керування пристроєм"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Додайте елементи керування для підключених пристроїв"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Налаштування елементів швидкого керування"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Налаштувати елементи керування пристроєм"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Щоб відкрити елементи керування, утримуйте кнопку живлення"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Виберіть, для якого додатка налаштувати елементи керування"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1028,10 +1028,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Елементи керування"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Виберіть, які елементи керування будуть у меню \"Живлення\""</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Щоб перемістити елемент керування, перетягніть його"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Не вдалося завантажити список усіх елементів керування."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Інше"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Додати в елем. швидк. керув."</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Додати до елементів керування пристроєм"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Додати у вибране"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> пропонує додати цей елемент керування у вибране."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Елементи керування оновлено"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 3cf00dd4390a..08a400f9ee89 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"میگنیفیکیشن اوورلے ونڈو"</string> <string name="magnification_window_title" msgid="4863914360847258333">"میگنیفکیشن ونڈو"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"میگنیفکیشن ونڈو کنٹرولز"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"فوری کنٹرولز"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"آلہ کے کنٹرولز"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"اپنے منسلک آلات کے لیے کنٹرولز شامل کریں"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"فوری کنٹرولز سیٹ اپ کریں"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"آلہ کے کنٹرولز سیٹ اپ کریں"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"اپنے کنٹرول تک رسائی حاصل کرنے کے ليے پاور بٹن کو دبائیں رکھیں"</string> <string name="controls_providers_title" msgid="6879775889857085056">"کنٹرولز شامل کرنے کے لیے ایپ منتخب کریں"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"کنٹرولز"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"پاور مینو سے رسائی حاصل کرنے کے لیے کنٹرولز کو منتخب کریں"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"اسے منتقل کرنے کے لیے کنٹرول کو پکڑیں اور گھسیٹیں"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"تمام کنٹرولز کی فہرست لوڈ نہیں کی جا سکی۔"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"دیگر"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"فوری کنٹرولز میں شامل کریں"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"آلہ کے کنٹرولز میں شامل کریں"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"پسندیدگیوں میں شامل کریں"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> نے آپ کی پسندیدگیوں میں شامل کرنے کے ليے یہ کنٹرول تجویز کیا۔"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"کنٹرولز اپ ڈیٹ کیے گئے"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index b88c874bfd82..de2656072cf9 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -63,12 +63,12 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Ruxsat berish"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB orqali nosozliklarni tuzatishga ruxsat berilmagan"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Ayni paytda ushbu qurilmaga o‘z hisobi bilan kirgan foydalanuvchi USB orqali nosozliklarni aniqlash funksiyasini yoqa olmaydi. Bu funksiyadan foydalanish uchun asosiy foydalanuvchi profiliga o‘ting."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Bu tarmoqdagi nosozliklar aniqlanishiga ruxsat berilsinmi?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Bu tarmoqda Wi-Fi orqali debagging uchun ruxsat berilsinmi?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Tarmoq nomi (SSID):\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Manzil (BSSID):\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Bu tarmoqda doim ruxsat etilsin"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Ruxsat"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Simsiz tarmoqdagi nosozliklar aniqlanishiga ruxsat berilmagan"</string> - <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Ayni paytda ushbu qurilmaga oʻz hisobi bilan kirgan foydalanuvchi simsiz tarmoqdagi nosozliklarni aniqlanish funksiyasini yoqa olmaydi. Bu funksiyadan foydalanish uchun asosiy foydalanuvchi profiliga oʻting."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Wi-Fi orqali debagging taqiqlandi"</string> + <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Ayni paytda ushbu qurilmaga oʻz hisobi bilan kirgan foydalanuvchi Wi-Fi orqali debagging funksiyasini yoqa olmaydi. Bu funksiyadan foydalanish uchun asosiy foydalanuvchi profiliga oʻting."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB port faolsizlashtirildi"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Qurilmangizni suyuqlik va turli parchalardan himoya qilish uchun USB port faolsizlashtiriladi va hech qanday aksessuarni aniqlay olmaydi.\n\nUSB portdan xavfsiz foydalanish mumkin boʻlganda, sizga xabar beriladi."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Quvvatlash moslamalari va aksessuarlarni aniqlash uchun USB port yoqildi"</string> @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ilova yoki tashkilotingiz skrinshot olishni taqiqlagan"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Skrinshotni yopish"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"Skrinshotni ochish"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"Ekranni yozib olish vositasi"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"Ekrandan yozib olish"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekrandan yozib olish seansi uchun joriy bildirishnoma"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Yozib olish boshlansinmi?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"Yozib olishda Android tizimi ekraningizda koʻringan yoki qurilmangizda ijro etilgan maxfiy axborotni ham yozib olishi mumkin. Bunga parollar, toʻlovga oid axborot, suratlar, xabarlar va audio kiradi."</string> @@ -712,7 +712,7 @@ <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"Barcha <xliff:g id="APP_NAME_0">%1$s</xliff:g> xabarlari bulutcha shaklida chiqadi. Sozlamalarni <xliff:g id="APP_NAME_1">%2$s</xliff:g> orqali oʻzgartirish mumkin."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Sozlamalar"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Muhimligi"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Avvalgi pufakchalar topilmadi"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Avvalgi bulutchalar topilmadi"</string> <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Bu yerda oxirgi va yopilgan bulutcha shaklidagi bildirishnomalar chiqadi"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ushbu bildirishnomalar guruhi bu yerda sozlanmaydi"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"Qurilma xizmatlari"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"Nomsiz"</string> <string name="restart_button_description" msgid="6916116576177456480">"Bu ilovani qaytadan ishga tushirish va butun ekranga ochish uchun bosing."</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> pufakchalari uchun sozlamalar"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> bulutchalari uchun sozlamalar"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"Boshqarish"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> ilovasidan <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> va yana <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ta bildirishnoma"</string> @@ -994,7 +994,7 @@ <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Quyi oʻngga surish"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"Yopish"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Suhbatlar bulutchalar shaklida chiqmasin"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bulutcha shaklidagi bildirishnomalar yordamida subhatlashish"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bulutchalar yordamida subhatlashish"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yangi xabarlar qalqib chiquvchi belgilar yoki bulutchalar kabi chiqadi. Xabarni ochish uchun bildirishnoma ustiga bosing. Xabarni qayta joylash uchun bildirishnomani suring."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Bulutcha shaklidagi bildirishnomalarni sozlash"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu ilova bulutchalarini faolsizlantirish uchun Boshqarish tugmasini bosing"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Kattalashtirish oynasining ustidan ochilishi"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Kattalashtirish oynasi"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Kattalashtirish oynasi sozlamalari"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Tezkor sozlamalar"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Qurilma boshqaruv elementlari"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Ulangan qurilmalarga boshqaruv elementlarini kiriting"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Tezkor sozlamalarni sozlash"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Qurilma boshqaruv elementlarini sozlash"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Boshqaruv elementlariga kirish uchun oʻchirib-yoqish tugmasini bosib turing"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Boshqaruv elementlarini kiritish uchun ilovani tanlang"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,11 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Boshqaruv elementlari"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Quvvat tugmasi menyusida chiqadigan boshqaruv elementlarini tanlang"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Elementni surish uchun uni bosib turib, kerakli joyga suring"</string> + <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Boshqaruv elementlarini qayta tartiblash uchun ushlab torting"</string> + <string name="controls_favorite_removed" msgid="5276978408529217272">"Barcha boshqaruv elementlari olib tashlandi"</string> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Boshqaruv elementlarining barchasi yuklanmadi."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Boshqa"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Tezkor sozlamalarga kiriting"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Qurilma boshqaruv elementlariga kiritish"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Saralanganlarga kiritish"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> ilovasi bu sozlamani saralanganlarga kiritishni taklif qildi."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Boshqaruv elementlari yangilandi"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 957bbd676367..b12ea2ff6df2 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -151,7 +151,7 @@ <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Dùng hình mở khóa"</string> <string name="biometric_dialog_use_password" msgid="3445033859393474779">"Dùng mật khẩu"</string> <string name="biometric_dialog_wrong_pin" msgid="1878539073972762803">"Mã PIN sai"</string> - <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Hình mở khóa sai"</string> + <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Hình mở khóa không chính xác"</string> <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Mật khẩu sai"</string> <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Bạn đã nhập sai quá nhiều lần.\nHãy thử lại sau <xliff:g id="NUMBER">%d</xliff:g> giây."</string> <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Thử lại. Lần thử <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>/<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string> @@ -232,7 +232,7 @@ <string name="cell_data_off_content_description" msgid="9165555931499878044">"Đã tắt dữ liệu di động"</string> <string name="not_default_data_content_description" msgid="6757881730711522517">"Chưa được đặt để sử dụng dữ liệu"</string> <string name="cell_data_off" msgid="4886198950247099526">"Tắt"</string> - <string name="accessibility_bluetooth_tether" msgid="6327291292208790599">"Chia sẻ kết nối Internet qua Bluetooth"</string> + <string name="accessibility_bluetooth_tether" msgid="6327291292208790599">"Chia sẻ Internet qua Bluetooth"</string> <string name="accessibility_airplane_mode" msgid="1899529214045998505">"Chế độ trên máy bay."</string> <string name="accessibility_vpn_on" msgid="8037549696057288731">"VPN đang bật."</string> <string name="accessibility_no_sims" msgid="5711270400476534667">"Không có thẻ SIM nào."</string> @@ -394,7 +394,7 @@ <string name="quick_settings_connected" msgid="3873605509184830379">"Đã kết nối"</string> <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Đã kết nối, mức pin <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="quick_settings_connecting" msgid="2381969772953268809">"Đang kết nối..."</string> - <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Đang dùng làm điểm truy cập Internet"</string> + <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Chia sẻ Internet"</string> <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Điểm phát sóng"</string> <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Đang bật…"</string> <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Trình tiết kiệm dữ liệu đang bật"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Cửa sổ lớp phủ phóng to"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Cửa sổ phóng to"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Các tùy chọn điều khiển cửa sổ phóng to"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Tùy chọn điều khiển nhanh"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Điều khiển thiết bị"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Thêm các tùy chọn điều khiển cho các thiết bị đã kết nối của bạn"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Thiết lập các tùy chọn điều khiển nhanh"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Thiết lập các tùy chọn điều khiển thiết bị"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Giữ nút Nguồn để truy cập vào các tùy chọn điều khiển"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Chọn ứng dụng để thêm các tùy chọn điều khiển"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Các tùy chọn điều khiển"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Chọn các tùy chọn điều khiển để truy cập từ trình đơn nguồn"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Giữ và kéo một tùy chọn điều khiển để di chuyển tùy chọn đó"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Không thể tải danh sách tất cả tùy chọn điều khiển."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Khác"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Thêm vào mục điều khiển nhanh"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Thêm vào mục điều khiển thiết bị"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Thêm vào mục yêu thích"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> đã đề xuất thêm tùy chọn điều khiển này vào mục yêu thích của bạn."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Đã cập nhật các tùy chọn điều khiển"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 791fe8dd74b2..b3c513d9c90e 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -582,7 +582,7 @@ <string name="accessibility_volume_settings" msgid="1458961116951564784">"声音设置"</string> <string name="accessibility_volume_expand" msgid="7653070939304433603">"展开"</string> <string name="accessibility_volume_collapse" msgid="2746845391013829996">"收起"</string> - <string name="volume_odi_captions_tip" msgid="8825655463280990941">"自动字幕媒体"</string> + <string name="volume_odi_captions_tip" msgid="8825655463280990941">"自动生成媒体字幕"</string> <string name="accessibility_volume_close_odi_captions_tip" msgid="8924753283621160480">"关闭字幕提示"</string> <string name="volume_odi_captions_content_description" msgid="4172765742046013630">"字幕重叠显示"</string> <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"启用"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"放大叠加窗口"</string> <string name="magnification_window_title" msgid="4863914360847258333">"放大窗口"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"放大窗口控件"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"快捷控件"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"设备控件"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"为您所连接的设备添加控件"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"设置快捷控件"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"设置设备控件"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"按住电源按钮即可访问您的控件"</string> <string name="controls_providers_title" msgid="6879775889857085056">"选择应用以添加控件"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"控件"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"选择要从电源菜单访问的控件"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"按住并拖动即可移动控件"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"无法加载所有控件的列表。"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"添加到快捷控件"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"添加到设备控件"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"添加到收藏夹"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g>建议将此控件添加到您的收藏夹。"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"控件已更新"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index d6a8546b2386..69a8da6dfe9a 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"放大重疊視窗"</string> <string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"放大視窗控制項"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"快速控制項"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"裝置控制項"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"為已連接的裝置新增控制項"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"設定快速控制項"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制項"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"按住「開關」按鈕便可存取控制項"</string> <string name="controls_providers_title" msgid="6879775889857085056">"選擇應用程式以新增控制項"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"控制項"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"從電源選單選擇要存取的控制項"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"按住並拖曳控制項即可移動"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"無法載入完整控制項清單。"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"加入至快速控制介面"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"加到裝置控制項"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"加入至常用項目"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"「<xliff:g id="APP">%s</xliff:g>」建議將此控制項加入至常用項目。"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"已更新控制項"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index c1f668d2bc91..4ea11d786fba 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -88,7 +88,7 @@ <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"這個應用程式或貴機構不允許擷取螢幕畫面"</string> <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"關閉螢幕截圖"</string> <string name="screenshot_preview_description" msgid="669177537416980449">"開啟螢幕截圖"</string> - <string name="screenrecord_name" msgid="2596401223859996572">"螢幕畫面錄製工具"</string> + <string name="screenrecord_name" msgid="2596401223859996572">"螢幕錄影器"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示螢幕畫面錄製工作階段通知"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"要開始錄製嗎?"</string> <string name="screenrecord_description" msgid="1123231719680353736">"錄製螢幕畫面時,Android 系統可擷取螢幕上顯示或裝置播放的任何機密資訊,包括密碼、付款資訊、相片、訊息和音訊。"</string> @@ -708,12 +708,12 @@ <string name="notification_channel_summary_low" msgid="7300447764759926720">"協助你不受音效或震動干擾。"</string> <string name="notification_channel_summary_default" msgid="3539949463907902037">"發出音效或震動吸引你的注意力。"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"利用浮動式捷徑快速存取這項內容。"</string> - <string name="notification_channel_summary_priority" msgid="7415770044553264622">"以泡泡形式顯示在對話部分的頂端。"</string> - <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」的所有對話預設會以泡泡形式顯示。你可以在「<xliff:g id="APP_NAME_1">%2$s</xliff:g>」中調整相關設定。"</string> + <string name="notification_channel_summary_priority" msgid="7415770044553264622">"以對話框形式顯示在對話部分的頂端。"</string> + <string name="notification_conversation_channel_all_bubble" msgid="5389290797101635297">"「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」的所有對話預設會以對話框形式顯示。你可以在「<xliff:g id="APP_NAME_1">%2$s</xliff:g>」中調整相關設定。"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string> <string name="notification_priority_title" msgid="2079708866333537093">"優先"</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近沒有任何泡泡"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近的泡泡和已關閉的泡泡會顯示在這裡"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近沒有任何對話框"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近的對話框和已關閉的對話框會顯示在這裡"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"無法在這裡設定這個通知群組"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"經過 Proxy 處理的通知"</string> @@ -741,7 +741,7 @@ <string name="notification_conversation_mute" msgid="268951550222925548">"已設為靜音"</string> <string name="notification_conversation_unmute" msgid="2692255619510896710">"解除略過"</string> <string name="notification_conversation_bubble" msgid="2242180995373949022">"以泡泡形式顯示"</string> - <string name="notification_conversation_unbubble" msgid="6908427185031099868">"移除泡泡"</string> + <string name="notification_conversation_unbubble" msgid="6908427185031099868">"移除對話框"</string> <string name="notification_conversation_home_screen" msgid="8347136037958438935">"新增至主螢幕"</string> <string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string> <string name="notification_menu_gear_description" msgid="6429668976593634862">"通知控制項"</string> @@ -983,7 +983,7 @@ <string name="device_services" msgid="1549944177856658705">"裝置服務"</string> <string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string> <string name="restart_button_description" msgid="6916116576177456480">"輕觸即可重新啟動這個應用程式並進入全螢幕模式。"</string> - <string name="bubbles_settings_button_description" msgid="7324245408859877545">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」泡泡的設定"</string> + <string name="bubbles_settings_button_description" msgid="7324245408859877545">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」對話框的設定"</string> <string name="manage_bubbles_text" msgid="6856830436329494850">"管理"</string> <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="7907610717462651870">"「<xliff:g id="APP_NAME">%2$s</xliff:g>」和其他 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 個應用程式:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> @@ -993,11 +993,11 @@ <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移至左下方"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移至右下方"</string> <string name="bubble_dismiss_text" msgid="7071770411580452911">"關閉"</string> - <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不要以泡泡形式顯示對話"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"使用泡泡進行即時通訊"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"新的對話會以浮動圖示或泡泡形式顯示。輕觸即可開啟泡泡,拖曳則可移動泡泡。"</string> - <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"你隨時可以控管泡泡的各項設定"</string> - <string name="bubbles_user_education_manage" msgid="1391639189507036423">"輕觸 [管理] 即可關閉來自這個應用程式的泡泡"</string> + <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不要以對話框形式顯示對話"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"使用對話框進行即時通訊"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"新的對話會以浮動圖示或對話框形式顯示。輕觸即可開啟對話框,拖曳則可移動對話框。"</string> + <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"你隨時可以控管對話框的各項設定"</string> + <string name="bubbles_user_education_manage" msgid="1391639189507036423">"輕觸 [管理] 即可關閉來自這個應用程式的對話框"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"我知道了"</string> <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系統操作機制已更新。如要進行變更,請前往「設定」。"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"請前往「設定」更新系統操作機制"</string> @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"放大重疊視窗"</string> <string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"放大視窗控制項"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"快速控制項"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"裝置控制項"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"新增已連結裝置的控制項"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"設定快速控制項"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"設定裝置控制項"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"按住電源按鈕即可存取控制項"</string> <string name="controls_providers_title" msgid="6879775889857085056">"選擇應用程式以新增控制項"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"控制項"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"選擇要從電源選單存取的控制項"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"按住並拖曳即可移動控制項"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"無法載入完整的控制項清單。"</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"新增至快速控制項"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"新增至裝置控制項"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"新增至常用控制項"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"「<xliff:g id="APP">%s</xliff:g>」建議你將這個控制項新增至常用控制項。"</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"已更新控制項"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index b5fd68deaa94..6d455df22a44 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -1005,9 +1005,9 @@ <string name="magnification_overlay_title" msgid="6584179429612427958">"Iwindi Lembondela Lesikhulisi"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Iwindi Lesikhulisi"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Izilawuli Zewindi Lesikhulisi"</string> - <string name="quick_controls_title" msgid="1686913115679255053">"Izilawuli ezisheshayo"</string> + <string name="quick_controls_title" msgid="6839108006171302273">"Izilawuli zedivayisi"</string> <string name="quick_controls_subtitle" msgid="1667408093326318053">"Engeza izilawuli zedivayisi yakho exhunyiwe"</string> - <string name="quick_controls_setup_title" msgid="9079435969373471268">"Setha izilawuli ezisheshayo"</string> + <string name="quick_controls_setup_title" msgid="8901436655997849822">"Setha izilawuli zedivayisi"</string> <string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Bamba inkinobho yamandla ukufinyelela kwizilawuli"</string> <string name="controls_providers_title" msgid="6879775889857085056">"Khetha uhlelo lokusebenza ukwengeza izilawuli"</string> <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380"> @@ -1016,10 +1016,13 @@ </plurals> <string name="controls_favorite_default_title" msgid="967742178688938137">"Izilawuli"</string> <string name="controls_favorite_subtitle" msgid="6604402232298443956">"Khetha izilawuli ukuze ufinyelele kusuka kumenyu yamandla"</string> - <string name="controls_favorite_rearrange" msgid="7364147066539766260">"Bamba futhi uhudule isilawuli ukuze usihambise"</string> + <!-- no translation found for controls_favorite_rearrange (5616952398043063519) --> + <skip /> + <!-- no translation found for controls_favorite_removed (5276978408529217272) --> + <skip /> <string name="controls_favorite_load_error" msgid="2533215155804455348">"Uhlu lwazo zonke izilawuli alilayishekanga."</string> <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Okunye"</string> - <string name="controls_dialog_title" msgid="3475025327938684220">"Engeza kuzilawuli ezisheshayo"</string> + <string name="controls_dialog_title" msgid="2343565267424406202">"Engeza kuzilawuli zedivayisi"</string> <string name="controls_dialog_ok" msgid="7011816381344485651">"Engeza kuzintandokazi"</string> <string name="controls_dialog_message" msgid="6292099631702047540">"I-<xliff:g id="APP">%s</xliff:g> iphakamise lokhu kulawula ukwengeza kuzintandokazi zakho."</string> <string name="controls_dialog_confirmation" msgid="586517302736263447">"Izilawuli zibuyekeziwe"</string> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 74bbee681ccc..4482cdac3327 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -50,6 +50,10 @@ <!-- The color of the text in the Global Actions menu --> <color name="global_actions_alert_text">@color/GM2_red_700</color> + <!-- The color of the background of the emergency button when home controls are visible --> + <color name="global_actions_emergency_background">@color/GM2_red_400</color> + <color name="global_actions_emergency_text">@color/GM2_grey_100</color> + <!-- Tint color for the content on the notification overflow card. --> <color name="keyguard_overflow_content_color">#ff686868</color> @@ -58,6 +62,19 @@ <!-- Shadows under the clock, date and other keyguard text fields --> <color name="keyguard_shadow_color">#B2000000</color> + <!-- Color for rounded background for activated user in keyguard user switcher --> + <color name="kg_user_switcher_activated_background_color">#26000000</color> + <!-- Icon color for user avatars in keyguard user switcher --> + <color name="kg_user_switcher_avatar_icon_color">@android:color/background_light</color> + <!-- Icon color for selected user avatars in keyguard user switcher --> + <color name="kg_user_switcher_selected_avatar_icon_color">@android:color/background_light</color> + <!-- Icon color for user avatars in user switcher quick settings --> + <color name="qs_user_switcher_avatar_icon_color">#3C4043</color> + <!-- Icon color for selected user avatars in user switcher quick settings --> + <color name="qs_user_switcher_selected_avatar_icon_color">@android:color/background_light</color> + <!-- Color of background circle of user avatars in quick settings --> + <color name="qs_user_switcher_avatar_background">#DADCE0</color> + <!-- The color of the legacy notification background --> <color name="notification_legacy_background_color">#ff1a1a1a</color> @@ -198,6 +215,7 @@ <color name="GM2_red_50">#FCE8E6</color> <color name="GM2_red_200">#F6AEA9</color> <color name="GM2_red_300">#F28B82</color> + <color name="GM2_red_400">#EE675C</color> <color name="GM2_red_500">#B71C1C</color> <color name="GM2_red_700">#C5221F</color> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index f549a3253319..62335abd4329 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -536,6 +536,10 @@ <!-- Max number of columns for quick controls area --> <integer name="controls_max_columns">2</integer> + + <!-- Max number of columns for power menu --> + <integer name="power_menu_max_columns">3</integer> + <!-- If the dp width of the available space is <= this value, potentially adjust the number of columns--> <integer name="controls_max_columns_adjust_below_width_dp">320</integer> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 5b213edd5f0f..e7ef8ccf4eba 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -16,6 +16,9 @@ */ --> <resources> + <!-- Recommended minimum clickable element dimension --> + <dimen name="min_clickable_item_size">48dp</dimen> + <!-- Amount to offset bottom of notification peek window from top of status bar. --> <dimen name="peek_window_y_offset">-12dp</dimen> @@ -752,8 +755,10 @@ quick settings header --> <dimen name="max_avatar_size">48dp</dimen> - <!-- Size of user icon + frame in the qs/keyguard user picker (incl. frame) --> - <dimen name="framed_avatar_size">54dp</dimen> + <!-- Size of user icon + frame in the qs user picker (incl. frame) --> + <dimen name="qs_framed_avatar_size">54dp</dimen> + <!-- Size of user icon + frame in the keyguard user picker (incl. frame) --> + <dimen name="kg_framed_avatar_size">54dp</dimen> <!-- Margin on the left side of the carrier text on Keyguard --> <dimen name="keyguard_carrier_text_margin">16dp</dimen> @@ -953,7 +958,7 @@ <dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen> <!-- The height of the gradient indicating the dismiss edge when moving a PIP. --> - <dimen name="pip_dismiss_gradient_height">176dp</dimen> + <dimen name="floating_dismiss_gradient_height">176dp</dimen> <!-- The bottom margin of the PIP drag to dismiss info text shown when moving a PIP. --> <dimen name="pip_dismiss_text_bottom_margin">24dp</dimen> @@ -1006,6 +1011,9 @@ <dimen name="global_actions_grid_container_shadow_offset">20dp</dimen> <dimen name="global_actions_grid_container_negative_shadow_offset">-20dp</dimen> + <!-- Margins at the left and right of the power menu and home controls widgets. --> + <dimen name="global_actions_side_margin">16dp</dimen> + <!-- The maximum offset in either direction that elements are moved horizontally to prevent burn-in on AOD. --> <dimen name="burn_in_prevention_offset_x">8dp</dimen> @@ -1209,6 +1217,7 @@ <!-- Size of media cards in the QSPanel carousel --> <dimen name="qs_media_width">350dp</dimen> <dimen name="qs_media_padding">8dp</dimen> + <dimen name="qs_media_panel_outer_padding">16dp</dimen> <dimen name="qs_media_corner_radius">10dp</dimen> <dimen name="qs_media_album_size">72dp</dimen> <dimen name="qs_seamless_icon_size">20dp</dimen> @@ -1229,7 +1238,6 @@ <dimen name="controls_header_side_margin">4dp</dimen> <dimen name="controls_header_menu_size">48dp</dimen> <dimen name="controls_header_app_icon_size">40dp</dimen> - <dimen name="controls_list_side_margin">16dp</dimen> <dimen name="controls_top_margin">44dp</dimen> <dimen name="control_header_text_size">22sp</dimen> <dimen name="control_text_size">14sp</dimen> @@ -1245,6 +1253,12 @@ <dimen name="control_base_item_margin">2dp</dimen> <dimen name="control_status_padding">3dp</dimen> + <!-- Home Controls activity view detail panel--> + <dimen name="controls_activity_view_top_padding">25dp</dimen> + <dimen name="controls_activity_view_side_padding">12dp</dimen> + <dimen name="controls_activity_view_top_offset">200dp</dimen> + <dimen name="controls_activity_view_text_size">17sp</dimen> + <!-- Home Controls management screens --> <dimen name="controls_management_top_padding">48dp</dimen> <dimen name="controls_management_side_padding">8dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 566d143208fc..d2654d6d7d9a 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -235,8 +235,8 @@ your organization</string> <!-- Content description indicating that tapping a button will dismiss the screenshots UI [CHAR LIMIT=NONE] --> <string name="screenshot_dismiss_ui_description">Dismiss screenshot</string> - <!-- Content description indicating that tapping will open an app to view/edit the screenshot. [CHAR LIMIT=NONE] --> - <string name="screenshot_preview_description">Open screenshot</string> + <!-- Content description indicating that the view is a preview of the screenshot that was just taken [CHAR LIMIT=NONE] --> + <string name="screenshot_preview_description">Screenshot preview</string> <!-- Notification title displayed for screen recording [CHAR LIMIT=50]--> <string name="screenrecord_name">Screen Recorder</string> @@ -2670,8 +2670,11 @@ <string name="controls_favorite_default_title">Controls</string> <!-- Controls management controls screen subtitle [CHAR LIMIT=NONE] --> <string name="controls_favorite_subtitle">Choose controls to access from the power menu</string> - <!-- Controls management controls screen, user direction for rearranging controls [CHAR LIMIT=NONE] --> - <string name="controls_favorite_rearrange">Hold and drag a control to move it</string> + <!-- Controls management editing screen, user direction for rearranging controls [CHAR LIMIT=NONE] --> + <string name="controls_favorite_rearrange">Hold & drag to rearrange controls</string> + + <!-- Controls management editing screen, text to indicate that all the favorites have been removed [CHAR LIMIT=NONE] --> + <string name="controls_favorite_removed">All controls removed</string> <!-- Controls management controls screen error on load message [CHAR LIMIT=60] --> <string name="controls_favorite_load_error">The list of all controls could not be loaded.</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index aabee1c952e8..118aa5b3f96a 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -511,7 +511,7 @@ </style> <style name="TextAppearance.NotificationInfo"> - <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:textColor">@color/notification_primary_text_color</item> </style> @@ -521,7 +521,6 @@ </style> <style name="TextAppearance.NotificationInfo.Title"> - <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> <item name="android:textColor">@color/notification_primary_text_color</item> <item name="android:textStyle">bold</item> </style> @@ -672,6 +671,19 @@ <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> </style> + <style name="Theme.SystemUI.Dialog.Control.DetailPanel" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar"> + <item name="android:windowAnimationStyle">@style/Animation.Bottomsheet</item> + <item name="android:windowFullscreen">true</item> + <item name="android:windowIsFloating">false</item> + <item name="android:windowBackground">@null</item> + <item name="android:backgroundDimEnabled">true</item> + </style> + + <style name="Animation.Bottomsheet"> + <item name="android:windowEnterAnimation">@anim/bottomsheet_in</item> + <item name="android:windowExitAnimation">@anim/bottomsheet_out</item> + </style> + <style name="Control" /> <style name="Control.MenuItem"> @@ -714,6 +726,11 @@ <item name="android:textSize">@dimen/control_text_size</item> <item name="android:textColor">@color/control_secondary_text</item> </style> + <style name="TextAppearance.ControlDialog"> + <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item> + <item name="android:textSize">@dimen/controls_activity_view_text_size</item> + <item name="android:textColor">@color/control_primary_text</item> + </style> <style name="Control.ListPopupWindow" parent="@*android:style/Widget.DeviceDefault.ListPopupWindow"> <item name="android:overlapAnchor">true</item> diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index fe6e44b5de0a..592f6c2a0dff 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -36,7 +36,6 @@ android_library { static_libs: [ "PluginCoreLib", - "SystemUI-statsd", ], // Enforce that the library is built against java 7 so that there are diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index 3bda3c8df699..806678f23bb3 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -261,6 +261,11 @@ public class ActivityManagerWrapper { animationHandler.onAnimationCanceled( taskSnapshot != null ? new ThumbnailData(taskSnapshot) : null); } + + @Override + public void onTaskAppeared(RemoteAnimationTarget app) { + animationHandler.onTaskAppeared(new RemoteAnimationTargetCompat(app)); + } }; } ActivityTaskManager.getService().startRecentsActivity(intent, receiver, runner); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java index 34a0268201f4..4794847d8be1 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java @@ -18,7 +18,6 @@ package com.android.systemui.shared.system; import android.content.ComponentName; import android.content.pm.ParceledListSlice; -import android.graphics.Rect; import android.view.DisplayInfo; import android.view.IPinnedStackController; import android.view.IPinnedStackListener; @@ -53,9 +52,9 @@ public class PinnedStackListenerForwarder extends IPinnedStackListener.Stub { } @Override - public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment) { + public void onMovementBoundsChanged(boolean fromImeAdjustment) { for (PinnedStackListener listener : mListeners) { - listener.onMovementBoundsChanged(animatingBounds, fromImeAdjustment); + listener.onMovementBoundsChanged(fromImeAdjustment); } } @@ -108,7 +107,7 @@ public class PinnedStackListenerForwarder extends IPinnedStackListener.Stub { public static class PinnedStackListener { public void onListenerRegistered(IPinnedStackController controller) {} - public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment) {} + public void onMovementBoundsChanged(boolean fromImeAdjustment) {} public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java index bbb83c73446c..76513c6ff3d5 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -109,4 +109,16 @@ public class RecentsAnimationControllerCompat { Log.e(TAG, "Failed to set overview reached state", e); } } + + /** + * @see IRecentsAnimationController#removeTask + */ + public boolean removeTask(int taskId) { + try { + return mAnimationController.removeTask(taskId); + } catch (RemoteException e) { + Log.e(TAG, "Failed to remove remote animation target", e); + return false; + } + } }
\ No newline at end of file diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java index 2c99c5c84015..c4cd192212a0 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java @@ -32,4 +32,10 @@ public interface RecentsAnimationListener { * Called when the animation into Recents was canceled. This call is made on the binder thread. */ void onAnimationCanceled(ThumbnailData thumbnailData); + + /** + * Called when the task of an activity that has been started while the recents animation + * was running becomes ready for control. + */ + void onTaskAppeared(RemoteAnimationTargetCompat app); } diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java index 7eb5a8f2b06c..e99245fa438f 100644 --- a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java +++ b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java @@ -34,6 +34,8 @@ import android.view.ViewGroup; import com.android.internal.annotations.VisibleForTesting; +import java.util.NoSuchElementException; + /** * Encapsulates all logic for secondary lockscreen state management. */ @@ -79,7 +81,9 @@ public class AdminSecondaryLockScreenController { private final IKeyguardCallback mCallback = new IKeyguardCallback.Stub() { @Override public void onDismiss() { - dismiss(UserHandle.getCallingUserId()); + mHandler.post(() -> { + dismiss(UserHandle.getCallingUserId()); + }); } @Override @@ -91,7 +95,9 @@ public class AdminSecondaryLockScreenController { if (surfacePackage != null) { mView.setChildSurfacePackage(surfacePackage); } else { - dismiss(KeyguardUpdateMonitor.getCurrentUser()); + mHandler.post(() -> { + dismiss(KeyguardUpdateMonitor.getCurrentUser()); + }); } } }; @@ -122,6 +128,7 @@ public class AdminSecondaryLockScreenController { // If the remote content is not readied within the timeout period, // move on without the secondary lockscreen. dismiss(userId); + Log.w(TAG, "Timed out waiting for secondary lockscreen content."); }, REMOTE_CONTENT_READY_TIMEOUT_MILLIS); } @@ -150,8 +157,12 @@ public class AdminSecondaryLockScreenController { * Displays the Admin security Surface view. */ public void show(Intent serviceIntent) { - mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE); - mParent.addView(mView); + if (mClient == null) { + mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE); + } + if (!mView.isAttachedToWindow()) { + mParent.addView(mView); + } } /** @@ -162,7 +173,11 @@ public class AdminSecondaryLockScreenController { mParent.removeView(mView); } if (mClient != null) { - mClient.asBinder().unlinkToDeath(mKeyguardClientDeathRecipient, 0); + try { + mClient.asBinder().unlinkToDeath(mKeyguardClientDeathRecipient, 0); + } catch (NoSuchElementException e) { + Log.w(TAG, "IKeyguardClient death recipient already released"); + } mContext.unbindService(mConnection); mClient = null; } @@ -185,10 +200,12 @@ public class AdminSecondaryLockScreenController { private void dismiss(int userId) { mHandler.removeCallbacksAndMessages(null); - if (mView != null && mView.isAttachedToWindow() - && userId == KeyguardUpdateMonitor.getCurrentUser()) { + if (mView.isAttachedToWindow() && userId == KeyguardUpdateMonitor.getCurrentUser()) { hide(); - mKeyguardCallback.dismiss(true, userId); + if (mKeyguardCallback != null) { + mKeyguardCallback.dismiss(/* securityVerified= */ true, userId, + /* bypassSecondaryLockScreen= */true); + } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java index caee8ccb6970..88f4176f5eac 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -34,6 +34,7 @@ import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; +import com.android.systemui.Dependency; import com.android.systemui.R; /** @@ -50,6 +51,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout private boolean mDismissing; protected boolean mResumed; private CountDownTimer mCountdownTimer = null; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; // To avoid accidental lockout due to events while the device in in the pocket, ignore // any passwords with length less than or equal to this length. @@ -61,6 +63,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) { super(context, attrs); + mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); } @Override @@ -151,6 +154,8 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL); LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED); } + + mKeyguardUpdateMonitor.setCredentialAttempted(); mPendingLockCheck = LockPatternChecker.checkCredential( mLockPatternUtils, password, diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index e3d9a267a149..d6fabd63420d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -126,8 +126,8 @@ public class KeyguardDisplayManager { final int displayId = display.getDisplayId(); Presentation presentation = mPresentations.get(displayId); if (presentation == null) { - final Presentation newPresentation = - new KeyguardPresentation(mContext, display, mInjectableInflater); + final Presentation newPresentation = new KeyguardPresentation(mContext, display, + mInjectableInflater.injectable(LayoutInflater.from(mContext))); newPresentation.setOnDismissListener(dialog -> { if (newPresentation.equals(mPresentations.get(displayId))) { mPresentations.remove(displayId); @@ -243,7 +243,7 @@ public class KeyguardDisplayManager { static final class KeyguardPresentation extends Presentation { private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s - private final InjectionInflationController mInjectableInflater; + private final LayoutInflater mInjectableLayoutInflater; private View mClock; private int mUsableWidth; private int mUsableHeight; @@ -261,9 +261,9 @@ public class KeyguardDisplayManager { }; KeyguardPresentation(Context context, Display display, - InjectionInflationController injectionInflater) { + LayoutInflater injectionLayoutInflater) { super(context, display, R.style.Theme_SystemUI_KeyguardPresentation); - mInjectableInflater = injectionInflater; + mInjectableLayoutInflater = injectionLayoutInflater; getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); setCancelable(false); } @@ -289,9 +289,7 @@ public class KeyguardDisplayManager { mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200; mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200; - LayoutInflater inflater = mInjectableInflater.injectable( - LayoutInflater.from(getContext())); - setContentView(inflater.inflate(R.layout.keyguard_presentation, null)); + setContentView(mInjectableLayoutInflater.inflate(R.layout.keyguard_presentation, null)); // Logic to make the lock screen fullscreen getWindow().getDecorView().setSystemUiVisibility( diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java index d5a08dda9853..aa2fe3c7f8fc 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java @@ -85,7 +85,8 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { // the user proved presence via some other way to the trust agent. Log.i(TAG, "TrustAgent dismissed Keyguard."); } - dismiss(false /* authenticated */, userId); + dismiss(false /* authenticated */, userId, + /* bypassSecondaryLockScreen */ false); } else { mViewMediatorCallback.playTrustedSound(); } @@ -190,7 +191,7 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { * @return True if the keyguard is done. */ public boolean dismiss(int targetUserId) { - return dismiss(false, targetUserId); + return dismiss(false, targetUserId, false); } public boolean handleBackKey() { @@ -206,8 +207,10 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { } @Override - public boolean dismiss(boolean authenticated, int targetUserId) { - return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId); + public boolean dismiss(boolean authenticated, int targetUserId, + boolean bypassSecondaryLockScreen) { + return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId, + bypassSecondaryLockScreen); } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java index d1544346a25a..af5196f92bcb 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java @@ -24,6 +24,8 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.media.MediaMetadata; +import android.media.session.MediaController; +import android.media.session.MediaSession; import android.util.Log; import android.view.View; import android.widget.ImageButton; @@ -40,6 +42,7 @@ import androidx.palette.graphics.Palette; import com.android.internal.util.ContrastColorUtil; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.media.MediaControllerFactory; import com.android.systemui.statusbar.notification.MediaNotificationProcessor; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.stack.MediaHeaderView; @@ -71,10 +74,11 @@ public class KeyguardMediaPlayer { private KeyguardMediaObserver mObserver; @Inject - public KeyguardMediaPlayer(Context context, @Background Executor backgroundExecutor) { + public KeyguardMediaPlayer(Context context, MediaControllerFactory factory, + @Background Executor backgroundExecutor) { mContext = context; mBackgroundExecutor = backgroundExecutor; - mViewModel = new KeyguardMediaViewModel(context); + mViewModel = new KeyguardMediaViewModel(context, factory); } /** Binds media controls to a view hierarchy. */ @@ -139,14 +143,16 @@ public class KeyguardMediaPlayer { private static final class KeyguardMediaViewModel { private final Context mContext; + private final MediaControllerFactory mMediaControllerFactory; private final MutableLiveData<KeyguardMedia> mMedia = new MutableLiveData<>(); private final Object mActionsLock = new Object(); private List<PendingIntent> mActions; private float mAlbumArtRadius; private int mAlbumArtSize; - KeyguardMediaViewModel(Context context) { + KeyguardMediaViewModel(Context context, MediaControllerFactory factory) { mContext = context; + mMediaControllerFactory = factory; loadDimens(); } @@ -162,6 +168,17 @@ public class KeyguardMediaPlayer { public void updateControls(NotificationEntry entry, Icon appIcon, MediaMetadata mediaMetadata) { + // Check the playback state of the media controller. If it is null, then the session was + // probably destroyed. Don't update in this case. + final MediaSession.Token token = entry.getSbn().getNotification().extras + .getParcelable(Notification.EXTRA_MEDIA_SESSION); + final MediaController controller = token != null + ? mMediaControllerFactory.create(token) : null; + if (controller != null && controller.getPlaybackState() == null) { + clearControls(); + return; + } + // Foreground and Background colors computed from album art Notification notif = entry.getSbn().getNotification(); int fgColor = notif.color; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java index 48c6bd114d4a..ad92f8f623e4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java @@ -282,6 +282,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit @Override public void onPatternDetected(final List<LockPatternView.Cell> pattern) { + mKeyguardUpdateMonitor.setCredentialAttempted(); mLockPatternView.disableInput(); if (mPendingLockCheck != null) { mPendingLockCheck.cancel(false); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java index 49dcfffb0d72..e38472745234 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java @@ -25,6 +25,15 @@ public interface KeyguardSecurityCallback { void dismiss(boolean securityVerified, int targetUserId); /** + * Dismiss the given security screen. + * @param securityVerified true if the user correctly entered credentials for the given screen. + * @param targetUserId a user that needs to be the foreground user at the dismissal completion. + * @param bypassSecondaryLockScreen true if the user can bypass the secondary lock screen, + * if any, during this dismissal. + */ + void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen); + + /** * Manually report user activity to keep the device awake. */ void userActivity(); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index ba8a1a945a77..5c3d17ce0e2b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -19,7 +19,9 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; import static android.view.ViewRootImpl.sNewInsetsMode; import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.systemBars; + import static com.android.systemui.DejankUtils.whitelistIpcs; + import static java.lang.Integer.max; import android.app.Activity; @@ -28,7 +30,6 @@ import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.res.ColorStateList; -import android.graphics.Rect; import android.metrics.LogMaker; import android.os.Handler; import android.os.Looper; @@ -115,7 +116,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe // Used to notify the container when something interesting happens. public interface SecurityCallback { - public boolean dismiss(boolean authenticated, int targetUserId); + public boolean dismiss(boolean authenticated, int targetUserId, + boolean bypassSecondaryLockScreen); public void userActivity(); public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput); @@ -504,9 +506,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe * @param authenticated true if the user entered the correct authentication * @param targetUserId a user that needs to be the foreground user at the finish (if called) * completion. + * @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary + * secondary lock screen requirement, if any. * @return true if keyguard is done */ - boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId) { + boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId, + boolean bypassSecondaryLockScreen) { if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); boolean finish = false; boolean strongAuth = false; @@ -555,7 +560,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe } } // Check for device admin specified additional security measures. - if (finish) { + if (finish && !bypassSecondaryLockScreen) { Intent secondaryLockscreenIntent = mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId); if (secondaryLockscreenIntent != null) { @@ -636,8 +641,15 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe mUpdateMonitor.cancelFaceAuth(); } + @Override public void dismiss(boolean authenticated, int targetId) { - mSecurityCallback.dismiss(authenticated, targetId); + dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false); + } + + @Override + public void dismiss(boolean authenticated, int targetId, + boolean bypassSecondaryLockScreen) { + mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen); } public boolean isVerifyUnlockOnly() { @@ -689,6 +701,9 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe @Override public void dismiss(boolean securityVerified, int targetUserId) { } @Override + public void dismiss(boolean authenticated, int targetId, + boolean bypassSecondaryLockScreen) { } + @Override public void onUserInput() { } @Override public void reset() {} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 57e3f14d7aed..367058fa58dd 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -57,7 +57,6 @@ import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; -import android.media.AudioManager; import android.os.CancellationSignal; import android.os.Handler; import android.os.IRemoteCallback; @@ -82,6 +81,8 @@ import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; +import androidx.lifecycle.Observer; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.widget.LockPatternUtils; import com.android.settingslib.WirelessUtils; @@ -97,6 +98,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.util.Assert; +import com.android.systemui.util.RingerModeTracker; import com.google.android.collect.Lists; @@ -223,6 +225,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private int mRingMode; private int mPhoneState; private boolean mKeyguardIsVisible; + private boolean mCredentialAttempted; private boolean mKeyguardGoingAway; private boolean mGoingToSleep; private boolean mBouncer; @@ -257,6 +260,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private TrustManager mTrustManager; private UserManager mUserManager; private KeyguardBypassController mKeyguardBypassController; + private RingerModeTracker mRingerModeTracker; private int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED; private int mFaceRunningState = BIOMETRIC_STATE_STOPPED; private LockPatternUtils mLockPatternUtils; @@ -294,6 +298,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final Handler mHandler; + private final Observer<Integer> mRingerModeObserver = new Observer<Integer>() { + @Override + public void onChanged(Integer ringer) { + mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, ringer, 0).sendToTarget(); + } + }; + private SparseBooleanArray mFaceSettingEnabledForUser = new SparseBooleanArray(); private BiometricManager mBiometricManager; private IBiometricEnabledOnKeyguardCallback mBiometricEnabledCallback = @@ -498,11 +509,21 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } /** + * Updates KeyguardUpdateMonitor's internal state to know if credential was attempted on + * bouncer. Note that this does not care if the credential was correct/incorrect. This is + * cleared when the user leaves the bouncer (unlocked, screen off, back to lockscreen, etc) + */ + public void setCredentialAttempted() { + mCredentialAttempted = true; + updateBiometricListeningState(); + } + + /** * Updates KeyguardUpdateMonitor's internal state to know if keyguard is goingAway */ public void setKeyguardGoingAway(boolean goingAway) { mKeyguardGoingAway = goingAway; - updateFingerprintListeningState(); + updateBiometricListeningState(); } /** @@ -664,6 +685,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab updateFingerprintListeningState(); } else { setFingerprintRunningState(BIOMETRIC_STATE_STOPPED); + mFingerprintCancelSignal = null; + mFaceCancelSignal = null; } if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) { @@ -679,6 +702,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab getCurrentUser()); } + if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT + || msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) { + mFingerprintLockedOut = true; + } + for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -688,6 +716,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleFingerprintLockoutReset() { + mFingerprintLockedOut = false; updateFingerprintListeningState(); } @@ -1126,9 +1155,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } mHandler.obtainMessage(MSG_SIM_STATE_CHANGE, args.subId, args.slotId, args.simState) .sendToTarget(); - } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_RINGER_MODE_CHANGED, - intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1), 0)); } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state)); @@ -1274,6 +1300,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private CancellationSignal mFaceCancelSignal; private FingerprintManager mFpm; private FaceManager mFaceManager; + private boolean mFingerprintLockedOut; /** * When we receive a @@ -1481,6 +1508,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mUserTrustIsUsuallyManaged.delete(userId); } + private void registerRingerTracker() { + mRingerModeTracker.getRingerMode().observeForever(mRingerModeObserver); + } + @VisibleForTesting @Inject protected KeyguardUpdateMonitor( @@ -1488,6 +1519,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @Main Looper mainLooper, BroadcastDispatcher broadcastDispatcher, DumpManager dumpManager, + RingerModeTracker ringerModeTracker, @Background Executor backgroundExecutor) { mContext = context; mSubscriptionManager = SubscriptionManager.from(context); @@ -1495,6 +1527,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged); mBackgroundExecutor = backgroundExecutor; mBroadcastDispatcher = broadcastDispatcher; + mRingerModeTracker = ringerModeTracker; dumpManager.registerDumpable(getClass().getName(), this); mHandler = new Handler(mainLooper) { @@ -1628,10 +1661,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab filter.addAction(Intent.ACTION_SERVICE_STATE); filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); - filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler); + mHandler.post(this::registerRingerTracker); + final IntentFilter allUserFilter = new IntentFilter(); allUserFilter.addAction(Intent.ACTION_USER_INFO_CHANGED); allUserFilter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); @@ -1820,13 +1854,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private boolean shouldListenForFingerprint() { + final boolean allowedOnBouncer = + !(mFingerprintLockedOut && mBouncer && mCredentialAttempted); + // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware. final boolean shouldListen = (mKeyguardIsVisible || !mDeviceInteractive || (mBouncer && !mKeyguardGoingAway) || mGoingToSleep || shouldListenForFingerprintAssistant() || (mKeyguardOccluded && mIsDreaming)) && !mSwitchingUser && !isFingerprintDisabled(getCurrentUser()) - && (!mKeyguardGoingAway || !mDeviceInteractive) && mIsPrimaryUser; + && (!mKeyguardGoingAway || !mDeviceInteractive) && mIsPrimaryUser + && allowedOnBouncer; return shouldListen; } @@ -2372,6 +2410,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // camera requests dismiss keyguard (tapping on photos for example). When these happen, // face auth should resume. mSecureCameraLaunched = false; + } else { + mCredentialAttempted = false; } for (int i = 0; i < mCallbacks.size(); i++) { @@ -2776,6 +2816,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver); mBroadcastDispatcher.unregisterReceiver(mBroadcastAllReceiver); + mRingerModeTracker.getRingerMode().removeObserver(mRingerModeObserver); mHandler.removeCallbacksAndMessages(null); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java index 2f103940f3e4..6a90d00c1e75 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java @@ -114,6 +114,11 @@ public interface KeyguardViewController { void keyguardGoingAway(); /** + * Sets the system state depending on whether the keyguard is going away or not. + */ + void setKeyguardGoingAwayState(boolean isKeyguardGoingAway); + + /** * @return Whether window animation for unlock should be disabled. */ boolean shouldDisableWindowAnimationsForUnlock(); @@ -147,6 +152,28 @@ public interface KeyguardViewController { */ ViewRootImpl getViewRootImpl(); + /** + * Notifies that the user has authenticated by other means than using the bouncer, for example, + * fingerprint. + */ + void notifyKeyguardAuthenticated(boolean strongAuth); + + /** + * Shows the Bouncer. + * + */ + void showBouncer(boolean scrimmed); + + /** + * Returns {@code true} when the bouncer is currently showing + */ + boolean isBouncerShowing(); + + /** + * When bouncer is fully visible or it is showing but animation didn't finish yet. + */ + boolean bouncerIsOrWillBeShowing(); + // TODO: Deprecate registerStatusBar in KeyguardViewController interface. It is currently // only used for testing purposes in StatusBarKeyguardViewManager, and it prevents us from // achieving complete abstraction away from where the Keyguard View is mounted. diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java index 362014f51e36..e17d4e69093a 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java @@ -25,6 +25,7 @@ import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.util.time.SystemClock; /** * Extends the lifetime of foreground notification services such that they show for at least @@ -39,8 +40,10 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx private NotificationSafeToRemoveCallback mNotificationSafeToRemoveCallback; private ArraySet<NotificationEntry> mManagedEntries = new ArraySet<>(); private Handler mHandler = new Handler(Looper.getMainLooper()); + private final SystemClock mSystemClock; - public ForegroundServiceLifetimeExtender() { + public ForegroundServiceLifetimeExtender(SystemClock systemClock) { + mSystemClock = systemClock; } @Override @@ -55,8 +58,8 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx return false; } - long currentTime = System.currentTimeMillis(); - return currentTime - entry.getSbn().getPostTime() < MIN_FGS_TIME_MS; + long currentTime = mSystemClock.uptimeMillis(); + return currentTime - entry.getCreationTime() < MIN_FGS_TIME_MS; } @Override @@ -84,7 +87,7 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx } }; long delayAmt = MIN_FGS_TIME_MS - - (System.currentTimeMillis() - entry.getSbn().getPostTime()); + - (mSystemClock.uptimeMillis() - entry.getCreationTime()); mHandler.postDelayed(r, delayAmt); } } diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java index f01fa811c529..ef1f4e0afede 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java @@ -30,6 +30,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.util.time.SystemClock; import javax.inject.Inject; import javax.inject.Singleton; @@ -49,7 +50,8 @@ public class ForegroundServiceNotificationListener { public ForegroundServiceNotificationListener(Context context, ForegroundServiceController foregroundServiceController, NotificationEntryManager notificationEntryManager, - NotifPipeline notifPipeline) { + NotifPipeline notifPipeline, + SystemClock systemClock) { mContext = context; mForegroundServiceController = foregroundServiceController; @@ -76,7 +78,8 @@ public class ForegroundServiceNotificationListener { removeNotification(entry.getSbn()); } }); - mEntryManager.addNotificationLifetimeExtender(new ForegroundServiceLifetimeExtender()); + mEntryManager.addNotificationLifetimeExtender( + new ForegroundServiceLifetimeExtender(systemClock)); notifPipeline.addCollectionListener(new NotifCollectionListener() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index 23fa645eff16..5442299881c0 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -120,7 +120,7 @@ public class ImageWallpaper extends WallpaperService { private void init(DozeParameters dozeParameters) { mIsHighEndGfx = ActivityManager.isHighEndGfx(); mDisplayNeedsBlanking = dozeParameters.getDisplayNeedsBlanking(); - mNeedTransition = mIsHighEndGfx && !mDisplayNeedsBlanking; + mNeedTransition = false; // We will preserve EGL context when we are in lock screen or aod // to avoid janking in following transition, we need to release when back to home. @@ -137,7 +137,7 @@ public class ImageWallpaper extends WallpaperService { mRenderer = getRendererInstance(); getDisplayContext().getDisplay().getDisplayInfo(mDisplayInfo); setFixedSizeAllowed(true); - setOffsetNotificationsEnabled(true); + setOffsetNotificationsEnabled(mNeedTransition); updateSurfaceSize(); } diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java index 6923079dd5c4..2eba9521b9e7 100644 --- a/packages/SystemUI/src/com/android/systemui/Interpolators.java +++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java @@ -54,6 +54,11 @@ public class Interpolators { public static final Interpolator PANEL_CLOSE_ACCELERATED = new PathInterpolator(0.3f, 0, 0.5f, 1); public static final Interpolator BOUNCE = new BounceInterpolator(); + /** + * For state transitions on the control panel that lives in GlobalActions. + */ + public static final Interpolator CONTROL_STATE = new PathInterpolator(0.4f, 0f, 0.2f, + 1.0f); /** * Interpolator to be used when animating a move based on a click. Pair with enough duration. diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 9d885fd3c207..da5c2968c6ac 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -17,6 +17,8 @@ package com.android.systemui.bubbles; import static android.app.Notification.FLAG_BUBBLE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL; import static android.service.notification.NotificationListenerService.REASON_CANCEL; @@ -30,7 +32,6 @@ import static android.view.View.VISIBLE; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER; -import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_EXPERIMENTS; import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.systemui.statusbar.StatusBarState.SHADE; @@ -43,6 +44,9 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.UserIdInt; import android.app.ActivityManager.RunningTaskInfo; +import android.app.INotificationManager; +import android.app.Notification; +import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; @@ -83,6 +87,7 @@ import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationRemoveInterceptor; +import com.android.systemui.statusbar.notification.NotificationChannelHelper; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotifCollection; @@ -169,6 +174,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi private final NotificationShadeWindowController mNotificationShadeWindowController; private final ZenModeController mZenModeController; private StatusBarStateListener mStatusBarStateListener; + private INotificationManager mINotificationManager; // Callback that updates BubbleOverflowActivity on data change. @Nullable private Runnable mOverflowCallback = null; @@ -293,11 +299,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi FeatureFlags featureFlags, DumpManager dumpManager, FloatingContentCoordinator floatingContentCoordinator, - SysUiState sysUiState) { + SysUiState sysUiState, + INotificationManager notificationManager) { this(context, notificationShadeWindowController, statusBarStateController, shadeController, data, null /* synchronizer */, configurationController, interruptionStateProvider, zenModeController, notifUserManager, groupManager, entryManager, - notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState); + notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState, + notificationManager); } /** @@ -319,7 +327,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi FeatureFlags featureFlags, DumpManager dumpManager, FloatingContentCoordinator floatingContentCoordinator, - SysUiState sysUiState) { + SysUiState sysUiState, + INotificationManager notificationManager) { dumpManager.registerDumpable(TAG, this); mContext = context; mShadeController = shadeController; @@ -327,6 +336,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mNotifUserManager = notifUserManager; mZenModeController = zenModeController; mFloatingContentCoordinator = floatingContentCoordinator; + mINotificationManager = notificationManager; mZenModeController.addCallback(new ZenModeController.Callback() { @Override public void onZenChanged(int zen) { @@ -599,7 +609,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (mStackView == null) { mStackView = new BubbleStackView( mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator, - mSysUiState); + mSysUiState, mNotificationShadeWindowController); ViewGroup nsv = mNotificationShadeWindowController.getNotificationShadeView(); int bubbleScrimIndex = nsv.indexOfChild(nsv.findViewById(R.id.scrim_for_bubble)); int stackIndex = bubbleScrimIndex + 1; // Show stack above bubble scrim. @@ -719,13 +729,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } /** - * Tell the stack of bubbles to expand. - */ - public void expandStack() { - mBubbleData.setExpanded(true); - } - - /** * Tell the stack of bubbles to collapse. */ public void collapseStack() { @@ -753,12 +756,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi return (isSummary && isSuppressedSummary) || isBubbleAndSuppressed; } - @VisibleForTesting - void selectBubble(String key) { - Bubble bubble = mBubbleData.getBubbleWithKey(key); - mBubbleData.setSelectedBubble(bubble); - } - void promoteBubbleFromOverflow(Bubble bubble) { bubble.setInflateSynchronously(mInflateSynchronously); mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory); @@ -778,13 +775,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } /** - * Tell the stack of bubbles to be dismissed, this will remove all of the bubbles in the stack. - */ - void dismissStack(@DismissReason int reason) { - mBubbleData.dismissAll(reason); - } - - /** * Directs a back gesture at the bubble stack. When opened, the current expanded bubble * is forwarded a back key down/up pair. */ @@ -829,37 +819,43 @@ public class BubbleController implements ConfigurationController.ConfigurationLi * This method will collapse the shade, create the bubble without a flyout or dot, and suppress * the notification from appearing in the shade. * - * @param entry the notification to show as a bubble. + * @param entry the notification to change bubble state for. + * @param shouldBubble whether the notification should show as a bubble or not. */ - public void onUserCreatedBubbleFromNotification(NotificationEntry entry) { - if (DEBUG_EXPERIMENTS || DEBUG_BUBBLE_CONTROLLER) { - Log.d(TAG, "onUserCreatedBubble: " + entry.getKey()); + public void onUserChangedBubble(NotificationEntry entry, boolean shouldBubble) { + NotificationChannel channel = entry.getChannel(); + final String appPkg = entry.getSbn().getPackageName(); + final int appUid = entry.getSbn().getUid(); + if (channel == null || appPkg == null) { + return; } - mShadeController.collapsePanel(true); - entry.setFlagBubble(true); - updateBubble(entry, true /* suppressFlyout */, false /* showInShade */); - mUserCreatedBubbles.add(entry.getKey()); - mUserBlockedBubbles.remove(entry.getKey()); - } - /** - * Called when a user has indicated that an active notification appearing as a bubble should - * no longer be shown as a bubble. - * - * @param entry the notification to no longer show as a bubble. - */ - public void onUserDemotedBubbleFromNotification(NotificationEntry entry) { - if (DEBUG_EXPERIMENTS || DEBUG_BUBBLE_CONTROLLER) { - Log.d(TAG, "onUserDemotedBubble: " + entry.getKey()); + // Update the state in NotificationManagerService + try { + int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; + mBarService.onNotificationBubbleChanged(entry.getKey(), shouldBubble, flags); + } catch (RemoteException e) { } - entry.setFlagBubble(false); - removeBubble(entry, DISMISS_BLOCKED); - mUserCreatedBubbles.remove(entry.getKey()); - if (BubbleExperimentConfig.isPackageWhitelistedToAutoBubble( - mContext, entry.getSbn().getPackageName())) { - // This package is whitelist but user demoted the bubble, let's save it so we don't - // auto-bubble for the whitelist again. - mUserBlockedBubbles.add(entry.getKey()); + + // Change the settings + channel = NotificationChannelHelper.createConversationChannelIfNeeded(mContext, + mINotificationManager, entry, channel); + channel.setAllowBubbles(shouldBubble); + try { + int currentPref = mINotificationManager.getBubblePreferenceForPackage(appPkg, appUid); + if (shouldBubble && currentPref == BUBBLE_PREFERENCE_NONE) { + mINotificationManager.setBubblesAllowed(appPkg, appUid, BUBBLE_PREFERENCE_SELECTED); + } + mINotificationManager.updateNotificationChannelForPackage(appPkg, appUid, channel); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage()); + } + + if (shouldBubble) { + mShadeController.collapsePanel(true); + if (entry.getRow() != null) { + entry.getRow().updateBubbleButton(); + } } } @@ -1007,14 +1003,15 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } else { // Update the flag for SysUI bubble.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE; + if (bubble.getEntry().getRow() != null) { + bubble.getEntry().getRow().updateBubbleButton(); + } - // Make sure NoMan knows it's not a bubble anymore so anyone querying it - // will get right result back + // Update the state in NotificationManagerService try { mBarService.onNotificationBubbleChanged(bubble.getKey(), - false /* isBubble */); + false /* isBubble */, 0 /* flags */); } catch (RemoteException e) { - // Bad things have happened } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java index be9cd5f01c86..a1393cddc9f6 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java @@ -28,6 +28,7 @@ import android.content.Context; import android.service.notification.NotificationListenerService; import android.util.Log; import android.util.Pair; +import android.view.View; import androidx.annotation.Nullable; @@ -119,6 +120,7 @@ public class BubbleData { /** Bubbles that are being loaded but haven't been added to the stack just yet. */ private final List<Bubble> mPendingBubbles; private Bubble mSelectedBubble; + private boolean mShowingOverflow; private boolean mExpanded; private final int mMaxBubbles; private final int mMaxOverflowBubbles; @@ -214,6 +216,10 @@ public class BubbleData { dispatchPendingChanges(); } + void setShowingOverflow(boolean showingOverflow) { + mShowingOverflow = showingOverflow; + } + private void moveOverflowBubbleToPending(Bubble b) { // Preserve new order for next repack, which sorts by last updated time. b.markUpdatedAt(mTimeSource.currentTimeMillis()); @@ -512,9 +518,11 @@ public class BubbleData { if (DEBUG_BUBBLE_DATA) { Log.d(TAG, "setSelectedBubbleInternal: " + bubble); } - if (Objects.equals(bubble, mSelectedBubble)) { + if (!mShowingOverflow && Objects.equals(bubble, mSelectedBubble)) { return; } + // Otherwise, if we are showing the overflow menu, return to the previously selected bubble. + if (bubble != null && !mBubbles.contains(bubble) && !mOverflowBubbles.contains(bubble)) { Log.e(TAG, "Cannot select bubble which doesn't exist!" + " (" + bubble + ") bubbles=" + mBubbles); @@ -558,6 +566,10 @@ public class BubbleData { mStateChange.orderChanged |= repackAll(); // Save the state which should be returned to when expanded (with no other changes) + if (mShowingOverflow) { + // Show previously selected bubble instead of overflow menu on next expansion. + setSelectedBubbleInternal(mSelectedBubble); + } if (mBubbles.indexOf(mSelectedBubble) > 0) { // Move the selected bubble to the top while collapsed. if (!mSelectedBubble.isOngoing() && mBubbles.get(0).isOngoing()) { @@ -751,6 +763,7 @@ public class BubbleData { } @VisibleForTesting(visibility = PRIVATE) + @Nullable Bubble getBubbleWithKey(String key) { for (int i = 0; i < mBubbles.size(); i++) { Bubble bubble = mBubbles.get(i); @@ -761,6 +774,17 @@ public class BubbleData { return null; } + @Nullable + Bubble getBubbleWithView(View view) { + for (int i = 0; i < mBubbles.size(); i++) { + Bubble bubble = mBubbles.get(i); + if (bubble.getIconView() != null && bubble.getIconView().equals(view)) { + return bubble; + } + } + return null; + } + @VisibleForTesting(visibility = PRIVATE) Bubble getOverflowBubbleWithKey(String key) { for (int i = 0; i < mOverflowBubbles.size(); i++) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index 496456deccee..93fb6972fad5 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -16,6 +16,7 @@ package com.android.systemui.bubbles; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.view.Display.INVALID_DISPLAY; @@ -126,6 +127,7 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(), 0 /* enterResId */, 0 /* exitResId */); options.setTaskAlwaysOnTop(true); + options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW); // Post to keep the lifecycle normal post(() -> { if (DEBUG_BUBBLE_EXPANDED_VIEW) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index eff693436451..1cabe221bef1 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -30,6 +30,7 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; +import android.annotation.SuppressLint; import android.app.Notification; import android.content.Context; import android.content.res.Configuration; @@ -43,6 +44,7 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.Region; import android.os.Bundle; import android.os.Vibrator; import android.util.Log; @@ -81,8 +83,10 @@ import com.android.systemui.bubbles.animation.StackAnimationController; import com.android.systemui.model.SysUiState; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.SysUiStatsLog; +import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.util.DismissCircleView; import com.android.systemui.util.FloatingContentCoordinator; +import com.android.systemui.util.RelativeTouchListener; import com.android.systemui.util.animation.PhysicsAnimator; import com.android.systemui.util.magnetictarget.MagnetizedObject; @@ -239,7 +243,6 @@ public class BubbleStackView extends FrameLayout { mExpandedAnimationController.dump(fd, pw, args); } - private BubbleTouchHandler mTouchHandler; private BubbleController.BubbleExpandListener mExpandListener; private SysUiState mSysUiState; @@ -296,7 +299,7 @@ public class BubbleStackView extends FrameLayout { @Override public void setValue(Object o, float v) { - onFlyoutDragged(v); + setFlyoutStateForDragLength(v); } }; @@ -328,6 +331,8 @@ public class BubbleStackView extends FrameLayout { @NonNull private final SurfaceSynchronizer mSurfaceSynchronizer; + private final NotificationShadeWindowController mNotificationShadeWindowController; + /** * The currently magnetized object, which is being dragged and will be attracted to the magnetic * dismiss target. @@ -337,13 +342,6 @@ public class BubbleStackView extends FrameLayout { private MagnetizedObject<?> mMagnetizedObject; /** - * The action to run when the magnetized object is released in the dismiss target. - * - * This will actually perform the dismissal of either the stack or an individual bubble. - */ - private Runnable mReleasedInDismissTargetAction; - - /** * The MagneticTarget instance for our circular dismiss view. This is added to the * MagnetizedObject instances for the stack and any dragged-out bubbles. */ @@ -377,7 +375,7 @@ public class BubbleStackView extends FrameLayout { public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) { mExpandedAnimationController.dismissDraggedOutBubble( mExpandedAnimationController.getDraggedOutBubble(), - mReleasedInDismissTargetAction); + BubbleStackView.this::dismissMagnetizedObject); hideDismissTarget(); } }; @@ -410,7 +408,7 @@ public class BubbleStackView extends FrameLayout { mStackAnimationController.implodeStack( () -> { resetDesaturationAndDarken(); - mReleasedInDismissTargetAction.run(); + dismissMagnetizedObject(); } ); @@ -418,6 +416,197 @@ public class BubbleStackView extends FrameLayout { } }; + /** + * Click listener set on each bubble view. When collapsed, clicking a bubble expands the stack. + * When expanded, clicking a bubble either expands that bubble, or collapses the stack. + */ + private OnClickListener mBubbleClickListener = new OnClickListener() { + @Override + public void onClick(View view) { + final Bubble clickedBubble = mBubbleData.getBubbleWithView(view); + + // If the bubble has since left us, ignore the click. + if (clickedBubble == null) { + return; + } + + final boolean clickedBubbleIsCurrentlyExpandedBubble = + clickedBubble.getKey().equals(mExpandedBubble.getKey()); + + if (isExpanded() && !clickedBubbleIsCurrentlyExpandedBubble) { + if (clickedBubble != mBubbleData.getSelectedBubble()) { + // Select the clicked bubble. + mBubbleData.setSelectedBubble(clickedBubble); + } else { + // If the clicked bubble is the selected bubble (but not the expanded bubble), + // that means overflow was previously expanded. Set the selected bubble + // internally without going through BubbleData (which would ignore it since it's + // already selected). + mBubbleData.setShowingOverflow(true); + setSelectedBubble(clickedBubble); + } + } else { + // Otherwise, we either tapped the stack (which means we're collapsed + // and should expand) or the currently selected bubble (we're expanded + // and should collapse). + if (!maybeShowStackUserEducation()) { + mBubbleData.setExpanded(!mBubbleData.isExpanded()); + } + } + } + }; + + /** + * Touch listener set on each bubble view. This enables dragging and dismissing the stack (when + * collapsed), or individual bubbles (when expanded). + */ + private RelativeTouchListener mBubbleTouchListener = new RelativeTouchListener() { + + @Override + public boolean onDown(@NonNull View v, @NonNull MotionEvent ev) { + // If we're expanding or collapsing, consume but ignore all touch events. + if (mIsExpansionAnimating) { + return true; + } + + if (mBubbleData.isExpanded()) { + maybeShowManageEducation(false /* show */); + + // If we're expanded, tell the animation controller to prepare to drag this bubble, + // dispatching to the individual bubble magnet listener. + mExpandedAnimationController.prepareForBubbleDrag( + v /* bubble */, + mMagneticTarget, + mIndividualBubbleMagnetListener); + + // Save the magnetized individual bubble so we can dispatch touch events to it. + mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut(); + } else { + // If we're collapsed, prepare to drag the stack. Cancel active animations, set the + // animation controller, and hide the flyout. + mStackAnimationController.cancelStackPositionAnimations(); + mBubbleContainer.setActiveController(mStackAnimationController); + hideFlyoutImmediate(); + + // Also, save the magnetized stack so we can dispatch touch events to it. + mMagnetizedObject = mStackAnimationController.getMagnetizedStack(mMagneticTarget); + mMagnetizedObject.setMagnetListener(mStackMagnetListener); + } + + passEventToMagnetizedObject(ev); + + // Bubbles are always interested in all touch events! + return true; + } + + @Override + public void onMove(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX, + float viewInitialY, float dx, float dy) { + // If we're expanding or collapsing, ignore all touch events. + if (mIsExpansionAnimating) { + return; + } + + // Show the dismiss target, if we haven't already. + springInDismissTargetMaybe(); + + // First, see if the magnetized object consumes the event - if so, we shouldn't move the + // bubble since it's stuck to the target. + if (!passEventToMagnetizedObject(ev)) { + if (mBubbleData.isExpanded()) { + mExpandedAnimationController.dragBubbleOut( + v, viewInitialX + dx, viewInitialY + dy); + } else { + hideStackUserEducation(false /* fromExpansion */); + mStackAnimationController.moveStackFromTouch( + viewInitialX + dx, viewInitialY + dy); + } + } + } + + @Override + public void onUp(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX, + float viewInitialY, float dx, float dy, float velX, float velY) { + // If we're expanding or collapsing, ignore all touch events. + if (mIsExpansionAnimating) { + return; + } + + // First, see if the magnetized object consumes the event - if so, the bubble was + // released in the target or flung out of it, and we should ignore the event. + if (!passEventToMagnetizedObject(ev)) { + if (mBubbleData.isExpanded()) { + mExpandedAnimationController.snapBubbleBack(v, velX, velY); + } else { + // Fling the stack to the edge, and save whether or not it's going to end up on + // the left side of the screen. + mStackOnLeftOrWillBe = + mStackAnimationController.flingStackThenSpringToEdge( + viewInitialX + dx, velX, velY) <= 0; + + updateBubbleZOrdersAndDotPosition(true /* animate */); + + logBubbleEvent(null /* no bubble associated with bubble stack move */, + SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_MOVED); + } + + hideDismissTarget(); + } + } + }; + + /** Click listener set on the flyout, which expands the stack when the flyout is tapped. */ + private OnClickListener mFlyoutClickListener = new OnClickListener() { + @Override + public void onClick(View view) { + if (maybeShowStackUserEducation()) { + // If we're showing user education, don't open the bubble show the education first + mBubbleToExpandAfterFlyoutCollapse = null; + } else { + mBubbleToExpandAfterFlyoutCollapse = mBubbleData.getSelectedBubble(); + } + + mFlyout.removeCallbacks(mHideFlyout); + mHideFlyout.run(); + } + }; + + /** Touch listener for the flyout. This enables the drag-to-dismiss gesture on the flyout. */ + private RelativeTouchListener mFlyoutTouchListener = new RelativeTouchListener() { + + @Override + public boolean onDown(@NonNull View v, @NonNull MotionEvent ev) { + mFlyout.removeCallbacks(mHideFlyout); + return true; + } + + @Override + public void onMove(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX, + float viewInitialY, float dx, float dy) { + setFlyoutStateForDragLength(dx); + } + + @Override + public void onUp(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX, + float viewInitialY, float dx, float dy, float velX, float velY) { + final boolean onLeft = mStackAnimationController.isStackOnLeftSide(); + final boolean metRequiredVelocity = + onLeft ? velX < -FLYOUT_DISMISS_VELOCITY : velX > FLYOUT_DISMISS_VELOCITY; + final boolean metRequiredDeltaX = + onLeft + ? dx < -mFlyout.getWidth() * FLYOUT_DRAG_PERCENT_DISMISS + : dx > mFlyout.getWidth() * FLYOUT_DRAG_PERCENT_DISMISS; + final boolean isCancelFling = onLeft ? velX > 0 : velX < 0; + final boolean shouldDismiss = metRequiredVelocity + || (metRequiredDeltaX && !isCancelFling); + + mFlyout.removeCallbacks(mHideFlyout); + animateFlyoutCollapsed(shouldDismiss, velX); + + maybeShowStackUserEducation(); + } + }; + private ViewGroup mDismissTargetContainer; private PhysicsAnimator<View> mDismissTargetAnimator; private PhysicsAnimator.SpringConfig mDismissTargetSpring = new PhysicsAnimator.SpringConfig( @@ -436,18 +625,19 @@ public class BubbleStackView extends FrameLayout { private BubbleManageEducationView mManageEducationView; private boolean mAnimatingManageEducationAway; + @SuppressLint("ClickableViewAccessibility") public BubbleStackView(Context context, BubbleData data, @Nullable SurfaceSynchronizer synchronizer, FloatingContentCoordinator floatingContentCoordinator, - SysUiState sysUiState) { + SysUiState sysUiState, + NotificationShadeWindowController notificationShadeWindowController) { super(context); mBubbleData = data; mInflater = LayoutInflater.from(context); - mTouchHandler = new BubbleTouchHandler(this, data, context); - setOnTouchListener(mTouchHandler); mSysUiState = sysUiState; + mNotificationShadeWindowController = notificationShadeWindowController; Resources res = getResources(); mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered); @@ -514,7 +704,7 @@ public class BubbleStackView extends FrameLayout { mDismissTargetContainer = new FrameLayout(context); mDismissTargetContainer.setLayoutParams(new FrameLayout.LayoutParams( MATCH_PARENT, - getResources().getDimensionPixelSize(R.dimen.pip_dismiss_gradient_height), + getResources().getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height), Gravity.BOTTOM)); mDismissTargetContainer.setClipChildren(false); mDismissTargetContainer.addView(targetView); @@ -523,7 +713,7 @@ public class BubbleStackView extends FrameLayout { // Start translated down so the target springs up. targetView.setTranslationY( - getResources().getDimensionPixelSize(R.dimen.pip_dismiss_gradient_height)); + getResources().getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height)); // Save the MagneticTarget instance for the newly set up view - we'll add this to the // MagnetizedObjects. @@ -641,6 +831,18 @@ public class BubbleStackView extends FrameLayout { mDesaturateAndDarkenPaint.setColorFilter(new ColorMatrixColorFilter(animatedMatrix)); mDesaturateAndDarkenTargetView.setLayerPaint(mDesaturateAndDarkenPaint); }); + + // If the stack itself is touched, it means none of its touchable views (bubbles, flyouts, + // ActivityViews, etc.) were touched. Collapse the stack if it's expanded. + setOnTouchListener((view, ev) -> { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + if (mBubbleData.isExpanded()) { + mBubbleData.setExpanded(false); + } + } + + return false; + }); } private void setUpUserEducation() { @@ -690,6 +892,7 @@ public class BubbleStackView extends FrameLayout { } } + @SuppressLint("ClickableViewAccessibility") private void setUpFlyout() { if (mFlyout != null) { removeView(mFlyout); @@ -699,6 +902,8 @@ public class BubbleStackView extends FrameLayout { mFlyout.animate() .setDuration(FLYOUT_ALPHA_ANIMATION_DURATION) .setInterpolator(new AccelerateDecelerateInterpolator()); + mFlyout.setOnClickListener(mFlyoutClickListener); + mFlyout.setOnTouchListener(mFlyoutTouchListener); addView(mFlyout, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); } @@ -718,6 +923,7 @@ public class BubbleStackView extends FrameLayout { mBubbleContainer.addView(mBubbleOverflow.getBtn(), overflowBtnIndex, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + mBubbleOverflow.getBtn().setOnClickListener(v -> setSelectedBubble(mBubbleOverflow)); } /** * Handle theme changes. @@ -920,6 +1126,7 @@ public class BubbleStackView extends FrameLayout { } // via BubbleData.Listener + @SuppressLint("ClickableViewAccessibility") void addBubble(Bubble bubble) { if (DEBUG_BUBBLE_STACK_VIEW) { Log.d(TAG, "addBubble: " + bubble); @@ -944,6 +1151,9 @@ public class BubbleStackView extends FrameLayout { bubble.getIconView().setDotPositionOnLeft( !mStackOnLeftOrWillBe /* onLeft */, false /* animate */); + bubble.getIconView().setOnClickListener(mBubbleClickListener); + bubble.getIconView().setOnTouchListener(mBubbleTouchListener); + mBubbleContainer.addView(bubble.getIconView(), 0, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); ViewClippingUtil.setClippingDeactivated(bubble.getIconView(), true, mClippingParameters); @@ -1009,10 +1219,6 @@ public class BubbleStackView extends FrameLayout { updatePointerPosition(); } - void showOverflow() { - setSelectedBubble(mBubbleOverflow); - } - /** * Changes the currently selected bubble. If the stack is already expanded, the newly selected * bubble will be shown immediately. This does not change the expanded state or change the @@ -1026,8 +1232,12 @@ public class BubbleStackView extends FrameLayout { if (mExpandedBubble != null && mExpandedBubble.equals(bubbleToSelect)) { return; } + if (bubbleToSelect == null || bubbleToSelect.getKey() != BubbleOverflow.KEY) { + mBubbleData.setShowingOverflow(false); + } final BubbleViewProvider previouslySelected = mExpandedBubble; mExpandedBubble = bubbleToSelect; + updatePointerPosition(); if (mIsExpanded) { // Make the container of the expanded view transparent before removing the expanded view @@ -1037,7 +1247,6 @@ public class BubbleStackView extends FrameLayout { mSurfaceSynchronizer.syncSurfaceAndRun(() -> { previouslySelected.setContentVisibility(false); updateExpandedBubble(); - updatePointerPosition(); requestUpdate(); logBubbleEvent(previouslySelected, @@ -1143,7 +1352,8 @@ public class BubbleStackView extends FrameLayout { if (show && mShouldShowManageEducation && mManageEducationView.getVisibility() != VISIBLE - && mIsExpanded) { + && mIsExpanded + && mExpandedBubble.getExpandedView() != null) { mManageEducationView.setAlpha(0); mManageEducationView.setVisibility(VISIBLE); mManageEducationView.post(() -> { @@ -1177,14 +1387,6 @@ public class BubbleStackView extends FrameLayout { } } - /* - * Sets the action to run to dismiss the currently dragging object (either the stack or an - * individual bubble). - */ - public void setReleasedInDismissTargetAction(Runnable action) { - mReleasedInDismissTargetAction = action; - } - /** * Dismiss the stack of bubbles. * @@ -1201,54 +1403,6 @@ public class BubbleStackView extends FrameLayout { } /** - * @return the view the touch event is on - */ - @Nullable - public View getTargetView(MotionEvent event) { - float x = event.getRawX(); - float y = event.getRawY(); - if (mIsExpanded) { - if (isIntersecting(mBubbleContainer, x, y)) { - if (BubbleExperimentConfig.allowBubbleOverflow(mContext) - && isIntersecting(mBubbleOverflow.getBtn(), x, y)) { - return mBubbleOverflow.getBtn(); - } - // Could be tapping or dragging a bubble while expanded - for (int i = 0; i < getBubbleCount(); i++) { - BadgedImageView view = (BadgedImageView) mBubbleContainer.getChildAt(i); - if (isIntersecting(view, x, y)) { - return view; - } - } - } - BubbleExpandedView bev = (BubbleExpandedView) mExpandedViewContainer.getChildAt(0); - if (bev.intersectingTouchableContent((int) x, (int) y)) { - return bev; - } - // Outside of the parts we care about. - return null; - } else if (mFlyout.getVisibility() == VISIBLE && isIntersecting(mFlyout, x, y)) { - return mFlyout; - } else if (mUserEducationView != null && mUserEducationView.getVisibility() == VISIBLE) { - View bubbleChild = mBubbleContainer.getChildAt(0); - if (isIntersecting(bubbleChild, x, y)) { - return this; - } else if (isIntersecting(mUserEducationView, x, y)) { - return mUserEducationView; - } else { - return null; - } - } - - // If it wasn't an individual bubble in the expanded state, or the flyout, it's the stack. - return this; - } - - View getFlyoutView() { - return mFlyout; - } - - /** * @deprecated use {@link #setExpanded(boolean)} and * {@link BubbleData#setSelectedBubble(Bubble)} */ @@ -1385,124 +1539,74 @@ public class BubbleStackView extends FrameLayout { } } - /** Called when the collapsed stack is tapped on. */ - void onStackTapped() { - if (!maybeShowStackUserEducation()) { - mBubbleData.setExpanded(true); - } - } - - /** Called when a drag operation on an individual bubble has started. */ - public void onBubbleDragStart(View bubble) { - if (DEBUG_BUBBLE_STACK_VIEW) { - Log.d(TAG, "onBubbleDragStart: bubble=" + ((BadgedImageView) bubble).getKey()); - } - - if (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView())) { - return; - } - - mExpandedAnimationController.prepareForBubbleDrag(bubble, mMagneticTarget); - - // We're dragging an individual bubble, so set the magnetized object to the magnetized - // bubble. - mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut(); - mMagnetizedObject.setMagnetListener(mIndividualBubbleMagnetListener); - - maybeShowManageEducation(false); - } - - /** Called with the coordinates to which an individual bubble has been dragged. */ - public void onBubbleDragged(View bubble, float x, float y) { - if (!mIsExpanded || mIsExpansionAnimating - || (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView()))) { - return; - } - - mExpandedAnimationController.dragBubbleOut(bubble, x, y); - springInDismissTarget(); - } - - /** Called when a drag operation on an individual bubble has finished. */ - public void onBubbleDragFinish( - View bubble, float x, float y, float velX, float velY) { - if (DEBUG_BUBBLE_STACK_VIEW) { - Log.d(TAG, "onBubbleDragFinish: bubble=" + bubble); - } - - if (!mIsExpanded || mIsExpansionAnimating - || (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView()))) { - return; - } - - mExpandedAnimationController.snapBubbleBack(bubble, velX, velY); - hideDismissTarget(); - } - - /** Expands the clicked bubble. */ - public void expandBubble(Bubble bubble) { - if (bubble != null && bubble.equals(mBubbleData.getSelectedBubble())) { - // If the bubble we're supposed to expand is the selected bubble, that means the - // overflow bubble is currently expanded. Don't tell BubbleData to set this bubble as - // selected, since it already is. Just call the stack's setSelectedBubble to expand it. - setSelectedBubble(bubble); - } else { - mBubbleData.setSelectedBubble(bubble); - } - } - - void onDragStart() { - if (DEBUG_BUBBLE_STACK_VIEW) { - Log.d(TAG, "onDragStart()"); - } - if (mIsExpanded || mIsExpansionAnimating) { - if (DEBUG_BUBBLE_STACK_VIEW) { - Log.d(TAG, "mIsExpanded or mIsExpansionAnimating"); - } - return; + /** + * This method is called by {@link android.app.ActivityView} because the BubbleStackView has a + * higher Z-index than the ActivityView (so that dragged-out bubbles are visible over the AV). + * ActivityView is asking BubbleStackView to subtract the stack's bounds from the provided + * touchable region, so that the ActivityView doesn't consume events meant for the stack. Due to + * the special nature of ActivityView, it does not respect the standard + * {@link #dispatchTouchEvent} and {@link #onInterceptTouchEvent} methods typically used for + * this purpose. + * + * BubbleStackView is MATCH_PARENT, so that bubbles can be positioned via their translation + * properties for performance reasons. This means that the default implementation of this method + * subtracts the entirety of the screen from the ActivityView's touchable region, resulting in + * it not receiving any touch events. This was previously addressed by returning false in the + * stack's {@link View#canReceivePointerEvents()} method, but this precluded the use of any + * touch handlers in the stack or its child views. + * + * To support touch handlers, we're overriding this method to leave the ActivityView's touchable + * region alone. The only touchable part of the stack that can ever overlap the AV is a + * dragged-out bubble that is animating back into the row of bubbles. It's not worth continually + * updating the touchable region to allow users to grab a bubble while it completes its ~50ms + * animation back to the bubble row. + * + * NOTE: Any future additions to the stack that obscure the ActivityView region will need their + * bounds subtracted here in order to receive touch events. + */ + @Override + public void subtractObscuredTouchableRegion(Region touchableRegion, View view) { + // If the notification shade is expanded, we shouldn't let the ActivityView steal any touch + // events from any location. + if (mNotificationShadeWindowController.getPanelExpanded()) { + touchableRegion.setEmpty(); } - mStackAnimationController.cancelStackPositionAnimations(); - mBubbleContainer.setActiveController(mStackAnimationController); - hideFlyoutImmediate(); - - // Since we're dragging the stack, set the magnetized object to the magnetized stack. - mMagnetizedObject = mStackAnimationController.getMagnetizedStack(mMagneticTarget); - mMagnetizedObject.setMagnetListener(mStackMagnetListener); } - void onDragged(float x, float y) { - if (mIsExpanded || mIsExpansionAnimating) { - return; - } - - hideStackUserEducation(false /* fromExpansion */); - springInDismissTarget(); - mStackAnimationController.moveStackFromTouch(x, y); + /** + * If you're here because you're not receiving touch events on a view that is a descendant of + * BubbleStackView, and you think BSV is intercepting them - it's not! You need to subtract the + * bounds of the view in question in {@link #subtractObscuredTouchableRegion}. The ActivityView + * consumes all touch events within its bounds, even for views like the BubbleStackView that are + * above it. It ignores typical view touch handling methods like this one and + * dispatchTouchEvent. + */ + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return super.onInterceptTouchEvent(ev); } - void onDragFinish(float x, float y, float velX, float velY) { - if (DEBUG_BUBBLE_STACK_VIEW) { - Log.d(TAG, "onDragFinish"); - } + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + boolean dispatched = super.dispatchTouchEvent(ev); - if (mIsExpanded || mIsExpansionAnimating) { - return; + // If a new bubble arrives while the collapsed stack is being dragged, it will be positioned + // at the front of the stack (under the touch position). Subsequent ACTION_MOVE events will + // then be passed to the new bubble, which will not consume them since it hasn't received an + // ACTION_DOWN yet. Work around this by passing MotionEvents directly to the touch handler + // until the current gesture ends with an ACTION_UP event. + if (!dispatched && !mIsExpanded && mIsGestureInProgress) { + dispatched = mBubbleTouchListener.onTouch(this /* view */, ev); } - final float newStackX = mStackAnimationController.flingStackThenSpringToEdge(x, velX, velY); - logBubbleEvent(null /* no bubble associated with bubble stack move */, - SysUiStatsLog.BUBBLE_UICHANGED__ACTION__STACK_MOVED); - - mStackOnLeftOrWillBe = newStackX <= 0; - updateBubbleZOrdersAndDotPosition(true /* animate */); - hideDismissTarget(); - } + mIsGestureInProgress = + ev.getAction() != MotionEvent.ACTION_UP + && ev.getAction() != MotionEvent.ACTION_CANCEL; - void onFlyoutDragStart() { - mFlyout.removeCallbacks(mHideFlyout); + return dispatched; } - void onFlyoutDragged(float deltaX) { + void setFlyoutStateForDragLength(float deltaX) { // This shouldn't happen, but if it does, just wait until the flyout lays out. This method // is continually called. if (mFlyout.getWidth() <= 0) { @@ -1538,59 +1642,27 @@ public class BubbleStackView extends FrameLayout { mFlyout.setTranslationX(mFlyout.getRestingTranslationX() + overscrollTranslation); } - void onFlyoutTapped() { - if (maybeShowStackUserEducation()) { - // If we're showing user education, don't open the bubble show the education first - mBubbleToExpandAfterFlyoutCollapse = null; - } else { - mBubbleToExpandAfterFlyoutCollapse = mBubbleData.getSelectedBubble(); - } - - mFlyout.removeCallbacks(mHideFlyout); - mHideFlyout.run(); - } - - /** - * Called when the flyout drag has finished, and returns true if the gesture successfully - * dismissed the flyout. - */ - void onFlyoutDragFinished(float deltaX, float velX) { - final boolean onLeft = mStackAnimationController.isStackOnLeftSide(); - final boolean metRequiredVelocity = - onLeft ? velX < -FLYOUT_DISMISS_VELOCITY : velX > FLYOUT_DISMISS_VELOCITY; - final boolean metRequiredDeltaX = - onLeft - ? deltaX < -mFlyout.getWidth() * FLYOUT_DRAG_PERCENT_DISMISS - : deltaX > mFlyout.getWidth() * FLYOUT_DRAG_PERCENT_DISMISS; - final boolean isCancelFling = onLeft ? velX > 0 : velX < 0; - final boolean shouldDismiss = metRequiredVelocity || (metRequiredDeltaX && !isCancelFling); - - mFlyout.removeCallbacks(mHideFlyout); - animateFlyoutCollapsed(shouldDismiss, velX); - - maybeShowStackUserEducation(); + /** Passes the MotionEvent to the magnetized object and returns true if it was consumed. */ + private boolean passEventToMagnetizedObject(MotionEvent event) { + return mMagnetizedObject != null && mMagnetizedObject.maybeConsumeMotionEvent(event); } /** - * Called when the first touch event of a gesture (stack drag, bubble drag, flyout drag, etc.) - * is received. + * Dismisses the magnetized object - either an individual bubble, if we're expanded, or the + * stack, if we're collapsed. */ - void onGestureStart() { - mIsGestureInProgress = true; - } - - /** Called when a gesture is completed or cancelled. */ - void onGestureFinished() { - mIsGestureInProgress = false; - + private void dismissMagnetizedObject() { if (mIsExpanded) { - mExpandedAnimationController.onGestureFinished(); - } - } + final View draggedOutBubbleView = (View) mMagnetizedObject.getUnderlyingObject(); + final Bubble draggedOutBubble = mBubbleData.getBubbleWithView(draggedOutBubbleView); - /** Passes the MotionEvent to the magnetized object and returns true if it was consumed. */ - boolean passEventToMagnetizedObject(MotionEvent event) { - return mMagnetizedObject != null && mMagnetizedObject.maybeConsumeMotionEvent(event); + if (mBubbleData.hasBubbleWithKey(draggedOutBubble.getKey())) { + mBubbleData.notificationEntryRemoved( + draggedOutBubble.getEntry(), BubbleController.DISMISS_USER_GESTURE); + } + } else { + mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE); + } } /** Prepares and starts the desaturate/darken animation on the bubble stack. */ @@ -1624,7 +1696,7 @@ public class BubbleStackView extends FrameLayout { } /** Animates in the dismiss target. */ - private void springInDismissTarget() { + private void springInDismissTargetMaybe() { if (mShowingDismiss) { return; } @@ -1827,13 +1899,6 @@ public class BubbleStackView extends FrameLayout { return 0; } - private boolean isIntersecting(View view, float x, float y) { - mTempLoc = view.getLocationOnScreen(); - mTempRect.set(mTempLoc[0], mTempLoc[1], mTempLoc[0] + view.getWidth(), - mTempLoc[1] + view.getHeight()); - return mTempRect.contains(x, y); - } - private void requestUpdate() { if (mViewUpdatedRequested || mIsExpansionAnimating) { return; @@ -1848,7 +1913,8 @@ public class BubbleStackView extends FrameLayout { Log.d(TAG, "updateExpandedBubble()"); } mExpandedViewContainer.removeAllViews(); - if (mIsExpanded && mExpandedBubble != null) { + if (mIsExpanded && mExpandedBubble != null + && mExpandedBubble.getExpandedView() != null) { BubbleExpandedView bev = mExpandedBubble.getExpandedView(); mExpandedViewContainer.addView(bev); bev.populateExpandedView(); @@ -1868,7 +1934,7 @@ public class BubbleStackView extends FrameLayout { if (!mExpandedViewYAnim.isRunning()) { // We're not animating so set the value mExpandedViewContainer.setTranslationY(y); - if (mExpandedBubble != null) { + if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) { mExpandedBubble.getExpandedView().updateView(); } } else { @@ -1906,7 +1972,7 @@ public class BubbleStackView extends FrameLayout { } private void updatePointerPosition() { - if (mExpandedBubble == null) { + if (mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) { return; } int index = getBubbleIndex(mExpandedBubble); @@ -1988,7 +2054,7 @@ public class BubbleStackView extends FrameLayout { * a back key down/up event pair is forwarded to the bubble Activity. */ boolean performBackPressIfNeeded() { - if (!isExpanded() || mExpandedBubble == null) { + if (!isExpanded() || mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) { return false; } return mExpandedBubble.getExpandedView().performBackPressIfNeeded(); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java deleted file mode 100644 index 132c45fab3d2..000000000000 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.bubbles; - -import android.content.Context; -import android.graphics.PointF; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import android.view.ViewConfiguration; - -import com.android.systemui.Dependency; - -/** - * Handles interpreting touches on a {@link BubbleStackView}. This includes expanding, collapsing, - * dismissing, and flings. - */ -class BubbleTouchHandler implements View.OnTouchListener { - - private final PointF mTouchDown = new PointF(); - private final PointF mViewPositionOnTouchDown = new PointF(); - private final BubbleStackView mStack; - private final BubbleData mBubbleData; - - private BubbleController mController = Dependency.get(BubbleController.class); - - private boolean mMovedEnough; - private int mTouchSlopSquared; - private VelocityTracker mVelocityTracker; - - /** View that was initially touched, when we received the first ACTION_DOWN event. */ - private View mTouchedView; - - BubbleTouchHandler(BubbleStackView stackView, - BubbleData bubbleData, Context context) { - final int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); - mTouchSlopSquared = touchSlop * touchSlop; - mBubbleData = bubbleData; - mStack = stackView; - } - - @Override - public boolean onTouch(View v, MotionEvent event) { - final int action = event.getActionMasked(); - - // If we aren't currently in the process of touching a view, figure out what we're touching. - // It'll be the stack, an individual bubble, or nothing. - if (mTouchedView == null) { - mTouchedView = mStack.getTargetView(event); - } - - // If this is an ACTION_OUTSIDE event, or the stack reported that we aren't touching - // anything, collapse the stack. - if (action == MotionEvent.ACTION_OUTSIDE || mTouchedView == null) { - mBubbleData.setExpanded(false); - mStack.hideStackUserEducation(false /* fromExpansion */); - resetForNextGesture(); - return false; - } - - if (!(mTouchedView instanceof BadgedImageView) - && !(mTouchedView instanceof BubbleStackView) - && !(mTouchedView instanceof BubbleFlyoutView)) { - - // Not touching anything touchable, but we shouldn't collapse (e.g. touching edge - // of expanded view). - mStack.maybeShowManageEducation(false); - resetForNextGesture(); - return false; - } - - final boolean isStack = mStack.equals(mTouchedView); - final boolean isFlyout = mStack.getFlyoutView().equals(mTouchedView); - final float rawX = event.getRawX(); - final float rawY = event.getRawY(); - - // The coordinates of the touch event, in terms of the touched view's position. - final float viewX = mViewPositionOnTouchDown.x + rawX - mTouchDown.x; - final float viewY = mViewPositionOnTouchDown.y + rawY - mTouchDown.y; - switch (action) { - case MotionEvent.ACTION_DOWN: - trackMovement(event); - - mTouchDown.set(rawX, rawY); - mStack.onGestureStart(); - - if (isStack) { - mViewPositionOnTouchDown.set(mStack.getStackPosition()); - - // Dismiss the entire stack if it's released in the dismiss target. - mStack.setReleasedInDismissTargetAction( - () -> mController.dismissStack(BubbleController.DISMISS_USER_GESTURE)); - mStack.onDragStart(); - mStack.passEventToMagnetizedObject(event); - } else if (isFlyout) { - mStack.onFlyoutDragStart(); - } else { - mViewPositionOnTouchDown.set( - mTouchedView.getTranslationX(), mTouchedView.getTranslationY()); - - // Dismiss only the dragged-out bubble if it's released in the target. - final String individualBubbleKey = ((BadgedImageView) mTouchedView).getKey(); - mStack.setReleasedInDismissTargetAction(() -> { - final Bubble bubble = - mBubbleData.getBubbleWithKey(individualBubbleKey); - // bubble can be null if the user is in the middle of - // dismissing the bubble, but the app also sent a cancel - if (bubble != null) { - mController.removeBubble(bubble.getEntry(), - BubbleController.DISMISS_USER_GESTURE); - } - }); - - mStack.onBubbleDragStart(mTouchedView); - mStack.passEventToMagnetizedObject(event); - } - - break; - case MotionEvent.ACTION_MOVE: - trackMovement(event); - final float deltaX = rawX - mTouchDown.x; - final float deltaY = rawY - mTouchDown.y; - - if ((deltaX * deltaX) + (deltaY * deltaY) > mTouchSlopSquared && !mMovedEnough) { - mMovedEnough = true; - } - - if (mMovedEnough) { - if (isFlyout) { - mStack.onFlyoutDragged(deltaX); - } else if (!mStack.passEventToMagnetizedObject(event)) { - // If the magnetic target doesn't consume the event, drag the stack or - // bubble. - if (isStack) { - mStack.onDragged(viewX, viewY); - } else { - mStack.onBubbleDragged(mTouchedView, viewX, viewY); - } - } - } - break; - - case MotionEvent.ACTION_CANCEL: - resetForNextGesture(); - break; - - case MotionEvent.ACTION_UP: - trackMovement(event); - mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000); - final float velX = mVelocityTracker.getXVelocity(); - final float velY = mVelocityTracker.getYVelocity(); - - if (isFlyout && mMovedEnough) { - mStack.onFlyoutDragFinished(rawX - mTouchDown.x /* deltaX */, velX); - } else if (isFlyout) { - if (!mBubbleData.isExpanded() && !mMovedEnough) { - mStack.onFlyoutTapped(); - } - } else if (mMovedEnough) { - if (!mStack.passEventToMagnetizedObject(event)) { - // If the magnetic target didn't consume the event, tell the stack to finish - // the drag. - if (isStack) { - mStack.onDragFinish(viewX, viewY, velX, velY); - } else { - mStack.onBubbleDragFinish(mTouchedView, viewX, viewY, velX, velY); - } - } - } else if (mTouchedView == mStack.getExpandedBubbleView()) { - mBubbleData.setExpanded(false); - } else if (isStack) { - mStack.onStackTapped(); - } else { - final String key = ((BadgedImageView) mTouchedView).getKey(); - if (key == BubbleOverflow.KEY) { - mStack.showOverflow(); - } else { - mStack.expandBubble(mBubbleData.getBubbleWithKey(key)); - } - } - resetForNextGesture(); - break; - } - - return true; - } - - /** Clears all touch-related state. */ - private void resetForNextGesture() { - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - - mTouchedView = null; - mMovedEnough = false; - - mStack.onGestureFinished(); - } - - private void trackMovement(MotionEvent event) { - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - mVelocityTracker.addMovement(event); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java index a0b49384d49f..d974adc34ee0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java @@ -252,8 +252,14 @@ public class ExpandedAnimationController mSpringToTouchOnNextMotionEvent = true; } - /** Prepares the given bubble to be dragged out. */ - public void prepareForBubbleDrag(View bubble, MagnetizedObject.MagneticTarget target) { + /** + * Prepares the given bubble view to be dragged out, using the provided magnetic target and + * listener. + */ + public void prepareForBubbleDrag( + View bubble, + MagnetizedObject.MagneticTarget target, + MagnetizedObject.MagnetListener listener) { mLayout.cancelAnimationsOnView(bubble); bubble.setTranslationZ(Short.MAX_VALUE); @@ -277,6 +283,7 @@ public class ExpandedAnimationController } }; mMagnetizedBubbleDraggingOut.addTarget(target); + mMagnetizedBubbleDraggingOut.setMagnetListener(listener); mMagnetizedBubbleDraggingOut.setHapticsEnabled(true); mMagnetizedBubbleDraggingOut.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java index c292769f1066..b1bbafc1ed8f 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java @@ -1117,9 +1117,4 @@ public class PhysicsAnimationLayout extends FrameLayout { mAssociatedController = controller; } } - - @Override - protected boolean canReceivePointerEvents() { - return false; - } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java index e84e932c9e61..72d646e0554d 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java @@ -16,6 +16,7 @@ package com.android.systemui.bubbles.dagger; +import android.app.INotificationManager; import android.content.Context; import com.android.systemui.bubbles.BubbleController; @@ -64,14 +65,15 @@ public interface BubbleModule { FeatureFlags featureFlags, DumpManager dumpManager, FloatingContentCoordinator floatingContentCoordinator, - SysUiState sysUiState) { + SysUiState sysUiState, + INotificationManager notifManager) { return new BubbleController( context, notificationShadeWindowController, statusBarStateController, shadeController, data, - /* synchronizer */null, + null /* synchronizer */, configurationController, interruptionStateProvider, zenModeController, @@ -82,6 +84,7 @@ public interface BubbleModule { featureFlags, dumpManager, floatingContentCoordinator, - sysUiState); + sysUiState, + notifManager); } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt index dec60073a55e..5891a7f705c8 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt @@ -18,10 +18,34 @@ package com.android.systemui.controls import android.content.ComponentName import android.service.controls.Control +import android.service.controls.DeviceTypes + +interface ControlInterface { + val favorite: Boolean + val component: ComponentName + val controlId: String + val title: CharSequence + val subtitle: CharSequence + val removed: Boolean + get() = false + @DeviceTypes.DeviceType val deviceType: Int +} data class ControlStatus( val control: Control, - val component: ComponentName, - var favorite: Boolean, - val removed: Boolean = false -) + override val component: ComponentName, + override var favorite: Boolean, + override val removed: Boolean = false +) : ControlInterface { + override val controlId: String + get() = control.controlId + + override val title: CharSequence + get() = control.title + + override val subtitle: CharSequence + get() = control.subtitle + + @DeviceTypes.DeviceType override val deviceType: Int + get() = control.deviceType +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt index 6e59ac162657..40606c2689e5 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt @@ -16,6 +16,7 @@ package com.android.systemui.controls.controller +import android.service.controls.Control import android.service.controls.DeviceTypes /** @@ -39,6 +40,14 @@ data class ControlInfo( companion object { private const val SEPARATOR = ":" + fun fromControl(control: Control): ControlInfo { + return ControlInfo( + control.controlId, + control.title, + control.subtitle, + control.deviceType + ) + } } /** @@ -49,13 +58,4 @@ data class ControlInfo( override fun toString(): String { return "$SEPARATOR$controlId$SEPARATOR$controlTitle$SEPARATOR$deviceType" } - - class Builder { - lateinit var controlId: String - lateinit var controlTitle: CharSequence - lateinit var controlSubtitle: CharSequence - var deviceType: Int = DeviceTypes.TYPE_UNKNOWN - - fun build() = ControlInfo(controlId, controlTitle, controlSubtitle, deviceType) - } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt index 5d03fc51004d..7e8fec716b1f 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt @@ -45,7 +45,7 @@ open class ControlsBindingControllerImpl @Inject constructor( companion object { private const val TAG = "ControlsBindingControllerImpl" private const val MAX_CONTROLS_REQUEST = 100000L - private const val SUGGESTED_CONTROLS_REQUEST = 4L + private const val SUGGESTED_CONTROLS_REQUEST = 6L } private var currentUser = UserHandle.of(ActivityManager.getCurrentUser()) @@ -61,6 +61,11 @@ open class ControlsBindingControllerImpl @Inject constructor( */ private var statefulControlSubscriber: StatefulControlSubscriber? = null + /* + * Will track any active load subscriber. Only one can be active at any time. + */ + private var loadSubscriber: LoadSubscriber? = null + private val actionCallbackService = object : IControlsActionCallback.Stub() { override fun accept( token: IBinder, @@ -99,17 +104,24 @@ open class ControlsBindingControllerImpl @Inject constructor( component: ComponentName, callback: ControlsBindingController.LoadCallback ): Runnable { - val subscriber = LoadSubscriber(callback, MAX_CONTROLS_REQUEST) - retrieveLifecycleManager(component).maybeBindAndLoad(subscriber) - return subscriber.loadCancel() + loadSubscriber?.loadCancel() + + val ls = LoadSubscriber(callback, MAX_CONTROLS_REQUEST) + loadSubscriber = ls + + retrieveLifecycleManager(component).maybeBindAndLoad(ls) + return ls.loadCancel() } override fun bindAndLoadSuggested( component: ComponentName, callback: ControlsBindingController.LoadCallback ) { - val subscriber = LoadSubscriber(callback, SUGGESTED_CONTROLS_REQUEST) - retrieveLifecycleManager(component).maybeBindAndLoadSuggested(subscriber) + loadSubscriber?.loadCancel() + val ls = LoadSubscriber(callback, SUGGESTED_CONTROLS_REQUEST) + loadSubscriber = ls + + retrieveLifecycleManager(component).maybeBindAndLoadSuggested(ls) } override fun subscribe(structureInfo: StructureInfo) { @@ -152,13 +164,16 @@ open class ControlsBindingControllerImpl @Inject constructor( override fun changeUser(newUser: UserHandle) { if (newUser == currentUser) return - unsubscribe() unbind() - currentProvider = null currentUser = newUser } private fun unbind() { + unsubscribe() + + loadSubscriber?.loadCancel() + loadSubscriber = null + currentProvider?.unbindService() currentProvider = null } @@ -210,6 +225,20 @@ open class ControlsBindingControllerImpl @Inject constructor( val callback: ControlsBindingController.LoadCallback ) : CallbackRunnable(token) { override fun doRun() { + Log.d(TAG, "LoadSubscription: Complete and loading controls") + callback.accept(list) + } + } + + private inner class OnCancelAndLoadRunnable( + token: IBinder, + val list: List<Control>, + val subscription: IControlsSubscription, + val callback: ControlsBindingController.LoadCallback + ) : CallbackRunnable(token) { + override fun doRun() { + Log.d(TAG, "LoadSubscription: Canceling and loading controls") + provider?.cancelSubscription(subscription) callback.accept(list) } } @@ -220,6 +249,7 @@ open class ControlsBindingControllerImpl @Inject constructor( val requestLimit: Long ) : CallbackRunnable(token) { override fun doRun() { + Log.d(TAG, "LoadSubscription: Starting subscription") provider?.startSubscription(subscription, requestLimit) } } @@ -254,34 +284,54 @@ open class ControlsBindingControllerImpl @Inject constructor( val requestLimit: Long ) : IControlsSubscriber.Stub() { val loadedControls = ArrayList<Control>() - var hasError = false + private var isTerminated = false private var _loadCancelInternal: (() -> Unit)? = null + private lateinit var subscription: IControlsSubscription + fun loadCancel() = Runnable { - Log.d(TAG, "Cancel load requested") - _loadCancelInternal?.invoke() - } + Log.d(TAG, "Cancel load requested") + _loadCancelInternal?.invoke() + } override fun onSubscribe(token: IBinder, subs: IControlsSubscription) { - _loadCancelInternal = subs::cancel + subscription = subs + _loadCancelInternal = { currentProvider?.cancelSubscription(subscription) } backgroundExecutor.execute(OnSubscribeRunnable(token, subs, requestLimit)) } override fun onNext(token: IBinder, c: Control) { - backgroundExecutor.execute { loadedControls.add(c) } + backgroundExecutor.execute { + if (isTerminated) return@execute + + loadedControls.add(c) + + // Once we have reached our requestLimit, send a request to cancel, and immediately + // load the results. Calls to onError() and onComplete() are not required after + // cancel. + if (loadedControls.size >= requestLimit) { + maybeTerminateAndRun( + OnCancelAndLoadRunnable(token, loadedControls, subscription, callback) + ) + } + } } + override fun onError(token: IBinder, s: String) { - hasError = true - _loadCancelInternal = {} - currentProvider?.cancelLoadTimeout() - backgroundExecutor.execute(OnLoadErrorRunnable(token, s, callback)) + maybeTerminateAndRun(OnLoadErrorRunnable(token, s, callback)) } override fun onComplete(token: IBinder) { + maybeTerminateAndRun(OnLoadRunnable(token, loadedControls, callback)) + } + + private fun maybeTerminateAndRun(postTerminateFn: Runnable) { + if (isTerminated) return + + isTerminated = true _loadCancelInternal = {} - if (!hasError) { - currentProvider?.cancelLoadTimeout() - backgroundExecutor.execute(OnLoadRunnable(token, loadedControls, callback)) - } + currentProvider?.cancelLoadTimeout() + + backgroundExecutor.execute(postTerminateFn) } } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt index ae75dd4d94ab..7cab847d52f7 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt @@ -148,6 +148,18 @@ interface ControlsController : UserAwareController { fun getFavoritesForComponent(componentName: ComponentName): List<StructureInfo> /** + * Get all the favorites for a given structure. + * + * @param componentName the name of the service that provides the [Control] + * @param structureName the name of the structure + * @return a list of the current favorites in that structure + */ + fun getFavoritesForStructure( + componentName: ComponentName, + structureName: CharSequence + ): List<ControlInfo> + + /** * Adds a single favorite to a given component and structure * @param componentName the name of the service that provides the [Control] * @param structureName the name of the structure that holds the [Control] @@ -180,6 +192,11 @@ interface ControlsController : UserAwareController { fun countFavoritesForComponent(componentName: ComponentName): Int /** + * TEMPORARY for testing + */ + fun resetFavorites() + + /** * Interface for structure to pass data to [ControlsFavoritingActivity]. */ interface LoadData { diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt index 34833396acef..6d34009169d5 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt @@ -365,6 +365,8 @@ class ControlsControllerImpl @Inject constructor ( componentName: ComponentName, callback: Consumer<Boolean> ) { + if (seedingInProgress) return + Log.i(TAG, "Beginning request to seed favorites for: $componentName") if (!confirmAvailability()) { if (userChanging) { @@ -495,6 +497,13 @@ class ControlsControllerImpl @Inject constructor ( } } + override fun resetFavorites() { + executor.execute { + Favorites.clear() + persistenceWrapper.storeFavorites(Favorites.getAllStructures()) + } + } + override fun refreshStatus(componentName: ComponentName, control: Control) { if (!confirmAvailability()) { Log.d(TAG, "Controls not available") @@ -535,6 +544,15 @@ class ControlsControllerImpl @Inject constructor ( override fun getFavoritesForComponent(componentName: ComponentName): List<StructureInfo> = Favorites.getStructuresForComponent(componentName) + override fun getFavoritesForStructure( + componentName: ComponentName, + structureName: CharSequence + ): List<ControlInfo> { + return Favorites.getControlsForStructure( + StructureInfo(componentName, structureName, emptyList()) + ) + } + override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { pw.println("ControlsController state:") pw.println(" Available: $available") diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt index 895f1d218982..a6af6a11d8b7 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt @@ -63,8 +63,6 @@ class ControlsProviderLifecycleManager( ) : IBinder.DeathRecipient { val token: IBinder = Binder() - @GuardedBy("subscriptions") - private val subscriptions = mutableListOf<IControlsSubscription>() private var requiresBound = false @GuardedBy("queuedServiceMethods") private val queuedServiceMethods: MutableSet<ServiceMethod> = ArraySet() @@ -194,7 +192,7 @@ class ControlsProviderLifecycleManager( * Request a call to [IControlsProvider.loadSuggested]. * * If the service is not bound, the call will be queued and the service will be bound first. - * The service will be unbound after the controls are returned or the call times out. + * The service will be unbound if the call times out. * * @param subscriber the subscriber that manages coordination for loading controls */ @@ -245,9 +243,7 @@ class ControlsProviderLifecycleManager( if (DEBUG) { Log.d(TAG, "startSubscription: $subscription") } - synchronized(subscriptions) { - subscriptions.add(subscription) - } + wrapper?.request(subscription, requestLimit) } @@ -261,9 +257,7 @@ class ControlsProviderLifecycleManager( if (DEBUG) { Log.d(TAG, "cancelSubscription: $subscription") } - synchronized(subscriptions) { - subscriptions.remove(subscription) - } + wrapper?.cancel(subscription) } @@ -281,17 +275,6 @@ class ControlsProviderLifecycleManager( onLoadCanceller?.run() onLoadCanceller = null - // be sure to cancel all subscriptions - val subs = synchronized(subscriptions) { - ArrayList(subscriptions).also { - subscriptions.clear() - } - } - - subs.forEach { - wrapper?.cancel(it) - } - bindService(false) } diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt index 946a2365585a..3bed55912332 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt @@ -22,6 +22,7 @@ import com.android.systemui.controls.controller.ControlsBindingControllerImpl import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.controller.ControlsControllerImpl import com.android.systemui.controls.controller.ControlsFavoritePersistenceWrapper +import com.android.systemui.controls.management.ControlsEditingActivity import com.android.systemui.controls.management.ControlsFavoritingActivity import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsListingControllerImpl @@ -73,6 +74,13 @@ abstract class ControlsModule { @Binds @IntoMap + @ClassKey(ControlsEditingActivity::class) + abstract fun provideControlsEditingActivity( + activity: ControlsEditingActivity + ): Activity + + @Binds + @IntoMap @ClassKey(ControlsRequestDialog::class) abstract fun provideControlsRequestDialog( activity: ControlsRequestDialog diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt index 11181e56838e..175ed061c714 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt @@ -37,23 +37,22 @@ import com.android.systemui.controls.controller.ControlInfo * @property controls List of controls as returned by loading * @property initialFavoriteIds sorted ids of favorite controls. * @property noZoneString text to use as header for all controls that have blank or `null` zone. + * @property controlsModelCallback callback to notify that favorites have changed for the first time */ class AllModel( private val controls: List<ControlStatus>, initialFavoriteIds: List<String>, - private val emptyZoneString: CharSequence + private val emptyZoneString: CharSequence, + private val controlsModelCallback: ControlsModel.ControlsModelCallback ) : ControlsModel { - override val favorites: List<ControlInfo.Builder> + private var modified = false + + override val favorites: List<ControlInfo> get() = favoriteIds.mapNotNull { id -> val control = controls.firstOrNull { it.control.controlId == id }?.control control?.let { - ControlInfo.Builder().apply { - controlId = it.controlId - controlTitle = it.title - controlSubtitle = it.subtitle - deviceType = it.deviceType - } + ControlInfo.fromControl(it) } } @@ -66,14 +65,18 @@ class AllModel( override fun changeFavoriteStatus(controlId: String, favorite: Boolean) { val toChange = elements.firstOrNull { - it is ControlWrapper && it.controlStatus.control.controlId == controlId - } as ControlWrapper? + it is ControlStatusWrapper && it.controlStatus.control.controlId == controlId + } as ControlStatusWrapper? if (favorite == toChange?.controlStatus?.favorite) return - if (favorite) { + val changed: Boolean = if (favorite) { favoriteIds.add(controlId) } else { favoriteIds.remove(controlId) } + if (changed && !modified) { + modified = true + controlsModelCallback.onFirstChange() + } toChange?.let { it.controlStatus.favorite = favorite } @@ -84,9 +87,9 @@ class AllModel( it.control.zone ?: "" } val output = mutableListOf<ElementWrapper>() - var emptyZoneValues: Sequence<ControlWrapper>? = null + var emptyZoneValues: Sequence<ControlStatusWrapper>? = null for (zoneName in map.orderedKeys) { - val values = map.getValue(zoneName).asSequence().map { ControlWrapper(it) } + val values = map.getValue(zoneName).asSequence().map { ControlStatusWrapper(it) } if (TextUtils.isEmpty(zoneName)) { emptyZoneValues = values } else { diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt index 1291dd98932e..03ca3931e68c 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt @@ -28,6 +28,7 @@ import android.widget.TextView import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.android.systemui.R +import com.android.systemui.controls.ControlInterface import com.android.systemui.controls.ui.RenderInfo private typealias ModelFavoriteChanger = (String, Boolean) -> Unit @@ -35,11 +36,10 @@ private typealias ModelFavoriteChanger = (String, Boolean) -> Unit /** * Adapter for binding [Control] information to views. * - * The model for this adapter is provided by a [FavoriteModel] that is set using + * The model for this adapter is provided by a [ControlModel] that is set using * [changeFavoritesModel]. This allows for updating the model if there's a reload. * - * @param layoutInflater an inflater for the views in the containing [RecyclerView] - * @param onlyFavorites set to true to only display favorites instead of all controls + * @property elevation elevation of each control view */ class ControlAdapter( private val elevation: Float @@ -48,11 +48,12 @@ class ControlAdapter( companion object { private const val TYPE_ZONE = 0 private const val TYPE_CONTROL = 1 + private const val TYPE_DIVIDER = 2 } val spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { - return if (getItemViewType(position) == TYPE_ZONE) 2 else 1 + return if (getItemViewType(position) != TYPE_CONTROL) 2 else 1 } } @@ -78,6 +79,10 @@ class ControlAdapter( TYPE_ZONE -> { ZoneHolder(layoutInflater.inflate(R.layout.controls_zone_header, parent, false)) } + TYPE_DIVIDER -> { + DividerHolder(layoutInflater.inflate( + R.layout.controls_horizontal_divider_with_empty, parent, false)) + } else -> throw IllegalStateException("Wrong viewType: $viewType") } } @@ -95,11 +100,26 @@ class ControlAdapter( } } + override fun onBindViewHolder(holder: Holder, position: Int, payloads: MutableList<Any>) { + if (payloads.isEmpty()) { + super.onBindViewHolder(holder, position, payloads) + } else { + model?.let { + val el = it.elements[position] + if (el is ControlInterface) { + holder.updateFavorite(el.favorite) + } + } + } + } + override fun getItemViewType(position: Int): Int { model?.let { return when (it.elements.get(position)) { is ZoneNameWrapper -> TYPE_ZONE - is ControlWrapper -> TYPE_CONTROL + is ControlStatusWrapper -> TYPE_CONTROL + is ControlInfoWrapper -> TYPE_CONTROL + is DividerWrapper -> TYPE_DIVIDER } } ?: throw IllegalStateException("Getting item type for null model") } @@ -115,6 +135,24 @@ sealed class Holder(view: View) : RecyclerView.ViewHolder(view) { * Bind the data from the model into the view */ abstract fun bindData(wrapper: ElementWrapper) + + open fun updateFavorite(favorite: Boolean) {} +} + +/** + * Holder for using with [DividerWrapper] to display a divider between zones. + * + * The divider can be shown or hidden. It also has a frame view the height of a control, that can + * be toggled visible or gone. + */ +private class DividerHolder(view: View) : Holder(view) { + private val frame: View = itemView.requireViewById(R.id.frame) + private val divider: View = itemView.requireViewById(R.id.divider) + override fun bindData(wrapper: ElementWrapper) { + wrapper as DividerWrapper + frame.visibility = if (wrapper.showNone) View.VISIBLE else View.GONE + divider.visibility = if (wrapper.showDivider) View.VISIBLE else View.GONE + } } /** @@ -130,11 +168,14 @@ private class ZoneHolder(view: View) : Holder(view) { } /** - * Holder for using with [ControlWrapper] to display names of zones. + * Holder for using with [ControlStatusWrapper] to display names of zones. * @param favoriteCallback this callback will be called whenever the favorite state of the * [Control] this view represents changes. */ -private class ControlHolder(view: View, val favoriteCallback: ModelFavoriteChanger) : Holder(view) { +internal class ControlHolder( + view: View, + val favoriteCallback: ModelFavoriteChanger +) : Holder(view) { private val icon: ImageView = itemView.requireViewById(R.id.icon) private val title: TextView = itemView.requireViewById(R.id.title) private val subtitle: TextView = itemView.requireViewById(R.id.subtitle) @@ -144,20 +185,23 @@ private class ControlHolder(view: View, val favoriteCallback: ModelFavoriteChang } override fun bindData(wrapper: ElementWrapper) { - wrapper as ControlWrapper - val data = wrapper.controlStatus - val renderInfo = getRenderInfo(data.component, data.control.deviceType) - title.text = data.control.title - subtitle.text = data.control.subtitle - favorite.isChecked = data.favorite - removed.text = if (data.removed) "Removed" else "" + wrapper as ControlInterface + val renderInfo = getRenderInfo(wrapper.component, wrapper.deviceType) + title.text = wrapper.title + subtitle.text = wrapper.subtitle + favorite.isChecked = wrapper.favorite + removed.text = if (wrapper.removed) "Removed" else "" itemView.setOnClickListener { favorite.isChecked = !favorite.isChecked - favoriteCallback(data.control.controlId, favorite.isChecked) + favoriteCallback(wrapper.controlId, favorite.isChecked) } applyRenderInfo(renderInfo) } + override fun updateFavorite(favorite: Boolean) { + this.favorite.isChecked = favorite + } + private fun getRenderInfo( component: ComponentName, @DeviceTypes.DeviceType deviceType: Int diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt new file mode 100644 index 000000000000..ee1ce7ab3d83 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt @@ -0,0 +1,176 @@ +/* + * 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.controls.management + +import android.app.Activity +import android.content.ComponentName +import android.content.Intent +import android.os.Bundle +import android.view.View +import android.view.ViewStub +import android.widget.Button +import android.widget.TextView +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import com.android.systemui.R +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.controls.controller.ControlsControllerImpl +import com.android.systemui.controls.controller.StructureInfo +import com.android.systemui.settings.CurrentUserTracker +import javax.inject.Inject + +/** + * Activity for rearranging and removing controls for a given structure + */ +class ControlsEditingActivity @Inject constructor( + private val controller: ControlsControllerImpl, + broadcastDispatcher: BroadcastDispatcher +) : Activity() { + + companion object { + private const val TAG = "ControlsEditingActivity" + private const val EXTRA_STRUCTURE = ControlsFavoritingActivity.EXTRA_STRUCTURE + private val SUBTITLE_ID = R.string.controls_favorite_rearrange + private val EMPTY_TEXT_ID = R.string.controls_favorite_removed + } + + private lateinit var component: ComponentName + private lateinit var structure: CharSequence + private lateinit var model: FavoritesModel + private lateinit var subtitle: TextView + private lateinit var saveButton: View + + private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) { + private val startingUser = controller.currentUserId + + override fun onUserSwitched(newUserId: Int) { + if (newUserId != startingUser) { + stopTracking() + finish() + } + } + } + + override fun onBackPressed() { + finish() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)?.let { + component = it + } ?: run(this::finish) + + intent.getCharSequenceExtra(EXTRA_STRUCTURE)?.let { + structure = it + } ?: run(this::finish) + + bindViews() + + bindButtons() + + setUpList() + + currentUserTracker.startTracking() + } + + private fun bindViews() { + setContentView(R.layout.controls_management) + requireViewById<ViewStub>(R.id.stub).apply { + layoutResource = R.layout.controls_management_editing + inflate() + } + requireViewById<TextView>(R.id.title).text = structure + subtitle = requireViewById<TextView>(R.id.subtitle).apply { + setText(SUBTITLE_ID) + } + } + + private fun bindButtons() { + requireViewById<Button>(R.id.other_apps).apply { + visibility = View.VISIBLE + setText(R.string.controls_menu_add) + setOnClickListener { + saveFavorites() + val intent = Intent(this@ControlsEditingActivity, + ControlsFavoritingActivity::class.java).apply { + putExtras(this@ControlsEditingActivity.intent) + putExtra(ControlsFavoritingActivity.EXTRA_SINGLE_STRUCTURE, true) + } + startActivity(intent) + finish() + } + } + + saveButton = requireViewById<Button>(R.id.done).apply { + isEnabled = false + setText(R.string.save) + setOnClickListener { + saveFavorites() + finishAffinity() + } + } + } + + private fun saveFavorites() { + controller.replaceFavoritesForStructure( + StructureInfo(component, structure, model.favorites)) + } + + private val favoritesModelCallback = object : FavoritesModel.FavoritesModelCallback { + override fun onNoneChanged(showNoFavorites: Boolean) { + if (showNoFavorites) { + subtitle.setText(EMPTY_TEXT_ID) + } else { + subtitle.setText(SUBTITLE_ID) + } + } + + override fun onFirstChange() { + saveButton.isEnabled = true + } + } + + private fun setUpList() { + val controls = controller.getFavoritesForStructure(component, structure) + model = FavoritesModel(component, controls, favoritesModelCallback) + val elevation = resources.getFloat(R.dimen.control_card_elevation) + val adapter = ControlAdapter(elevation) + val recycler = requireViewById<RecyclerView>(R.id.list) + val margin = resources + .getDimensionPixelSize(R.dimen.controls_card_margin) + val itemDecorator = MarginItemDecorator(margin, margin) + + recycler.apply { + this.adapter = adapter + layoutManager = GridLayoutManager(recycler.context, 2).apply { + spanSizeLookup = adapter.spanSizeLookup + } + addItemDecoration(itemDecorator) + } + adapter.changeModel(model) + model.attachAdapter(adapter) + ItemTouchHelper(model.itemTouchHelperCallback).attachToRecyclerView(recycler) + } + + override fun onDestroy() { + currentUserTracker.stopTracking() + super.onDestroy() + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt index f2303e622f8d..6f34deeb8547 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt @@ -55,13 +55,20 @@ class ControlsFavoritingActivity @Inject constructor( companion object { private const val TAG = "ControlsFavoritingActivity" + + // If provided and no structure is available, use as the title const val EXTRA_APP = "extra_app_label" + + // If provided, show this structure page first + const val EXTRA_STRUCTURE = "extra_structure" + const val EXTRA_SINGLE_STRUCTURE = "extra_single_structure" private const val TOOLTIP_PREFS_KEY = Prefs.Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT private const val TOOLTIP_MAX_SHOWN = 2 } private var component: ComponentName? = null private var appName: CharSequence? = null + private var structureExtra: CharSequence? = null private lateinit var structurePager: ViewPager2 private lateinit var statusText: TextView @@ -111,6 +118,7 @@ class ControlsFavoritingActivity @Inject constructor( val collator = Collator.getInstance(resources.configuration.locales[0]) comparator = compareBy(collator) { it.structureName } appName = intent.getCharSequenceExtra(EXTRA_APP) + structureExtra = intent.getCharSequenceExtra(EXTRA_STRUCTURE) ?: "" component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME) bindViews() @@ -124,6 +132,12 @@ class ControlsFavoritingActivity @Inject constructor( currentUserTracker.startTracking() } + private val controlsModelCallback = object : ControlsModel.ControlsModelCallback { + override fun onFirstChange() { + doneButton.isEnabled = true + } + } + private fun loadControls() { component?.let { statusText.text = resources.getText(com.android.internal.R.string.loading) @@ -135,11 +149,22 @@ class ControlsFavoritingActivity @Inject constructor( val error = data.errorOnLoad val controlsByStructure = allControls.groupBy { it.control.structure ?: "" } listOfStructures = controlsByStructure.map { - StructureContainer(it.key, AllModel(it.value, favoriteKeys, emptyZoneString)) + StructureContainer(it.key, AllModel( + it.value, favoriteKeys, emptyZoneString, controlsModelCallback)) }.sortedWith(comparator) + + val structureIndex = listOfStructures.indexOfFirst { + sc -> sc.structureName == structureExtra + }.let { if (it == -1) 0 else it } + + // If we were requested to show a single structure, set the list to just that one + if (intent.getBooleanExtra(EXTRA_SINGLE_STRUCTURE, false)) { + listOfStructures = listOf(listOfStructures[structureIndex]) + } + executor.execute { - doneButton.isEnabled = true structurePager.adapter = StructureAdapter(listOfStructures) + structurePager.setCurrentItem(structureIndex) if (error) { statusText.text = resources.getText(R.string.controls_favorite_load_error) } else { @@ -226,8 +251,11 @@ class ControlsFavoritingActivity @Inject constructor( } } + val title = structureExtra + ?: (appName ?: resources.getText(R.string.controls_favorite_default_title)) + setTitle(title) titleView = requireViewById<TextView>(R.id.title).apply { - text = appName ?: resources.getText(R.string.controls_favorite_default_title) + text = title } requireViewById<TextView>(R.id.subtitle).text = resources.getText(R.string.controls_favorite_subtitle) @@ -247,7 +275,10 @@ class ControlsFavoritingActivity @Inject constructor( requireViewById<Button>(R.id.other_apps).apply { visibility = View.VISIBLE setOnClickListener { - this@ControlsFavoritingActivity.onBackPressed() + val i = Intent() + i.setComponent( + ComponentName(context, ControlsProviderSelectorActivity::class.java)) + context.startActivity(i) } } @@ -256,7 +287,7 @@ class ControlsFavoritingActivity @Inject constructor( setOnClickListener { if (component == null) return@setOnClickListener listOfStructures.forEach { - val favoritesForStorage = it.model.favorites.map { it.build() } + val favoritesForStorage = it.model.favorites controller.replaceFavoritesForStructure( StructureInfo(component!!, it.structureName, favoritesForStorage) ) diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt index a995a2ebfd25..37b6d15c0afe 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt @@ -16,6 +16,9 @@ package com.android.systemui.controls.management +import android.content.ComponentName +import androidx.recyclerview.widget.RecyclerView +import com.android.systemui.controls.ControlInterface import com.android.systemui.controls.ControlStatus import com.android.systemui.controls.controller.ControlInfo @@ -27,12 +30,12 @@ import com.android.systemui.controls.controller.ControlInfo interface ControlsModel { /** - * List of favorites (builders) in order. + * List of favorites in order. * * This should be obtained prior to storing the favorites using * [ControlsController.replaceFavoritesForComponent]. */ - val favorites: List<ControlInfo.Builder> + val favorites: List<ControlInfo> /** * List of all the elements to display by the corresponding [RecyclerView]. @@ -48,6 +51,24 @@ interface ControlsModel { * Move an item (in elements) from one position to another. */ fun onMoveItem(from: Int, to: Int) {} + + /** + * Attach an adapter to the model. + * + * This can be used to notify the adapter of changes in the model. + */ + fun attachAdapter(adapter: RecyclerView.Adapter<*>) {} + + /** + * Callback to notify elements (other than the adapter) of relevant changes in the model. + */ + interface ControlsModelCallback { + + /** + * Use to notify that the model has changed for the first time + */ + fun onFirstChange() + } } /** @@ -55,5 +76,29 @@ interface ControlsModel { * [ControlAdapter]. */ sealed class ElementWrapper + data class ZoneNameWrapper(val zoneName: CharSequence) : ElementWrapper() -data class ControlWrapper(val controlStatus: ControlStatus) : ElementWrapper()
\ No newline at end of file + +data class ControlStatusWrapper( + val controlStatus: ControlStatus +) : ElementWrapper(), ControlInterface by controlStatus + +data class ControlInfoWrapper( + override val component: ComponentName, + val controlInfo: ControlInfo, + override var favorite: Boolean +) : ElementWrapper(), ControlInterface { + override val controlId: String + get() = controlInfo.controlId + override val title: CharSequence + get() = controlInfo.controlTitle + override val subtitle: CharSequence + get() = controlInfo.controlSubtitle + override val deviceType: Int + get() = controlInfo.deviceType +} + +data class DividerWrapper( + var showNone: Boolean = false, + var showDivider: Boolean = false +) : ElementWrapper()
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt index 0c41f7e5df5a..3be59009f531 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt @@ -64,6 +64,7 @@ class ControlsProviderSelectorActivity @Inject constructor( override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setContentView(R.layout.controls_management) requireViewById<ViewStub>(R.id.stub).apply { layoutResource = R.layout.controls_management_apps diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt deleted file mode 100644 index 5c51e3dbe4ac..000000000000 --- a/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.controls.management - -import android.text.TextUtils -import android.util.Log -import com.android.systemui.controls.ControlStatus -import java.util.Collections -import java.util.Comparator - -/** - * Model for keeping track of current favorites and their order. - * - * This model is to be used with two [ControlAdapter] one that shows only favorites in the current - * order and another that shows all controls, separated by zone. When the favorite state of any - * control is modified or when the favorites are reordered, the adapters are notified of the change. - * - * @param listControls list of all the [ControlStatus] to display. This includes controls currently - * marked as favorites as well as those that have been removed (not returned - * from load) - * @param listFavoritesIds list of the [Control.controlId] for all the favorites, including those - * that have been removed. - * @param favoritesAdapter [ControlAdapter] used by the [RecyclerView] that shows only favorites - * @param allAdapter [ControlAdapter] used by the [RecyclerView] that shows all controls - */ -class FavoriteModel( - private val listControls: List<ControlStatus>, - listFavoritesIds: List<String>, - private val favoritesAdapter: ControlAdapter, - private val allAdapter: ControlAdapter -) { - - companion object { - private const val TAG = "FavoriteModel" - } - - /** - * List of favorite controls ([ControlWrapper]) in order. - * - * Initially, this list will give a list of wrappers in the order specified by the constructor - * variable `listFavoriteIds`. - * - * As the favorites are added, removed or moved, this list will keep track of those changes. - */ - val favorites: List<ControlWrapper> = listFavoritesIds.map { id -> - ControlWrapper(listControls.first { it.control.controlId == id }) - }.toMutableList() - - /** - * List of all controls by zones. - * - * Lists all the controls with the zone names interleaved as a flat list. After each zone name, - * the controls in that zone are listed. Zones are listed in alphabetical order - */ - val all: List<ElementWrapper> = listControls.groupBy { it.control.zone } - .mapKeys { it.key ?: "" } // map null to empty - .toSortedMap(CharSequenceComparator()) - .flatMap { - val controls = it.value.map { ControlWrapper(it) } - if (!TextUtils.isEmpty(it.key)) { - listOf(ZoneNameWrapper(it.key)) + controls - } else { - controls - } - } - - /** - * Change the favorite status of a [Control]. - * - * This can be invoked from any of the [ControlAdapter]. It will change the status of that - * control and either add it to the list of favorites (at the end) or remove it from it. - * - * Removing the favorite status from a Removed control will make it disappear completely if - * changes are saved. - * - * @param controlId the id of the [Control] to change the status - * @param favorite `true` if and only if it's set to be a favorite. - */ - fun changeFavoriteStatus(controlId: String, favorite: Boolean) { - favorites as MutableList - val index = all.indexOfFirst { - it is ControlWrapper && it.controlStatus.control.controlId == controlId - } - val control = (all[index] as ControlWrapper).controlStatus - if (control.favorite == favorite) { - Log.d(TAG, "Changing favorite to same state for ${control.control.controlId} ") - return - } else { - control.favorite = favorite - } - allAdapter.notifyItemChanged(index) - if (favorite) { - favorites.add(all[index] as ControlWrapper) - favoritesAdapter.notifyItemInserted(favorites.size - 1) - } else { - val i = favorites.indexOfFirst { it.controlStatus.control.controlId == controlId } - favorites.removeAt(i) - favoritesAdapter.notifyItemRemoved(i) - } - } - - /** - * Move items in the model and notify the [favoritesAdapter]. - */ - fun onMoveItem(from: Int, to: Int) { - if (from < to) { - for (i in from until to) { - Collections.swap(favorites, i, i + 1) - } - } else { - for (i in from downTo to + 1) { - Collections.swap(favorites, i, i - 1) - } - } - favoritesAdapter.notifyItemMoved(from, to) - } -} - -/** - * Compares [CharSequence] as [String]. - * - * It will have empty strings as the first element - */ -class CharSequenceComparator : Comparator<CharSequence> { - override fun compare(p0: CharSequence?, p1: CharSequence?): Int { - if (p0 == null && p1 == null) return 0 - else if (p0 == null && p1 != null) return -1 - else if (p0 != null && p1 == null) return 1 - return p0.toString().compareTo(p1.toString()) - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt new file mode 100644 index 000000000000..411170cb322c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt @@ -0,0 +1,221 @@ +/* + * 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.controls.management + +import android.content.ComponentName +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import com.android.systemui.controls.ControlInterface +import com.android.systemui.controls.controller.ControlInfo +import java.util.Collections + +/** + * Model used to show and rearrange favorites. + * + * The model will show all the favorite controls and a divider that can be toggled visible/gone. + * It will place the items selected as favorites before the divider and the ones unselected after. + * + * @property componentName used by the [ControlAdapter] to retrieve resources. + * @property favorites list of current favorites + * @property favoritesModelCallback callback to notify on first change and empty favorites + */ +class FavoritesModel( + private val componentName: ComponentName, + favorites: List<ControlInfo>, + private val favoritesModelCallback: FavoritesModelCallback +) : ControlsModel { + + private var adapter: RecyclerView.Adapter<*>? = null + private var modified = false + + override fun attachAdapter(adapter: RecyclerView.Adapter<*>) { + this.adapter = adapter + } + + override val favorites: List<ControlInfo> + get() = elements.take(dividerPosition).map { + (it as ControlInfoWrapper).controlInfo + } + + override val elements: List<ElementWrapper> = favorites.map { + ControlInfoWrapper(componentName, it, true) + } + DividerWrapper() + + /** + * Indicates the position of the divider to determine + */ + private var dividerPosition = elements.size - 1 + + override fun changeFavoriteStatus(controlId: String, favorite: Boolean) { + val position = elements.indexOfFirst { it is ControlInterface && it.controlId == controlId } + if (position == -1) { + return // controlId not found + } + if (position < dividerPosition && favorite || position > dividerPosition && !favorite) { + return // Does not change favorite status + } + if (favorite) { + onMoveItemInternal(position, dividerPosition) + } else { + onMoveItemInternal(position, elements.size - 1) + } + } + + override fun onMoveItem(from: Int, to: Int) { + onMoveItemInternal(from, to) + } + + private fun updateDividerNone(oldDividerPosition: Int, show: Boolean) { + (elements[oldDividerPosition] as DividerWrapper).showNone = show + favoritesModelCallback.onNoneChanged(show) + } + + private fun updateDividerShow(oldDividerPosition: Int, show: Boolean) { + (elements[oldDividerPosition] as DividerWrapper).showDivider = show + } + + /** + * Performs the update in the model. + * + * * update the favorite field of the [ControlInterface] + * * update the fields of the [DividerWrapper] + * * move the corresponding element in [elements] + * + * It may emit the following signals: + * * [RecyclerView.Adapter.notifyItemChanged] if a [ControlInterface.favorite] has changed + * (in the new position) or if the information in [DividerWrapper] has changed (in the + * old position). + * * [RecyclerView.Adapter.notifyItemMoved] + * * [FavoritesModelCallback.onNoneChanged] whenever we go from 1 to 0 favorites and back + * * [ControlsModel.ControlsModelCallback.onFirstChange] upon the first change in the model + */ + private fun onMoveItemInternal(from: Int, to: Int) { + if (from == dividerPosition) return // divider does not move + var changed = false + if (from < dividerPosition && to >= dividerPosition || + from > dividerPosition && to <= dividerPosition) { + if (from < dividerPosition && to >= dividerPosition) { + // favorite to not favorite + (elements[from] as ControlInfoWrapper).favorite = false + } else if (from > dividerPosition && to <= dividerPosition) { + // not favorite to favorite + (elements[from] as ControlInfoWrapper).favorite = true + } + changed = true + updateDivider(from, to) + } + moveElement(from, to) + adapter?.notifyItemMoved(from, to) + if (changed) { + adapter?.notifyItemChanged(to, Any()) + } + if (!modified) { + modified = true + favoritesModelCallback.onFirstChange() + } + } + + private fun updateDivider(from: Int, to: Int) { + var dividerChanged = false + val oldDividerPosition = dividerPosition + if (from < dividerPosition && to >= dividerPosition) { // favorite to not favorite + dividerPosition-- + if (dividerPosition == 0) { + updateDividerNone(oldDividerPosition, true) + dividerChanged = true + } + if (dividerPosition == elements.size - 2) { + updateDividerShow(oldDividerPosition, true) + dividerChanged = true + } + } else if (from > dividerPosition && to <= dividerPosition) { // not favorite to favorite + dividerPosition++ + if (dividerPosition == 1) { + updateDividerNone(oldDividerPosition, false) + dividerChanged = true + } + if (dividerPosition == elements.size - 1) { + updateDividerShow(oldDividerPosition, false) + dividerChanged = true + } + } + if (dividerChanged) { + adapter?.notifyItemChanged(oldDividerPosition) + } + } + + private fun moveElement(from: Int, to: Int) { + if (from < to) { + for (i in from until to) { + Collections.swap(elements, i, i + 1) + } + } else { + for (i in from downTo to + 1) { + Collections.swap(elements, i, i - 1) + } + } + } + + /** + * Touch helper to facilitate dragging in the [RecyclerView]. + * + * Only views above the divider line (favorites) can be dragged or accept drops. + */ + val itemTouchHelperCallback = object : ItemTouchHelper.SimpleCallback(0, 0) { + + private val MOVEMENT = ItemTouchHelper.UP or + ItemTouchHelper.DOWN or + ItemTouchHelper.LEFT or + ItemTouchHelper.RIGHT + + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean { + onMoveItem(viewHolder.adapterPosition, target.adapterPosition) + return true + } + + override fun getMovementFlags( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder + ): Int { + if (viewHolder.adapterPosition < dividerPosition) { + return ItemTouchHelper.Callback.makeMovementFlags(MOVEMENT, 0) + } else { + return ItemTouchHelper.Callback.makeMovementFlags(0, 0) + } + } + + override fun canDropOver( + recyclerView: RecyclerView, + current: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean { + return target.adapterPosition < dividerPosition + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {} + + override fun isItemViewSwipeEnabled() = false + } + + interface FavoritesModelCallback : ControlsModel.ControlsModelCallback { + fun onNoneChanged(showNoFavorites: Boolean) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt index 680d0066fc56..2c1a91dca225 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt @@ -16,52 +16,64 @@ package com.android.systemui.controls.ui +import android.app.Dialog import android.app.PendingIntent import android.content.Intent -import android.provider.Settings +import android.service.controls.Control import android.service.controls.actions.BooleanAction import android.service.controls.actions.CommandAction import android.util.Log import android.view.HapticFeedbackConstants +import com.android.systemui.R object ControlActionCoordinator { - public const val MIN_LEVEL = 0 - public const val MAX_LEVEL = 10000 + const val MIN_LEVEL = 0 + const val MAX_LEVEL = 10000 - private var useDetailDialog: Boolean? = null + private var dialog: Dialog? = null + + fun closeDialog() { + dialog?.dismiss() + dialog = null + } fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) { cvh.action(BooleanAction(templateId, !isChecked)) - - val nextLevel = if (isChecked) MIN_LEVEL else MAX_LEVEL - cvh.clipLayer.setLevel(nextLevel) } - fun touch(cvh: ControlViewHolder, templateId: String) { - cvh.action(CommandAction(templateId)) + fun touch(cvh: ControlViewHolder, templateId: String, control: Control) { + if (cvh.usePanel()) { + showDialog(cvh, control.getAppIntent().getIntent()) + } else { + cvh.action(CommandAction(templateId)) + } } + /** + * Allow apps to specify whether they would like to appear in a detail panel or within + * the full activity by setting the {@link Control#EXTRA_USE_PANEL} flag. In order for + * activities to determine how they are being launched, they should inspect the + * {@link Control#EXTRA_USE_PANEL} flag for a value of true. + */ fun longPress(cvh: ControlViewHolder) { // Long press snould only be called when there is valid control state, otherwise ignore cvh.cws.control?.let { - if (useDetailDialog == null) { - useDetailDialog = Settings.Secure.getInt(cvh.context.getContentResolver(), - "systemui.controls_use_detail_panel", 0) != 0 - } - try { + it.getAppIntent().send() cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) - if (useDetailDialog!!) { - DetailDialog(cvh.context, it.getAppIntent()).show() - } else { - it.getAppIntent().send() - val closeDialog = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) - cvh.context.sendBroadcast(closeDialog) - } + cvh.context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) } catch (e: PendingIntent.CanceledException) { Log.e(ControlsUiController.TAG, "Error sending pending intent", e) - cvh.setTransientStatus("Error opening application") + cvh.setTransientStatus( + cvh.context.resources.getString(R.string.controls_error_failed)) } } } + + private fun showDialog(cvh: ControlViewHolder, intent: Intent) { + dialog = DetailDialog(cvh, intent).also { + it.setOnDismissListener { _ -> dialog = null } + it.show() + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt index b1cb04e10eef..055adc6f6774 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt @@ -16,6 +16,9 @@ package com.android.systemui.controls.ui +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ValueAnimator import android.content.Context import android.graphics.drawable.ClipDrawable import android.graphics.drawable.GradientDrawable @@ -32,23 +35,38 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView - +import com.android.internal.graphics.ColorUtils +import com.android.systemui.Interpolators +import com.android.systemui.R import com.android.systemui.controls.controller.ControlsController import com.android.systemui.util.concurrency.DelayableExecutor -import com.android.systemui.R - import kotlin.reflect.KClass -private const val UPDATE_DELAY_IN_MILLIS = 3000L -private const val ALPHA_ENABLED = (255.0 * 0.2).toInt() -private const val ALPHA_DISABLED = 255 - +/** + * Wraps the widgets that make up the UI representation of a {@link Control}. Updates to the view + * are signaled via calls to {@link #bindData}. Similar to the ViewHolder concept used in + * RecyclerViews. + */ class ControlViewHolder( val layout: ViewGroup, val controlsController: ControlsController, val uiExecutor: DelayableExecutor, - val bgExecutor: DelayableExecutor + val bgExecutor: DelayableExecutor, + val usePanels: Boolean ) { + + companion object { + const val STATE_ANIMATION_DURATION = 700L + private const val UPDATE_DELAY_IN_MILLIS = 3000L + private const val ALPHA_ENABLED = (255.0 * 0.2).toInt() + private const val ALPHA_DISABLED = 0 + private val FORCE_PANEL_DEVICES = setOf( + DeviceTypes.TYPE_THERMOSTAT, + DeviceTypes.TYPE_CAMERA + ) + } + + private var stateAnimator: ValueAnimator? = null val icon: ImageView = layout.requireViewById(R.id.icon) val status: TextView = layout.requireViewById(R.id.status) val title: TextView = layout.requireViewById(R.id.title) @@ -59,11 +77,14 @@ class ControlViewHolder( var cancelUpdate: Runnable? = null var behavior: Behavior? = null var lastAction: ControlAction? = null + val deviceType: Int + get() = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType init { val ld = layout.getBackground() as LayerDrawable ld.mutate() clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable + clipLayer.alpha = ALPHA_DISABLED // needed for marquee to start status.setSelected(true) } @@ -76,7 +97,7 @@ class ControlViewHolder( val (controlStatus, template) = cws.control?.let { title.setText(it.getTitle()) subtitle.setText(it.getSubtitle()) - Pair(it.getStatus(), it.getControlTemplate()) + Pair(it.status, it.controlTemplate) } ?: run { title.setText(cws.ci.controlTitle) subtitle.setText(cws.ci.controlSubtitle) @@ -91,7 +112,7 @@ class ControlViewHolder( }) } - val clazz = findBehavior(controlStatus, template) + val clazz = findBehavior(controlStatus, template, deviceType) if (behavior == null || behavior!!::class != clazz) { // Behavior changes can signal a change in template from the app or // first time setup @@ -126,9 +147,17 @@ class ControlViewHolder( controlsController.action(cws.componentName, cws.ci, action) } - private fun findBehavior(status: Int, template: ControlTemplate): KClass<out Behavior> { + fun usePanel(): Boolean = + usePanels && deviceType in ControlViewHolder.FORCE_PANEL_DEVICES + + private fun findBehavior( + status: Int, + template: ControlTemplate, + deviceType: Int + ): KClass<out Behavior> { return when { status == Control.STATUS_UNKNOWN -> UnknownBehavior::class + deviceType == DeviceTypes.TYPE_CAMERA -> TouchBehavior::class template is ToggleTemplate -> ToggleBehavior::class template is StatelessTemplate -> TouchBehavior::class template is ToggleRangeTemplate -> ToggleRangeBehavior::class @@ -137,31 +166,49 @@ class ControlViewHolder( } } - internal fun applyRenderInfo(enabled: Boolean, offset: Int = 0) { + internal fun applyRenderInfo(enabled: Boolean, offset: Int = 0, animated: Boolean = true) { setEnabled(enabled) - val deviceType = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType val ri = RenderInfo.lookup(context, cws.componentName, deviceType, enabled, offset) val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme()) - val (bg, alpha) = if (enabled) { + val (bg, newAlpha) = if (enabled) { Pair(ri.enabledBackground, ALPHA_ENABLED) } else { Pair(R.color.control_default_background, ALPHA_DISABLED) } status.setTextColor(fg) - icon.setImageDrawable(ri.icon) // do not color app icons if (deviceType != DeviceTypes.TYPE_ROUTINE) { - icon.setImageTintList(fg) + icon.imageTintList = fg } (clipLayer.getDrawable() as GradientDrawable).apply { - setColor(context.getResources().getColor(bg, context.getTheme())) - setAlpha(alpha) + val newColor = context.resources.getColor(bg, context.theme) + stateAnimator?.cancel() + if (animated) { + val oldColor = color?.defaultColor ?: newColor + stateAnimator = ValueAnimator.ofInt(clipLayer.alpha, newAlpha).apply { + addUpdateListener { + alpha = it.animatedValue as Int + setColor(ColorUtils.blendARGB(oldColor, newColor, it.animatedFraction)) + } + addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + stateAnimator = null + } + }) + duration = STATE_ANIMATION_DURATION + interpolator = Interpolators.CONTROL_STATE + start() + } + } else { + alpha = newAlpha + setColor(newColor) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index 6e527e29a848..fab6fc7357dd 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -16,24 +16,33 @@ package com.android.systemui.controls.ui +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ObjectAnimator +import android.app.AlertDialog import android.app.Dialog import android.content.ComponentName import android.content.Context +import android.content.DialogInterface import android.content.Intent import android.content.SharedPreferences import android.content.res.Configuration import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable +import android.os.Process +import android.provider.Settings import android.service.controls.Control import android.service.controls.actions.ControlAction -import android.util.TypedValue import android.util.Log +import android.util.TypedValue import android.view.ContextThemeWrapper import android.view.LayoutInflater import android.view.View import android.view.View.MeasureSpec import android.view.ViewGroup import android.view.WindowManager +import android.view.animation.AccelerateInterpolator +import android.view.animation.DecelerateInterpolator import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.ImageView @@ -41,22 +50,21 @@ import android.widget.LinearLayout import android.widget.ListPopupWindow import android.widget.Space import android.widget.TextView +import com.android.systemui.R import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.controller.ControlInfo import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.controller.StructureInfo +import com.android.systemui.controls.management.ControlsEditingActivity +import com.android.systemui.controls.management.ControlsFavoritingActivity import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsProviderSelectorActivity import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.util.concurrency.DelayableExecutor -import com.android.systemui.R - import dagger.Lazy - import java.text.Collator import java.util.function.Consumer - import javax.inject.Inject import javax.inject.Singleton @@ -76,6 +84,9 @@ class ControlsUiControllerImpl @Inject constructor ( private const val PREF_COMPONENT = "controls_component" private const val PREF_STRUCTURE = "controls_structure" + private const val USE_PANELS = "systemui.controls_use_panel" + private const val FADE_IN_MILLIS = 225L + private val EMPTY_COMPONENT = ComponentName("", "") private val EMPTY_STRUCTURE = StructureInfo( EMPTY_COMPONENT, @@ -92,21 +103,8 @@ class ControlsUiControllerImpl @Inject constructor ( private lateinit var lastItems: List<SelectionItem> private var popup: ListPopupWindow? = null private var activeDialog: Dialog? = null - private val addControlsItem: SelectionItem private var hidden = true - init { - val addDrawable = context.getDrawable(R.drawable.ic_add).apply { - setTint(context.resources.getColor(R.color.control_secondary_text, null)) - } - addControlsItem = SelectionItem( - context.resources.getString(R.string.controls_providers_title), - "", - addDrawable, - EMPTY_COMPONENT - ) - } - override val available: Boolean get() = controlsController.get().available @@ -165,7 +163,20 @@ class ControlsUiControllerImpl @Inject constructor ( private fun reload(parent: ViewGroup) { if (hidden) return - show(parent) + + val fadeAnim = ObjectAnimator.ofFloat(parent, "alpha", 1.0f, 0.0f) + fadeAnim.setInterpolator(AccelerateInterpolator(1.0f)) + fadeAnim.setDuration(FADE_IN_MILLIS) + fadeAnim.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + show(parent) + val showAnim = ObjectAnimator.ofFloat(parent, "alpha", 0.0f, 1.0f) + showAnim.setInterpolator(DecelerateInterpolator(1.0f)) + showAnim.setDuration(FADE_IN_MILLIS) + showAnim.start() + } + }) + fadeAnim.start() } private fun showSeedingView(items: List<SelectionItem>) { @@ -184,7 +195,7 @@ class ControlsUiControllerImpl @Inject constructor ( inflater.inflate(R.layout.controls_no_favorites, parent, true) val viewGroup = parent.requireViewById(R.id.controls_no_favorites_group) as ViewGroup - viewGroup.setOnClickListener(launchSelectorActivityListener(context)) + viewGroup.setOnClickListener { v: View -> startProviderSelectorActivity(v.context) } val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle) subtitle.setText(context.resources.getString(R.string.quick_controls_subtitle)) @@ -198,16 +209,42 @@ class ControlsUiControllerImpl @Inject constructor ( } } - private fun launchSelectorActivityListener(context: Context): (View) -> Unit { - return { _ -> - val closeDialog = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) - context.sendBroadcast(closeDialog) + private fun startFavoritingActivity(context: Context, si: StructureInfo) { + startTargetedActivity(context, si, ControlsFavoritingActivity::class.java) + } + + private fun startEditingActivity(context: Context, si: StructureInfo) { + startTargetedActivity(context, si, ControlsEditingActivity::class.java) + } + + private fun startTargetedActivity(context: Context, si: StructureInfo, klazz: Class<*>) { + val i = Intent(context, klazz).apply { + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + } + putIntentExtras(i, si) + startActivity(context, i) + } + + private fun putIntentExtras(intent: Intent, si: StructureInfo) { + intent.apply { + putExtra(ControlsFavoritingActivity.EXTRA_APP, + controlsListingController.get().getAppLabel(si.componentName)) + putExtra(ControlsFavoritingActivity.EXTRA_STRUCTURE, si.structure) + putExtra(Intent.EXTRA_COMPONENT_NAME, si.componentName) + } + } - val i = Intent() - i.setComponent(ComponentName(context, ControlsProviderSelectorActivity::class.java)) - i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) - context.startActivity(i) + private fun startProviderSelectorActivity(context: Context) { + val i = Intent(context, ControlsProviderSelectorActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) } + startActivity(context, i) + } + + private fun startActivity(context: Context, intent: Intent) { + val closeDialog = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) + context.sendBroadcast(closeDialog) + context.startActivity(intent) } private fun showControlsView(items: List<SelectionItem>) { @@ -229,7 +266,9 @@ class ControlsUiControllerImpl @Inject constructor ( private fun createMenu() { val items = arrayOf( - context.resources.getString(R.string.controls_menu_add) + context.resources.getString(R.string.controls_menu_add), + context.resources.getString(R.string.controls_menu_edit), + "Reset" ) var adapter = ArrayAdapter<String>(context, R.layout.controls_more_item, items) @@ -248,7 +287,11 @@ class ControlsUiControllerImpl @Inject constructor ( ) { when (pos) { // 0: Add Control - 0 -> launchSelectorActivityListener(view.context)(parent) + 0 -> startFavoritingActivity(view.context, selectedStructure) + // 1: Edit controls + 1 -> startEditingActivity(view.context, selectedStructure) + // 2: TEMPORARY for reset controls + 2 -> showResetConfirmation() else -> Log.w(ControlsUiController.TAG, "Unsupported index ($pos) on 'more' menu selection") } @@ -275,6 +318,39 @@ class ControlsUiControllerImpl @Inject constructor ( }) } + private fun showResetConfirmation() { + val builder = AlertDialog.Builder( + context, + android.R.style.Theme_DeviceDefault_Dialog_Alert + ).apply { + setMessage("For testing purposes: Would you like to " + + "reset your favorited device controls?") + setPositiveButton( + android.R.string.ok, + DialogInterface.OnClickListener { dialog, _ -> + val userHandle = Process.myUserHandle() + val userContext = context.createContextAsUser(userHandle, 0) + val prefs = userContext.getSharedPreferences( + "controls_prefs", Context.MODE_PRIVATE) + prefs.edit().putBoolean("ControlsSeedingCompleted", false).apply() + controlsController.get().resetFavorites() + dialog.dismiss() + context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) + }) + setNegativeButton( + android.R.string.cancel, + DialogInterface.OnClickListener { + dialog, _ -> dialog.cancel() + } + ) + } + builder.create().apply { + getWindow().apply { + setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) + } + }.show() + } + private fun createDropDown(items: List<SelectionItem>) { items.forEach { RenderInfo.registerComponentIcon(it.componentName, it.icon) @@ -302,7 +378,6 @@ class ControlsUiControllerImpl @Inject constructor ( .setTint(context.resources.getColor(R.color.control_spinner_dropdown, null)) } parent.requireViewById<ImageView>(R.id.app_icon).apply { - setContentDescription(selectionItem.getTitle()) setImageDrawable(selectionItem.icon) } @@ -349,6 +424,9 @@ class ControlsUiControllerImpl @Inject constructor ( val maxColumns = findMaxColumns() + // use flag only temporarily for testing + val usePanels = Settings.Secure.getInt(context.contentResolver, USE_PANELS, 0) == 1 + val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup var lastRow: ViewGroup = createRow(inflater, listView) selectedStructure.controls.forEach { @@ -362,7 +440,8 @@ class ControlsUiControllerImpl @Inject constructor ( baseLayout, controlsController.get(), uiExecutor, - bgExecutor + bgExecutor, + usePanels ) val key = ControlKey(selectedStructure.componentName, it.controlId) cvh.bindData(controlsById.getValue(key)) @@ -370,7 +449,8 @@ class ControlsUiControllerImpl @Inject constructor ( } // add spacers if necessary to keep control size consistent - var spacersToAdd = selectedStructure.controls.size % maxColumns + val mod = selectedStructure.controls.size % maxColumns + var spacersToAdd = if (mod == 0) 0 else maxColumns - mod while (spacersToAdd > 0) { lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f)) spacersToAdd-- @@ -441,6 +521,7 @@ class ControlsUiControllerImpl @Inject constructor ( hidden = true popup?.dismiss() activeDialog?.dismiss() + ControlActionCoordinator.closeDialog() controlsController.get().unsubscribe() @@ -526,7 +607,6 @@ private class ItemAdapter( setText(item.getTitle()) } view.requireViewById<ImageView>(R.id.app_icon).apply { - setContentDescription(item.appName) setImageDrawable(item.icon) } return view diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt index d3d4287b8707..15c41a2005a6 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt @@ -17,18 +17,16 @@ package com.android.systemui.controls.ui import android.app.ActivityView -import android.app.ActivityOptions import android.app.Dialog -import android.app.PendingIntent import android.content.ComponentName -import android.content.Context import android.content.Intent +import android.provider.Settings import android.view.View import android.view.ViewGroup -import android.view.ViewGroup.LayoutParams.MATCH_PARENT -import android.view.Window +import android.view.WindowInsets import android.view.WindowManager -import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS +import android.widget.ImageView +import android.widget.TextView import com.android.systemui.R @@ -38,20 +36,26 @@ import com.android.systemui.R * The activity being launched is specified by {@link android.service.controls.Control#getAppIntent}. */ class DetailDialog( - val parentContext: Context, - val intent: PendingIntent -) : Dialog(parentContext) { + val cvh: ControlViewHolder, + val intent: Intent +) : Dialog(cvh.context, R.style.Theme_SystemUI_Dialog_Control_DetailPanel) { - var activityView: ActivityView + companion object { + private const val ALPHA = (0.8f * 255).toInt() + private const val PANEL_TOP_OFFSET = "systemui.controls_panel_top_offset" + } + + lateinit var activityView: ActivityView val stateCallback: ActivityView.StateCallback = object : ActivityView.StateCallback() { override fun onActivityViewReady(view: ActivityView) { - val fillInIntent = Intent() + val launchIntent = Intent(intent) // Apply flags to make behaviour match documentLaunchMode=always. - fillInIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) - view.startActivity(intent, fillInIntent, ActivityOptions.makeBasic()) + launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) + + view.startActivity(launchIntent) } override fun onActivityViewDestroyed(view: ActivityView) {} @@ -61,28 +65,8 @@ class DetailDialog( override fun onTaskRemovalStarted(taskId: Int) {} } - @Suppress("DEPRECATION") - private fun Window.setWindowParams() { - requestFeature(Window.FEATURE_NO_TITLE) - - // Inflate the decor view, so the attributes below are not overwritten by the theme. - decorView - attributes.systemUiVisibility = - (attributes.systemUiVisibility - or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - or View.SYSTEM_UI_FLAG_LAYOUT_STABLE) - - setLayout(MATCH_PARENT, MATCH_PARENT) - clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) - addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR - or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) - setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) - getAttributes().setFitInsetsTypes(0 /* types */) - } - init { - getWindow()?.setWindowParams() + window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) setContentView(R.layout.controls_detail_dialog) @@ -90,19 +74,61 @@ class DetailDialog( requireViewById<ViewGroup>(R.id.controls_activity_view).apply { addView(activityView) } + + requireViewById<ImageView>(R.id.control_detail_close).apply { + setOnClickListener { _: View -> dismiss() } + } + + requireViewById<TextView>(R.id.title).apply { + setText(cvh.title.text) + } + + requireViewById<TextView>(R.id.subtitle).apply { + setText(cvh.subtitle.text) + } + + requireViewById<ImageView>(R.id.control_detail_open_in_app).apply { + setOnClickListener { v: View -> + dismiss() + context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) + v.context.startActivity(intent) + } + } + + // consume all insets to achieve slide under effect + window.getDecorView().setOnApplyWindowInsetsListener { + v: View, insets: WindowInsets -> + activityView.apply { + val l = getPaddingLeft() + val t = getPaddingTop() + val r = getPaddingRight() + setPadding(l, t, r, insets.getSystemWindowInsets().bottom) + } + + insets.consumeSystemWindowInsets() + } + + requireViewById<ViewGroup>(R.id.control_detail_root).apply { + // use flag only temporarily for testing + val resolver = cvh.context.contentResolver + val defaultOffsetInPx = cvh.context.resources + .getDimensionPixelSize(R.dimen.controls_activity_view_top_offset) + val offsetInPx = Settings.Secure.getInt(resolver, PANEL_TOP_OFFSET, defaultOffsetInPx) + + val lp = getLayoutParams() as ViewGroup.MarginLayoutParams + lp.topMargin = offsetInPx + setLayoutParams(lp) + } } override fun show() { - val attrs = getWindow()?.attributes - attrs?.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS - getWindow()?.attributes = attrs - activityView.setCallback(stateCallback) super.show() } override fun dismiss() { + if (!isShowing()) return activityView.release() super.dismiss() diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt index d33cd94004fd..124df32af5e0 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt @@ -56,20 +56,19 @@ data class RenderInfo( enabled: Boolean, offset: Int = 0 ): RenderInfo { - val (fg, bg) = deviceColorMap.getValue(deviceType) - - val iconKey = if (offset > 0) { + val key = if (offset > 0) { deviceType * BUCKET_SIZE + offset } else deviceType - val iconState = deviceIconMap.getValue(iconKey) + val (fg, bg) = deviceColorMap.getValue(key) + val iconState = deviceIconMap.getValue(key) val resourceId = iconState[enabled] var icon: Drawable? if (resourceId == APP_ICON_ID) { icon = appIconMap.get(componentName) if (icon == null) { icon = context.resources - .getDrawable(R.drawable.ic_device_unknown_gm2_24px, null) + .getDrawable(R.drawable.ic_device_unknown_on, null) appIconMap.put(componentName, icon) } } else { @@ -268,10 +267,74 @@ private val deviceIconMap = mapOf<Int, IconState>( DeviceTypes.TYPE_ROUTINE to IconState( RenderInfo.APP_ICON_ID, RenderInfo.APP_ICON_ID + ), + DeviceTypes.TYPE_AC_HEATER to IconState( + R.drawable.ic_device_thermostat_off, + R.drawable.ic_device_thermostat_on + ), + DeviceTypes.TYPE_AC_UNIT to IconState( + R.drawable.ic_device_thermostat_off, + R.drawable.ic_device_thermostat_on + ), + DeviceTypes.TYPE_COFFEE_MAKER to IconState( + R.drawable.ic_device_kettle_off, + R.drawable.ic_device_kettle_on + ), + DeviceTypes.TYPE_DEHUMIDIFIER to IconState( + R.drawable.ic_device_air_freshener_off, + R.drawable.ic_device_air_freshener_on + ), + DeviceTypes.TYPE_RADIATOR to IconState( + R.drawable.ic_device_thermostat_off, + R.drawable.ic_device_thermostat_on + ), + DeviceTypes.TYPE_STANDMIXER to IconState( + R.drawable.ic_device_cooking_off, + R.drawable.ic_device_cooking_on + ), + DeviceTypes.TYPE_DISPLAY to IconState( + R.drawable.ic_device_display_off, + R.drawable.ic_device_display_on + ), + DeviceTypes.TYPE_DRYER to IconState( + R.drawable.ic_device_washer_off, + R.drawable.ic_device_washer_on + ), + DeviceTypes.TYPE_MOWER to IconState( + R.drawable.ic_device_outdoor_garden_off, + R.drawable.ic_device_outdoor_garden_on + ), + DeviceTypes.TYPE_SHOWER to IconState( + R.drawable.ic_device_water_off, + R.drawable.ic_device_water_on + ), + DeviceTypes.TYPE_AWNING to IconState( + R.drawable.ic_device_pergola_off, + R.drawable.ic_device_pergola_on + ), + DeviceTypes.TYPE_CLOSET to IconState( + R.drawable.ic_device_drawer_off, + R.drawable.ic_device_drawer_on + ), + DeviceTypes.TYPE_CURTAIN to IconState( + R.drawable.ic_device_blinds_off, + R.drawable.ic_device_blinds_on + ), + DeviceTypes.TYPE_DOOR to IconState( + R.drawable.ic_device_door_off, + R.drawable.ic_device_door_on + ), + DeviceTypes.TYPE_SHUTTER to IconState( + R.drawable.ic_device_window_off, + R.drawable.ic_device_window_on + ), + DeviceTypes.TYPE_HEATER to IconState( + R.drawable.ic_device_thermostat_off, + R.drawable.ic_device_thermostat_on ) ).withDefault { IconState( - R.drawable.ic_device_unknown_gm2_24px, - R.drawable.ic_device_unknown_gm2_24px + R.drawable.ic_device_unknown_off, + R.drawable.ic_device_unknown_on ) } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt index 15c1dabf71bd..6340db1d756d 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt @@ -33,6 +33,10 @@ class TemperatureControlBehavior : Behavior { override fun initialize(cvh: ControlViewHolder) { this.cvh = cvh + + cvh.layout.setOnClickListener { _ -> + ControlActionCoordinator.touch(cvh, template.getTemplateId(), control) + } } override fun bind(cws: ControlWithState) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt index a3368ef77a56..368d1399971d 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt @@ -18,12 +18,10 @@ package com.android.systemui.controls.ui import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable -import android.view.View import android.service.controls.Control import android.service.controls.templates.ToggleTemplate - +import android.view.View import com.android.systemui.R -import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL import com.android.systemui.controls.ui.ControlActionCoordinator.MAX_LEVEL class ToggleBehavior : Behavior { @@ -34,7 +32,7 @@ class ToggleBehavior : Behavior { override fun initialize(cvh: ControlViewHolder) { this.cvh = cvh - cvh.applyRenderInfo(false) + cvh.applyRenderInfo(false /* enabled */, 0 /* offset */, false /* animated */) cvh.layout.setOnClickListener(View.OnClickListener() { ControlActionCoordinator.toggle(cvh, template.getTemplateId(), template.isChecked()) @@ -49,9 +47,9 @@ class ToggleBehavior : Behavior { val ld = cvh.layout.getBackground() as LayerDrawable clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) + clipLayer.level = MAX_LEVEL val checked = template.isChecked() - clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL) cvh.applyRenderInfo(checked) } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt index 5a956653285c..d8b26e2e68d8 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt @@ -16,11 +16,20 @@ package com.android.systemui.controls.ui -import android.os.Bundle +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ValueAnimator import android.content.Context import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable +import android.os.Bundle +import android.service.controls.Control +import android.service.controls.actions.FloatAction +import android.service.controls.templates.RangeTemplate +import android.service.controls.templates.ToggleRangeTemplate import android.util.Log +import android.util.MathUtils +import android.util.TypedValue import android.view.GestureDetector import android.view.GestureDetector.SimpleOnGestureListener import android.view.MotionEvent @@ -29,19 +38,14 @@ import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityNodeInfo import android.widget.TextView -import android.service.controls.Control -import android.service.controls.actions.FloatAction -import android.service.controls.templates.RangeTemplate -import android.service.controls.templates.ToggleRangeTemplate -import android.util.TypedValue - +import com.android.systemui.Interpolators import com.android.systemui.R -import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL import com.android.systemui.controls.ui.ControlActionCoordinator.MAX_LEVEL - +import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL import java.util.IllegalFormatException class ToggleRangeBehavior : Behavior { + private var rangeAnimator: ValueAnimator? = null lateinit var clipLayer: Drawable lateinit var template: ToggleRangeTemplate lateinit var control: Control @@ -61,20 +65,21 @@ class ToggleRangeBehavior : Behavior { status = cvh.status context = status.getContext() - cvh.applyRenderInfo(false) + cvh.applyRenderInfo(false /* enabled */, 0 /* offset */, false /* animated */) val gestureListener = ToggleRangeGestureListener(cvh.layout) val gestureDetector = GestureDetector(context, gestureListener) cvh.layout.setOnTouchListener { v: View, e: MotionEvent -> if (gestureDetector.onTouchEvent(e)) { - return@setOnTouchListener true + // Don't return true to let the state list change to "pressed" + return@setOnTouchListener false } if (e.getAction() == MotionEvent.ACTION_UP && gestureListener.isDragging) { v.getParent().requestDisallowInterceptTouchEvent(false) gestureListener.isDragging = false endUpdateRange() - return@setOnTouchListener true + return@setOnTouchListener false } return@setOnTouchListener false @@ -87,17 +92,18 @@ class ToggleRangeBehavior : Behavior { currentStatusText = control.getStatusText() status.setText(currentStatusText) + // ControlViewHolder sets a long click listener, but we want to handle touch in + // here instead, otherwise we'll have state conflicts. + cvh.layout.setOnLongClickListener(null) + val ld = cvh.layout.getBackground() as LayerDrawable clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) - clipLayer.setLevel(MIN_LEVEL) template = control.getControlTemplate() as ToggleRangeTemplate rangeTemplate = template.getRange() val checked = template.isChecked() - val currentRatio = rangeTemplate.getCurrentValue() / - (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue()) - updateRange(currentRatio, checked, /* isDragging */ false) + updateRange(rangeToLevelValue(rangeTemplate.currentValue), checked, /* isDragging */ false) cvh.applyRenderInfo(checked) @@ -146,9 +152,8 @@ class ToggleRangeBehavior : Behavior { } else { val value = arguments.getFloat( AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE) - val ratioDiff = (value - rangeTemplate.getCurrentValue()) / - (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue()) - updateRange(ratioDiff, template.isChecked(), /* isDragging */ false) + val level = rangeToLevelValue(value - rangeTemplate.getCurrentValue()) + updateRange(level, template.isChecked(), /* isDragging */ false) endUpdateRange() true } @@ -172,13 +177,30 @@ class ToggleRangeBehavior : Behavior { .getDimensionPixelSize(R.dimen.control_status_expanded).toFloat()) } - fun updateRange(ratioDiff: Float, checked: Boolean, isDragging: Boolean) { - val changeAmount = if (checked) (MAX_LEVEL * ratioDiff).toInt() else MIN_LEVEL - val newLevel = Math.max(MIN_LEVEL, Math.min(MAX_LEVEL, clipLayer.getLevel() + changeAmount)) - clipLayer.setLevel(newLevel) + fun updateRange(level: Int, checked: Boolean, isDragging: Boolean) { + val newLevel = if (checked) Math.max(MIN_LEVEL, Math.min(MAX_LEVEL, level)) else MIN_LEVEL + + rangeAnimator?.cancel() + if (isDragging) { + clipLayer.level = newLevel + } else { + rangeAnimator = ValueAnimator.ofInt(cvh.clipLayer.level, newLevel).apply { + addUpdateListener { + cvh.clipLayer.level = it.animatedValue as Int + } + addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + rangeAnimator = null + } + }) + duration = ControlViewHolder.STATE_ANIMATION_DURATION + interpolator = Interpolators.CONTROL_STATE + start() + } + } if (checked) { - val newValue = levelToRangeValue(clipLayer.getLevel()) + val newValue = levelToRangeValue(newLevel) currentRangeValue = format(rangeTemplate.getFormatString().toString(), DEFAULT_FORMAT, newValue) val text = if (isDragging) { @@ -206,9 +228,13 @@ class ToggleRangeBehavior : Behavior { } private fun levelToRangeValue(i: Int): Float { - val ratio = i.toFloat() / MAX_LEVEL - return rangeTemplate.getMinValue() + - (ratio * (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())) + return MathUtils.constrainedMap(rangeTemplate.minValue, rangeTemplate.maxValue, + MIN_LEVEL.toFloat(), MAX_LEVEL.toFloat(), i.toFloat()) + } + + private fun rangeToLevelValue(i: Float): Int { + return MathUtils.constrainedMap(MIN_LEVEL.toFloat(), MAX_LEVEL.toFloat(), + rangeTemplate.minValue, rangeTemplate.maxValue, i).toInt() } fun endUpdateRange() { @@ -247,6 +273,9 @@ class ToggleRangeBehavior : Behavior { } override fun onLongPress(e: MotionEvent) { + if (isDragging) { + return + } ControlActionCoordinator.longPress(this@ToggleRangeBehavior.cvh) } @@ -256,14 +285,19 @@ class ToggleRangeBehavior : Behavior { xDiff: Float, yDiff: Float ): Boolean { + if (!template.isChecked) { + return false + } if (!isDragging) { v.getParent().requestDisallowInterceptTouchEvent(true) this@ToggleRangeBehavior.beginUpdateRange() isDragging = true } - this@ToggleRangeBehavior.updateRange(-xDiff / v.getWidth(), - /* checked */ true, /* isDragging */ true) + val ratioDiff = -xDiff / v.width + val changeAmount = ((MAX_LEVEL - MIN_LEVEL) * ratioDiff).toInt() + this@ToggleRangeBehavior.updateRange(clipLayer.level + changeAmount, + checked = true, isDragging = true) return true } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt index d64a5f060487..fd96cea1541e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt @@ -20,7 +20,7 @@ import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable import android.view.View import android.service.controls.Control -import android.service.controls.templates.StatelessTemplate +import android.service.controls.templates.ControlTemplate import com.android.systemui.R import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL @@ -31,23 +31,23 @@ import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL */ class TouchBehavior : Behavior { lateinit var clipLayer: Drawable - lateinit var template: StatelessTemplate + lateinit var template: ControlTemplate lateinit var control: Control lateinit var cvh: ControlViewHolder override fun initialize(cvh: ControlViewHolder) { this.cvh = cvh - cvh.applyRenderInfo(false) + cvh.applyRenderInfo(false /* enabled */, 0 /* offset */, false /* animated */) cvh.layout.setOnClickListener(View.OnClickListener() { - ControlActionCoordinator.touch(cvh, template.getTemplateId()) + ControlActionCoordinator.touch(cvh, template.getTemplateId(), control) }) } override fun bind(cws: ControlWithState) { this.control = cws.control!! cvh.status.setText(control.getStatusText()) - template = control.getControlTemplate() as StatelessTemplate + template = control.getControlTemplate() val ld = cvh.layout.getBackground() as LayerDrawable clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java index 5b3d5c565472..82ccb17a52c6 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java @@ -74,6 +74,8 @@ import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.statusbar.policy.ZenModeControllerImpl; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerServiceImpl; +import com.android.systemui.util.RingerModeTracker; +import com.android.systemui.util.RingerModeTrackerImpl; import com.android.systemui.volume.VolumeComponent; import com.android.systemui.volume.VolumeDialogComponent; import com.android.systemui.volume.VolumeDialogControllerImpl; @@ -264,4 +266,10 @@ public abstract class DependencyBinder { @Binds public abstract VolumeComponent provideVolumeComponent( VolumeDialogComponent volumeDialogComponent); + + /** + */ + @Binds + public abstract RingerModeTracker provideRingerModeTracker( + RingerModeTrackerImpl ringerModeTrackerImpl); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java index c16dce12041d..3f88f252bfe7 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java @@ -40,7 +40,7 @@ public class DozeDockHandler implements DozeMachine.Part { private int mDockState = DockManager.STATE_NONE; - public DozeDockHandler(AmbientDisplayConfiguration config, DozeMachine machine, + DozeDockHandler(AmbientDisplayConfiguration config, DozeMachine machine, DockManager dockManager) { mMachine = machine; mConfig = config; @@ -74,8 +74,13 @@ public class DozeDockHandler implements DozeMachine.Part { @Override public void onEvent(int dockState) { if (DEBUG) Log.d(TAG, "dock event = " + dockState); - final DozeMachine.State nextState; + mDockState = dockState; + if (isPulsing()) { + return; + } + + DozeMachine.State nextState; switch (mDockState) { case DockManager.STATE_DOCKED: nextState = State.DOZE_AOD_DOCKED; @@ -90,10 +95,15 @@ public class DozeDockHandler implements DozeMachine.Part { default: return; } - mMachine.requestState(nextState); } + private boolean isPulsing() { + DozeMachine.State state = mMachine.getState(); + return state == State.DOZE_REQUEST_PULSE || state == State.DOZE_PULSING + || state == State.DOZE_PULSING_BRIGHT; + } + void register() { if (mRegistered) { return; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index f7f9afdd2928..18bfd899a4e7 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -339,8 +339,8 @@ public class DozeMachine { return State.DOZE; } if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING - || mState == State.DOZE_AOD || mState == State.DOZE) - && requestedState == State.DOZE_PULSE_DONE) { + || mState == State.DOZE_AOD || mState == State.DOZE + || mState == State.DOZE_AOD_DOCKED) && requestedState == State.DOZE_PULSE_DONE) { Log.i(TAG, "Dropping pulse done because current state is already done: " + mState); return mState; } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index fdd859373685..e6af36b2c86b 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -39,9 +39,11 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.UserInfo; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Color; +import android.graphics.Insets; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.ConnectivityManager; @@ -70,13 +72,22 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; +import android.view.WindowInsets; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; +import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ImageView.ScaleType; +import android.widget.ListPopupWindow; +import android.widget.ListView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; + import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.colorextraction.ColorExtractor; @@ -113,6 +124,7 @@ import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.EmergencyDialerConstants; +import com.android.systemui.util.RingerModeTracker; import com.android.systemui.util.leak.RotationUtils; import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolator; @@ -129,7 +141,8 @@ import javax.inject.Inject; public class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogInterface.OnShowListener, ConfigurationController.ConfigurationListener, - GlobalActionsPanelPlugin.Callbacks { + GlobalActionsPanelPlugin.Callbacks, + LifecycleOwner { public static final String SYSTEM_DIALOG_REASON_KEY = "reason"; public static final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; @@ -141,19 +154,20 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, /* Valid settings for global actions keys. * see config.xml config_globalActionList */ - private static final String GLOBAL_ACTION_KEY_POWER = "power"; - private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane"; - private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport"; - private static final String GLOBAL_ACTION_KEY_SILENT = "silent"; - private static final String GLOBAL_ACTION_KEY_USERS = "users"; - private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings"; - private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown"; - private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist"; - private static final String GLOBAL_ACTION_KEY_ASSIST = "assist"; - private static final String GLOBAL_ACTION_KEY_RESTART = "restart"; - private static final String GLOBAL_ACTION_KEY_LOGOUT = "logout"; - private static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency"; - private static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot"; + @VisibleForTesting + protected static final String GLOBAL_ACTION_KEY_POWER = "power"; + protected static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane"; + protected static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport"; + protected static final String GLOBAL_ACTION_KEY_SILENT = "silent"; + protected static final String GLOBAL_ACTION_KEY_USERS = "users"; + protected static final String GLOBAL_ACTION_KEY_SETTINGS = "settings"; + protected static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown"; + protected static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist"; + protected static final String GLOBAL_ACTION_KEY_ASSIST = "assist"; + protected static final String GLOBAL_ACTION_KEY_RESTART = "restart"; + protected static final String GLOBAL_ACTION_KEY_LOGOUT = "logout"; + protected static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency"; + protected static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot"; private static final String PREFS_CONTROLS_SEEDING_COMPLETED = "ControlsSeedingCompleted"; private static final String PREFS_CONTROLS_FILE = "controls_prefs"; @@ -178,17 +192,25 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final NotificationShadeDepthController mDepthController; private final BlurUtils mBlurUtils; - private ArrayList<Action> mItems; + // Used for RingerModeTracker + private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this); + + @VisibleForTesting + protected ArrayList<Action> mItems; + @VisibleForTesting + protected ArrayList<Action> mOverflowItems; + private ActionsDialog mDialog; private Action mSilentModeAction; private ToggleAction mAirplaneModeOn; private MyAdapter mAdapter; + private MyOverflowAdapter mOverflowAdapter; private boolean mKeyguardShowing = false; private boolean mDeviceProvisioned = false; - private ToggleAction.State mAirplaneState = ToggleAction.State.Off; + private ToggleState mAirplaneState = ToggleState.Off; private boolean mIsWaitingForEcmExit = false; private boolean mHasTelephony; private boolean mHasVibrator; @@ -205,12 +227,31 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final IWindowManager mIWindowManager; private final Executor mBackgroundExecutor; private final ControlsListingController mControlsListingController; - private boolean mAnyControlsProviders = false; + private List<ControlsServiceInfo> mControlsServiceInfos = new ArrayList<>(); + private ControlsController mControlsController; + private SharedPreferences mControlsPreferences; + private final RingerModeTracker mRingerModeTracker; + private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms @VisibleForTesting public enum GlobalActionsEvent implements UiEventLogger.UiEventEnum { @UiEvent(doc = "The global actions / power menu surface became visible on the screen.") - GA_POWER_MENU_OPEN(337); + GA_POWER_MENU_OPEN(337), + + @UiEvent(doc = "The global actions bugreport button was pressed.") + GA_BUGREPORT_PRESS(344), + + @UiEvent(doc = "The global actions bugreport button was long pressed.") + GA_BUGREPORT_LONG_PRESS(345), + + @UiEvent(doc = "The global actions emergency button was pressed.") + GA_EMERGENCY_DIALER_PRESS(346), + + @UiEvent(doc = "The global actions screenshot button was pressed.") + GA_SCREENSHOT_PRESS(347), + + @UiEvent(doc = "The global actions screenshot button was long pressed.") + GA_SCREENSHOT_LONG_PRESS(348); private final int mId; @@ -244,7 +285,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, ControlsUiController controlsUiController, IWindowManager iWindowManager, @Background Executor backgroundExecutor, ControlsListingController controlsListingController, - ControlsController controlsController, UiEventLogger uiEventLogger) { + ControlsController controlsController, UiEventLogger uiEventLogger, + RingerModeTracker ringerModeTracker) { mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme); mWindowManagerFuncs = windowManagerFuncs; mAudioManager = audioManager; @@ -271,6 +313,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mBackgroundExecutor = backgroundExecutor; mControlsListingController = controlsListingController; mBlurUtils = blurUtils; + mRingerModeTracker = ringerModeTracker; + mControlsController = controlsController; // receive broadcasts IntentFilter filter = new IntentFilter(); @@ -290,6 +334,11 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mShowSilentToggle = SHOW_SILENT_TOGGLE && !resources.getBoolean( R.bool.config_useFixedVolume); + if (mShowSilentToggle) { + mRingerModeTracker.getRingerMode().observe(this, ringer -> + mHandler.sendEmptyMessage(MESSAGE_REFRESH) + ); + } mEmergencyAffordanceManager = new EmergencyAffordanceManager(context); mScreenshotHelper = new ScreenshotHelper(context); @@ -309,45 +358,54 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } }); - String preferredControlsPackage = mContext.getResources() - .getString(com.android.systemui.R.string.config_controlsPreferredPackage); mControlsListingController.addCallback(list -> { - mAnyControlsProviders = !list.isEmpty(); - - /* - * See if any service providers match the preferred component. If they do, - * and there are no current favorites, and we haven't successfully loaded favorites to - * date, query the preferred component for a limited number of suggested controls. - */ - ComponentName preferredComponent = null; - for (ControlsServiceInfo info : list) { - if (info.componentName.getPackageName().equals(preferredControlsPackage)) { - preferredComponent = info.componentName; - break; - } - } + mControlsServiceInfos = list; + }); - if (preferredComponent == null) return; + // Need to be user-specific with the context to make sure we read the correct prefs + Context userContext = context.createContextAsUser( + new UserHandle(mUserManager.getUserHandle()), 0); + mControlsPreferences = userContext.getSharedPreferences(PREFS_CONTROLS_FILE, + Context.MODE_PRIVATE); - SharedPreferences prefs = context.getSharedPreferences(PREFS_CONTROLS_FILE, - Context.MODE_PRIVATE); - boolean isSeeded = prefs.getBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, false); - boolean hasFavorites = controlsController.getFavorites().size() > 0; - if (!isSeeded && !hasFavorites) { - controlsController.seedFavoritesForComponent( - preferredComponent, - (accepted) -> { - Log.i(TAG, "Controls seeded: " + accepted); - prefs.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, - accepted).apply(); - } - ); - } - }); } + private void seedFavorites() { + if (mControlsServiceInfos.isEmpty() + || mControlsController.getFavorites().size() > 0 + || mControlsPreferences.getBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, false)) { + return; + } + + /* + * See if any service providers match the preferred component. If they do, + * and there are no current favorites, and we haven't successfully loaded favorites to + * date, query the preferred component for a limited number of suggested controls. + */ + String preferredControlsPackage = mContext.getResources() + .getString(com.android.systemui.R.string.config_controlsPreferredPackage); + + ComponentName preferredComponent = null; + for (ControlsServiceInfo info : mControlsServiceInfos) { + if (info.componentName.getPackageName().equals(preferredControlsPackage)) { + preferredComponent = info.componentName; + break; + } + } + if (preferredComponent == null) { + Log.i(TAG, "Controls seeding: No preferred component has been set, will not seed"); + mControlsPreferences.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, true).apply(); + } + mControlsController.seedFavoritesForComponent( + preferredComponent, + (accepted) -> { + Log.i(TAG, "Controls seeded: " + accepted); + mControlsPreferences.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, + accepted).apply(); + }); + } /** * Show the global actions dialog (creating if necessary) @@ -393,6 +451,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, awakenIfNecessary(); mDialog = createDialog(); prepareDialog(); + seedFavorites(); // If we only have 1 item and it's a simple press action, just do this action. if (mAdapter.getCount() == 1 @@ -409,12 +468,51 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } + @VisibleForTesting + protected boolean shouldShowAction(Action action) { + if (mKeyguardShowing && !action.showDuringKeyguard()) { + return false; + } + if (!mDeviceProvisioned && !action.showBeforeProvisioning()) { + return false; + } + return true; + } + /** - * Create the global actions dialog. - * - * @return A new dialog. + * Returns the maximum number of power menu items to show based on which GlobalActions + * layout is being used. */ - private ActionsDialog createDialog() { + @VisibleForTesting + protected int getMaxShownPowerItems() { + if (shouldShowControls()) { + return mResources.getInteger(com.android.systemui.R.integer.power_menu_max_columns); + } else { + return Integer.MAX_VALUE; + } + } + + /** + * Add a power menu action item for to either the main or overflow items lists, depending on + * whether controls are enabled and whether the max number of shown items has been reached. + */ + private void addActionItem(Action action) { + if (mItems != null && shouldShowAction(action)) { + if (mItems.size() < getMaxShownPowerItems()) { + mItems.add(action); + } else if (mOverflowItems != null) { + mOverflowItems.add(action); + } + } + } + + @VisibleForTesting + protected String[] getDefaultActions() { + return mResources.getStringArray(R.array.config_globalActionsList); + } + + @VisibleForTesting + protected void createActionItems() { // Simple toggle style if there's no vibrator, otherwise use a tri-state if (!mHasVibrator) { mSilentModeAction = new SilentModeToggleAction(); @@ -425,7 +523,13 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, onAirplaneModeChanged(); mItems = new ArrayList<Action>(); - String[] defaultActions = mResources.getStringArray(R.array.config_globalActionsList); + mOverflowItems = new ArrayList<Action>(); + String[] defaultActions = getDefaultActions(); + + // make sure emergency affordance action is first, if needed + if (mEmergencyAffordanceManager.needsEmergencyAffordance()) { + addActionItem(new EmergencyAffordanceAction()); + } ArraySet<String> addedKeys = new ArraySet<String>(); for (int i = 0; i < defaultActions.length; i++) { @@ -435,46 +539,46 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, continue; } if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) { - mItems.add(new PowerAction()); + addActionItem(new PowerAction()); } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) { - mItems.add(mAirplaneModeOn); + addActionItem(mAirplaneModeOn); } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) { if (Settings.Global.getInt(mContentResolver, Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) { - mItems.add(new BugReportAction()); + addActionItem(new BugReportAction()); } } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) { if (mShowSilentToggle) { - mItems.add(mSilentModeAction); + addActionItem(mSilentModeAction); } } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) { if (SystemProperties.getBoolean("fw.power_user_switcher", false)) { - addUsersToMenu(mItems); + addUsersToMenu(); } } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) { - mItems.add(getSettingsAction()); + addActionItem(getSettingsAction()); } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) { if (Settings.Secure.getIntForUser(mContentResolver, Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0, getCurrentUser().id) != 0 && shouldDisplayLockdown()) { - mItems.add(getLockdownAction()); + addActionItem(getLockdownAction()); } } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) { - mItems.add(getVoiceAssistAction()); + addActionItem(getVoiceAssistAction()); } else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) { - mItems.add(getAssistAction()); + addActionItem(getAssistAction()); } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) { - mItems.add(new RestartAction()); + addActionItem(new RestartAction()); } else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) { - mItems.add(new ScreenshotAction()); + addActionItem(new ScreenshotAction()); } else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) { if (mDevicePolicyManager.isLogoutEnabled() && getCurrentUser().id != UserHandle.USER_SYSTEM) { - mItems.add(new LogoutAction()); + addActionItem(new LogoutAction()); } } else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) { if (!mEmergencyAffordanceManager.needsEmergencyAffordance()) { - mItems.add(new EmergencyDialerAction()); + addActionItem(new EmergencyDialerAction()); } } else { Log.e(TAG, "Invalid global action key " + actionKey); @@ -482,16 +586,23 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, // Add here so we don't add more than one. addedKeys.add(actionKey); } + } - if (mEmergencyAffordanceManager.needsEmergencyAffordance()) { - mItems.add(new EmergencyAffordanceAction()); - } + /** + * Create the global actions dialog. + * + * @return A new dialog. + */ + private ActionsDialog createDialog() { + createActionItems(); mAdapter = new MyAdapter(); + mOverflowAdapter = new MyOverflowAdapter(); - ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, getWalletPanelViewController(), - mDepthController, mSysuiColorExtractor, mStatusBarService, - mNotificationShadeWindowController, + mDepthController.setShowingHomeControls(shouldShowControls()); + ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, mOverflowAdapter, + getWalletPanelViewController(), mDepthController, mSysuiColorExtractor, + mStatusBarService, mNotificationShadeWindowController, shouldShowControls() ? mControlsUiController : null, mBlurUtils); dialog.setCanceledOnTouchOutside(false); // Handled by the custom class. dialog.setKeyguardShowing(mKeyguardShowing); @@ -593,7 +704,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, @Override public boolean shouldBeSeparated() { - return true; + return !shouldShowControls(); } @Override @@ -601,7 +712,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { View v = super.create(context, convertView, parent, inflater); int textColor; - if (shouldBeSeparated()) { + if (shouldShowControls()) { + v.setBackgroundTintList(ColorStateList.valueOf(v.getResources().getColor( + com.android.systemui.R.color.global_actions_emergency_background))); + textColor = v.getResources().getColor( + com.android.systemui.R.color.global_actions_emergency_text); + } else if (shouldBeSeparated()) { textColor = v.getResources().getColor( com.android.systemui.R.color.global_actions_alert_text); } else { @@ -611,7 +727,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, TextView messageView = v.findViewById(R.id.message); messageView.setTextColor(textColor); messageView.setSelected(true); // necessary for marquee to work - ImageView icon = (ImageView) v.findViewById(R.id.icon); + ImageView icon = v.findViewById(R.id.icon); icon.getDrawable().setTint(textColor); return v; } @@ -639,7 +755,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } - private class EmergencyDialerAction extends EmergencyAction { + @VisibleForTesting + class EmergencyDialerAction extends EmergencyAction { private EmergencyDialerAction() { super(com.android.systemui.R.drawable.ic_emergency_star, R.string.global_action_emergency); @@ -648,6 +765,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, @Override public void onPress() { mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_DIALER_FROM_POWER_MENU); + mUiEventLogger.log(GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS); if (mTelecomManager != null) { Intent intent = mTelecomManager.createLaunchEmergencyDialerIntent( null /* number */); @@ -661,6 +779,11 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } + @VisibleForTesting + EmergencyDialerAction makeEmergencyDialerActionForTesting() { + return new EmergencyDialerAction(); + } + private final class RestartAction extends SinglePressAction implements LongPressAction { private RestartAction() { super(R.drawable.ic_restart, R.string.global_action_restart); @@ -691,7 +814,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } - private class ScreenshotAction extends SinglePressAction implements LongPressAction { + @VisibleForTesting + class ScreenshotAction extends SinglePressAction implements LongPressAction { public ScreenshotAction() { super(R.drawable.ic_screenshot, R.string.global_action_screenshot); } @@ -707,8 +831,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, public void run() { mScreenshotHelper.takeScreenshot(1, true, true, mHandler, null); mMetricsLogger.action(MetricsEvent.ACTION_SCREENSHOT_POWER_MENU); + mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_PRESS); } - }, 500); + }, mDialogPressDelay); } @Override @@ -724,6 +849,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, @Override public boolean onLongPress() { if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SCREENRECORD_LONG_PRESS)) { + mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS); mScreenRecordHelper.launchRecordPrompt(); } else { onPress(); @@ -732,7 +858,13 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } - private class BugReportAction extends SinglePressAction implements LongPressAction { + @VisibleForTesting + ScreenshotAction makeScreenshotActionForTesting() { + return new ScreenshotAction(); + } + + @VisibleForTesting + class BugReportAction extends SinglePressAction implements LongPressAction { public BugReportAction() { super(R.drawable.ic_lock_bugreport, R.string.bugreport_title); @@ -755,6 +887,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, // Take an "interactive" bugreport. mMetricsLogger.action( MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE); + mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_PRESS); if (!mIActivityManager.launchBugReportHandlerApp()) { Log.w(TAG, "Bugreport handler could not be launched"); mIActivityManager.requestInteractiveBugReport(); @@ -762,7 +895,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } catch (RemoteException e) { } } - }, 500); + }, mDialogPressDelay); } @Override @@ -775,6 +908,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, try { // Take a "full" bugreport. mMetricsLogger.action(MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL); + mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS); mIActivityManager.requestFullBugReport(); } catch (RemoteException e) { } @@ -791,6 +925,11 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } + @VisibleForTesting + BugReportAction makeBugReportActionForTesting() { + return new BugReportAction(); + } + private final class LogoutAction extends SinglePressAction { private LogoutAction() { super(R.drawable.ic_logout, R.string.global_action_logout); @@ -818,7 +957,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } catch (RemoteException re) { Log.e(TAG, "Couldn't logout user " + re); } - }, 500); + }, mDialogPressDelay); } } @@ -941,7 +1080,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, return currentUser == null || currentUser.isPrimary(); } - private void addUsersToMenu(ArrayList<Action> items) { + private void addUsersToMenu() { if (mUserManager.isUserSwitcherEnabled()) { List<UserInfo> users = mUserManager.getUsers(); UserInfo currentUser = getCurrentUser(); @@ -971,7 +1110,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, return false; } }; - items.add(switchToUser); + addActionItem(switchToUser); } } } @@ -981,18 +1120,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, refreshSilentMode(); mAirplaneModeOn.updateState(mAirplaneState); mAdapter.notifyDataSetChanged(); - if (mShowSilentToggle) { - IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION); - mBroadcastDispatcher.registerReceiver(mRingerModeReceiver, filter); - } + mLifecycle.setCurrentState(Lifecycle.State.RESUMED); } private void refreshSilentMode() { if (!mHasVibrator) { - final boolean silentModeOn = - mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; + Integer value = mRingerModeTracker.getRingerMode().getValue(); + final boolean silentModeOn = value != null && value != AudioManager.RINGER_MODE_NORMAL; ((ToggleAction) mSilentModeAction).updateState( - silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off); + silentModeOn ? ToggleState.On : ToggleState.Off); } } @@ -1004,14 +1140,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mDialog = null; } mWindowManagerFuncs.onGlobalActionsHidden(); - if (mShowSilentToggle) { - try { - mBroadcastDispatcher.unregisterReceiver(mRingerModeReceiver); - } catch (IllegalArgumentException ie) { - // ignore this - Log.w(TAG, ie); - } - } + mLifecycle.setCurrentState(Lifecycle.State.DESTROYED); } /** @@ -1022,12 +1151,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mUiEventLogger.log(GlobalActionsEvent.GA_POWER_MENU_OPEN); } + private int getActionLayoutId() { + if (shouldShowControls()) { + return com.android.systemui.R.layout.global_actions_grid_item_v2; + } + return com.android.systemui.R.layout.global_actions_grid_item; + } + /** - * The adapter used for the list within the global actions dialog, taking into account whether - * the keyguard is showing via - * {@link com.android.systemui.globalactions.GlobalActionsDialog#mKeyguardShowing} - * and whether the device is provisioned via - * {@link com.android.systemui.globalactions.GlobalActionsDialog#mDeviceProvisioned}. + * The adapter used for power menu items shown in the global actions dialog. */ public class MyAdapter extends MultiListAdapter { private int countItems(boolean separated) { @@ -1035,23 +1167,13 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, for (int i = 0; i < mItems.size(); i++) { final Action action = mItems.get(i); - if (shouldBeShown(action) && action.shouldBeSeparated() == separated) { + if (action.shouldBeSeparated() == separated) { count++; } } return count; } - private boolean shouldBeShown(Action action) { - if (mKeyguardShowing && !action.showDuringKeyguard()) { - return false; - } - if (!mDeviceProvisioned && !action.showBeforeProvisioning()) { - return false; - } - return true; - } - @Override public int countSeparatedItems() { return countItems(true); @@ -1082,7 +1204,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, int filteredPos = 0; for (int i = 0; i < mItems.size(); i++) { final Action action = mItems.get(i); - if (!shouldBeShown(action)) { + if (!shouldShowAction(action)) { continue; } if (filteredPos == position) { @@ -1147,6 +1269,79 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } + /** + * The adapter used for items in the overflow menu. + */ + public class MyOverflowAdapter extends BaseAdapter { + @Override + public int getCount() { + return mOverflowItems != null ? mOverflowItems.size() : 0; + } + + @Override + public Action getItem(int position) { + return mOverflowItems != null ? mOverflowItems.get(position) : null; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Action action = getItem(position); + if (action == null) { + Log.w(TAG, "No overflow action found at position: " + position); + return null; + } + int viewLayoutResource = com.android.systemui.R.layout.controls_more_item; + View view = convertView != null ? convertView + : LayoutInflater.from(mContext).inflate(viewLayoutResource, parent, false); + TextView textView = (TextView) view; + textView.setOnClickListener(v -> onClickItem(position)); + if (action.getMessageResId() != 0) { + textView.setText(action.getMessageResId()); + } else { + textView.setText(action.getMessage()); + } + + if (action instanceof LongPressAction) { + textView.setOnLongClickListener(v -> onLongClickItem(position)); + } else { + textView.setOnLongClickListener(null); + } + return textView; + } + + private boolean onLongClickItem(int position) { + final Action action = getItem(position); + if (action instanceof LongPressAction) { + if (mDialog != null) { + mDialog.hidePowerOverflowMenu(); + mDialog.dismiss(); + } else { + Log.w(TAG, "Action long-clicked while mDialog is null."); + } + return ((LongPressAction) action).onLongPress(); + } + return false; + } + + private void onClickItem(int position) { + Action item = getItem(position); + if (!(item instanceof SilentModeTriStateAction)) { + if (mDialog != null) { + mDialog.hidePowerOverflowMenu(); + mDialog.dismiss(); + } else { + Log.w(TAG, "Action clicked while mDialog is null."); + } + item.onPress(); + } + } + } + // note: the scheme below made more sense when we were planning on having // 8 different things in the global actions dialog. seems overkill with // only 3 items now, but may as well keep this flexible approach so it will @@ -1172,8 +1367,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, boolean showDuringKeyguard(); /** - * @return whether this action should appear in the dialog before the device is - * provisioned.onlongpress + * @return whether this action should appear in the dialog before the + * device is provisioned.f */ boolean showBeforeProvisioning(); @@ -1182,6 +1377,18 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, default boolean shouldBeSeparated() { return false; } + + /** + * Return the id of the message associated with this action, or 0 if it doesn't have one. + * @return + */ + int getMessageResId(); + + /** + * Return the message associated with this action, or null if it doesn't have one. + * @return + */ + CharSequence getMessage(); } /** @@ -1233,20 +1440,21 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } - protected int getActionLayoutId(Context context) { - if (shouldShowControls()) { - return com.android.systemui.R.layout.global_actions_grid_item_v2; - } - return com.android.systemui.R.layout.global_actions_grid_item; + + public int getMessageResId() { + return mMessageResId; + } + + public CharSequence getMessage() { + return mMessage; } public View create( Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { - View v = inflater.inflate(getActionLayoutId(context), parent, - false); + View v = inflater.inflate(getActionLayoutId(), parent, false /* attach */); - ImageView icon = (ImageView) v.findViewById(R.id.icon); - TextView messageView = (TextView) v.findViewById(R.id.message); + ImageView icon = v.findViewById(R.id.icon); + TextView messageView = v.findViewById(R.id.message); messageView.setSelected(true); // necessary for marquee to work if (mIcon != null) { @@ -1265,30 +1473,30 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } - /** - * A toggle action knows whether it is on or off, and displays an icon and status message - * accordingly. - */ - private static abstract class ToggleAction implements Action { - - enum State { - Off(false), - TurningOn(true), - TurningOff(true), - On(false); + private enum ToggleState { + Off(false), + TurningOn(true), + TurningOff(true), + On(false); - private final boolean inTransition; + private final boolean mInTransition; - State(boolean intermediate) { - inTransition = intermediate; - } + ToggleState(boolean intermediate) { + mInTransition = intermediate; + } - public boolean inTransition() { - return inTransition; - } + public boolean inTransition() { + return mInTransition; } + } + + /** + * A toggle action knows whether it is on or off, and displays an icon and status message + * accordingly. + */ + private abstract class ToggleAction implements Action { - protected State mState = State.Off; + protected ToggleState mState = ToggleState.Off; // prefs protected int mEnabledIconResId; @@ -1328,27 +1536,41 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, return context.getString(mMessageResId); } + private boolean isOn() { + return mState == ToggleState.On || mState == ToggleState.TurningOn; + } + + @Override + public CharSequence getMessage() { + return null; + } + @Override + public int getMessageResId() { + return isOn() ? mEnabledStatusMessageResId : mDisabledStatusMessageResId; + } + + private int getIconResId() { + return isOn() ? mEnabledIconResId : mDisabledIconResid; + } + public View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { willCreate(); - View v = inflater.inflate(com.android.systemui.R - .layout.global_actions_grid_item, parent, false); + View v = inflater.inflate(getActionLayoutId(), parent, false /* attach */); ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); final boolean enabled = isEnabled(); - boolean on = ((mState == State.On) || (mState == State.TurningOn)); if (messageView != null) { - messageView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId); + messageView.setText(getMessageResId()); messageView.setEnabled(enabled); messageView.setSelected(true); // necessary for marquee to work } if (icon != null) { - icon.setImageDrawable(context.getDrawable( - (on ? mEnabledIconResId : mDisabledIconResid))); + icon.setImageDrawable(context.getDrawable(getIconResId())); icon.setEnabled(enabled); } @@ -1363,7 +1585,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, return; } - final boolean nowOn = !(mState == State.On); + final boolean nowOn = !(mState == ToggleState.On); onToggle(nowOn); changeStateFromPress(nowOn); } @@ -1380,12 +1602,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, * @param buttonOn Whether the button was turned on or off */ protected void changeStateFromPress(boolean buttonOn) { - mState = buttonOn ? State.On : State.Off; + mState = buttonOn ? ToggleState.On : ToggleState.Off; } abstract void onToggle(boolean on); - public void updateState(State state) { + public void updateState(ToggleState state) { mState = state; } } @@ -1419,7 +1641,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, // In ECM mode airplane state cannot be changed if (!TelephonyProperties.in_ecm_mode().orElse(false)) { - mState = buttonOn ? State.TurningOn : State.TurningOff; + mState = buttonOn ? ToggleState.TurningOn : ToggleState.TurningOff; mAirplaneState = mState; } } @@ -1486,6 +1708,16 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, return null; } + @Override + public int getMessageResId() { + return 0; + } + + @Override + public CharSequence getMessage() { + return null; + } + public View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false); @@ -1554,21 +1786,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, public void onServiceStateChanged(ServiceState serviceState) { if (!mHasTelephony) return; final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF; - mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off; + mAirplaneState = inAirplaneMode ? ToggleState.On : ToggleState.Off; mAirplaneModeOn.updateState(mAirplaneState); mAdapter.notifyDataSetChanged(); } }; - private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { - mHandler.sendEmptyMessage(MESSAGE_REFRESH); - } - } - }; - private ContentObserver mAirplaneModeObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { @@ -1580,6 +1803,11 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private static final int MESSAGE_REFRESH = 1; private static final int MESSAGE_SHOW = 2; private static final int DIALOG_DISMISS_DELAY = 300; // ms + private static final int DIALOG_PRESS_DELAY = 850; // ms + + @VisibleForTesting void setZeroDialogPressDelayForTesting() { + mDialogPressDelay = 0; // ms + } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { @@ -1613,7 +1841,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mContentResolver, Settings.Global.AIRPLANE_MODE_ON, 0) == 1; - mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off; + mAirplaneState = airplaneModeOn ? ToggleState.On : ToggleState.Off; mAirplaneModeOn.updateState(mAirplaneState); } @@ -1630,15 +1858,22 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, intent.putExtra("state", on); mContext.sendBroadcastAsUser(intent, UserHandle.ALL); if (!mHasTelephony) { - mAirplaneState = on ? ToggleAction.State.On : ToggleAction.State.Off; + mAirplaneState = on ? ToggleState.On : ToggleState.Off; } } + @NonNull + @Override + public Lifecycle getLifecycle() { + return mLifecycle; + } + private static final class ActionsDialog extends Dialog implements DialogInterface, ColorExtractor.OnColorsChangedListener { private final Context mContext; private final MyAdapter mAdapter; + private final MyOverflowAdapter mOverflowAdapter; private final IStatusBarService mStatusBarService; private final IBinder mToken = new Binder(); private MultiListLayout mGlobalActionsLayout; @@ -1653,11 +1888,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final NotificationShadeWindowController mNotificationShadeWindowController; private final NotificationShadeDepthController mDepthController; private final BlurUtils mBlurUtils; + private ListPopupWindow mOverflowPopup; private ControlsUiController mControlsUiController; private ViewGroup mControlsView; - ActionsDialog(Context context, MyAdapter adapter, + ActionsDialog(Context context, MyAdapter adapter, MyOverflowAdapter overflowAdapter, GlobalActionsPanelPlugin.PanelViewController plugin, NotificationShadeDepthController depthController, SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService, @@ -1666,6 +1902,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions); mContext = context; mAdapter = adapter; + mOverflowAdapter = overflowAdapter; mDepthController = depthController; mColorExtractor = sysuiColorExtractor; mStatusBarService = statusBarService; @@ -1748,6 +1985,45 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } + private ListPopupWindow createPowerOverflowPopup() { + ListPopupWindow popup = new ListPopupWindow(new ContextThemeWrapper( + mContext, com.android.systemui.R.style.Control_ListPopupWindow)); + popup.setWindowLayoutType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); + View overflowButton = + findViewById(com.android.systemui.R.id.global_actions_overflow_button); + popup.setAnchorView(overflowButton); + int parentWidth = mGlobalActionsLayout.getWidth(); + // arbitrarily set the menu width to half of parent + // TODO: Logic for menu sizing based on contents. + int halfParentWidth = Math.round(parentWidth * 0.5f); + popup.setContentWidth(halfParentWidth); + popup.setAdapter(mOverflowAdapter); + popup.setModal(true); + return popup; + } + + private void showPowerOverflowMenu() { + mOverflowPopup.show(); + + // Width is fixed to slightly more than half of the GlobalActionsLayout container. + // TODO: Resize the width of this dialog based on the sizes of the items in it. + int width = Math.round(mGlobalActionsLayout.getWidth() * 0.6f); + + ListView listView = mOverflowPopup.getListView(); + listView.setDividerHeight(mContext.getResources() + .getDimensionPixelSize(com.android.systemui.R.dimen.control_list_divider)); + listView.setDivider(mContext.getResources().getDrawable( + com.android.systemui.R.drawable.controls_list_divider)); + mOverflowPopup.setWidth(width); + mOverflowPopup.setHorizontalOffset(-width + mOverflowPopup.getAnchorView().getWidth()); + mOverflowPopup.setVerticalOffset(mOverflowPopup.getAnchorView().getHeight()); + mOverflowPopup.show(); + } + + private void hidePowerOverflowMenu() { + mOverflowPopup.dismiss(); + } + private void initializeLayout() { setContentView(getGlobalActionsLayoutId(mContext)); fixNavBarClipping(); @@ -1766,6 +2042,18 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mGlobalActionsLayout.setRotationListener(this::onRotate); mGlobalActionsLayout.setAdapter(mAdapter); + mOverflowPopup = createPowerOverflowPopup(); + + View overflowButton = findViewById( + com.android.systemui.R.id.global_actions_overflow_button); + if (overflowButton != null) { + if (mOverflowAdapter.getCount() > 0) { + overflowButton.setOnClickListener((view) -> showPowerOverflowMenu()); + } else { + overflowButton.setVisibility(View.GONE); + } + } + View globalActionsParent = (View) mGlobalActionsLayout.getParent(); globalActionsParent.setOnClickListener(v -> dismiss()); @@ -1780,8 +2068,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } if (mBackgroundDrawable == null) { mBackgroundDrawable = new ScrimDrawable(); - mScrimAlpha = mBlurUtils.supportsBlursOnWindows() - ? ScrimController.BLUR_SCRIM_ALPHA : ScrimController.BUSY_SCRIM_ALPHA; + if (mControlsUiController != null) { + mScrimAlpha = 1.0f; + } else { + mScrimAlpha = mBlurUtils.supportsBlursOnWindows() + ? ScrimController.BLUR_SCRIM_ALPHA : ScrimController.BUSY_SCRIM_ALPHA; + } } getWindow().setBackgroundDrawable(mBackgroundDrawable); } @@ -1841,8 +2133,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, if (!(mBackgroundDrawable instanceof ScrimDrawable)) { return; } - ((ScrimDrawable) mBackgroundDrawable).setColor(colors.supportsDarkText() ? Color.WHITE - : Color.BLACK, animate); + boolean hasControls = mControlsUiController != null; + ((ScrimDrawable) mBackgroundDrawable).setColor( + !hasControls && colors.supportsDarkText() ? Color.WHITE : Color.BLACK, animate); View decorView = getWindow().getDecorView(); if (colors.supportsDarkText()) { decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR | @@ -1882,6 +2175,14 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mGlobalActionsLayout); }) .start(); + ViewGroup root = (ViewGroup) mGlobalActionsLayout.getRootView(); + root.setOnApplyWindowInsetsListener((v, windowInsets) -> { + if (mControlsUiController != null) { + Insets insets = windowInsets.getInsets(WindowInsets.Type.all()); + root.setPadding(insets.left, insets.top, insets.right, insets.bottom); + } + return WindowInsets.CONSUMED; + }); if (mControlsUiController != null) { mControlsUiController.show(mControlsView); } @@ -2008,9 +2309,10 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, return isPanelDebugModeEnabled(context); } - private boolean shouldShowControls() { + @VisibleForTesting + protected boolean shouldShowControls() { return mKeyguardStateController.isUnlocked() && mControlsUiController.getAvailable() - && mAnyControlsProviders; + && !mControlsServiceInfos.isEmpty(); } -} +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java index f1025615783b..2f32d972449e 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsFlatLayout.java @@ -32,7 +32,6 @@ import com.android.systemui.R; * Flat, single-row implementation of the button layout created by the global actions dialog. */ public class GlobalActionsFlatLayout extends GlobalActionsLayout { - private static final int MAX_ITEMS = 4; public GlobalActionsFlatLayout(Context context, AttributeSet attrs) { super(context, attrs); } @@ -54,11 +53,28 @@ public class GlobalActionsFlatLayout extends GlobalActionsLayout { return null; } + private View getOverflowButton() { + return findViewById(com.android.systemui.R.id.global_actions_overflow_button); + } + @Override protected void addToListView(View v, boolean reverse) { - // only add items to the list view if we haven't hit our max yet - if (getListView().getChildCount() < MAX_ITEMS) { - super.addToListView(v, reverse); + super.addToListView(v, reverse); + View overflowButton = getOverflowButton(); + // if there's an overflow button, make sure it stays at the end + if (overflowButton != null) { + getListView().removeView(overflowButton); + super.addToListView(overflowButton, reverse); + } + } + + @Override + protected void removeAllListViews() { + View overflowButton = getOverflowButton(); + super.removeAllListViews(); + // if there's an overflow button, add it back after clearing the list views + if (overflowButton != null) { + super.addToListView(overflowButton, false); } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 226ac16cf1f2..1012a5213a58 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -96,7 +96,6 @@ import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NavigationModeController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; -import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.InjectionInflationController; @@ -216,7 +215,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { private AlarmManager mAlarmManager; private AudioManager mAudioManager; private StatusBarManager mStatusBarManager; - private final NotificationShadeWindowController mNotificationShadeWindowController; private final Executor mUiBgExecutor; private boolean mSystemReady; @@ -628,7 +626,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { @Override public void keyguardGone() { Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardGone"); - mNotificationShadeWindowController.setKeyguardGoingAway(false); + mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false); mKeyguardDisplayManager.hide(); Trace.endSection(); } @@ -717,7 +715,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { FalsingManager falsingManager, LockPatternUtils lockPatternUtils, BroadcastDispatcher broadcastDispatcher, - NotificationShadeWindowController notificationShadeWindowController, Lazy<KeyguardViewController> statusBarKeyguardViewManagerLazy, DismissCallbackRegistry dismissCallbackRegistry, KeyguardUpdateMonitor keyguardUpdateMonitor, DumpManager dumpManager, @@ -729,7 +726,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { mFalsingManager = falsingManager; mLockPatternUtils = lockPatternUtils; mBroadcastDispatcher = broadcastDispatcher; - mNotificationShadeWindowController = notificationShadeWindowController; mKeyguardViewControllerLazy = statusBarKeyguardViewManagerLazy; mDismissCallbackRegistry = dismissCallbackRegistry; mUiBgExecutor = uiBgExecutor; @@ -877,7 +873,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { mGoingToSleep = true; // Reset keyguard going away state so we can start listening for fingerprint. We - // explicitly DO NOT want to call mStatusBarWindowController.setKeyguardGoingAway(false) + // explicitly DO NOT want to call + // mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false) // here, since that will mess with the device lock state. mUpdateMonitor.setKeyguardGoingAway(false); @@ -1861,7 +1858,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { adjustStatusBarLocked(); userActivity(); mUpdateMonitor.setKeyguardGoingAway(false); - mNotificationShadeWindowController.setKeyguardGoingAway(false); + mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false); mShowKeyguardWakeLock.release(); } mKeyguardDisplayManager.show(); @@ -1901,7 +1898,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { } mUpdateMonitor.setKeyguardGoingAway(true); - mNotificationShadeWindowController.setKeyguardGoingAway(true); + mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(true); // Don't actually hide the Keyguard at the moment, wait for window // manager until it tells us it's safe to do so with diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 7a63a5e406f6..83c95b77b716 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -30,7 +30,6 @@ import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.phone.NavigationModeController; -import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.DeviceConfigProxy; @@ -57,7 +56,6 @@ public class KeyguardModule { FalsingManager falsingManager, LockPatternUtils lockPatternUtils, BroadcastDispatcher broadcastDispatcher, - NotificationShadeWindowController notificationShadeWindowController, Lazy<KeyguardViewController> statusBarKeyguardViewManagerLazy, DismissCallbackRegistry dismissCallbackRegistry, KeyguardUpdateMonitor updateMonitor, @@ -72,7 +70,6 @@ public class KeyguardModule { falsingManager, lockPatternUtils, broadcastDispatcher, - notificationShadeWindowController, statusBarKeyguardViewManagerLazy, dismissCallbackRegistry, updateMonitor, diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 9873d240efe3..62efd8ce4cee 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -44,9 +44,11 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.Nullable; import androidx.core.graphics.drawable.RoundedBitmapDrawable; import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; +import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; import com.android.settingslib.media.MediaOutputSliceConstants; import com.android.settingslib.widget.AdaptiveIcon; @@ -66,6 +68,7 @@ import java.util.concurrent.Executor; public class MediaControlPanel { private static final String TAG = "MediaControlPanel"; private final NotificationMediaManager mMediaManager; + @Nullable private final LocalMediaManager mLocalMediaManager; private final Executor mForegroundExecutor; private final Executor mBackgroundExecutor; @@ -77,6 +80,7 @@ public class MediaControlPanel { private int mForegroundColor; private int mBackgroundColor; protected ComponentName mRecvComponent; + private MediaDevice mDevice; private boolean mIsRegistered = false; private final int[] mActionIds; @@ -121,19 +125,44 @@ public class MediaControlPanel { } }; + private final LocalMediaManager.DeviceCallback mDeviceCallback = + new LocalMediaManager.DeviceCallback() { + @Override + public void onDeviceListUpdate(List<MediaDevice> devices) { + if (mLocalMediaManager == null) { + return; + } + MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice(); + // Check because this can be called several times while changing devices + if (mDevice == null || !mDevice.equals(currentDevice)) { + mDevice = currentDevice; + updateDevice(mDevice); + } + } + + @Override + public void onSelectedDeviceStateChanged(MediaDevice device, int state) { + if (mDevice == null || !mDevice.equals(device)) { + mDevice = device; + updateDevice(mDevice); + } + } + }; + /** * Initialize a new control panel * @param context * @param parent * @param manager + * @param routeManager Manager used to listen for device change events. * @param layoutId layout resource to use for this control panel * @param actionIds resource IDs for action buttons in the layout * @param foregroundExecutor foreground executor * @param backgroundExecutor background executor, used for processing artwork */ public MediaControlPanel(Context context, ViewGroup parent, NotificationMediaManager manager, - @LayoutRes int layoutId, int[] actionIds, Executor foregroundExecutor, - Executor backgroundExecutor) { + @Nullable LocalMediaManager routeManager, @LayoutRes int layoutId, int[] actionIds, + Executor foregroundExecutor, Executor backgroundExecutor) { mContext = context; LayoutInflater inflater = LayoutInflater.from(mContext); mMediaNotifView = (LinearLayout) inflater.inflate(layoutId, parent, false); @@ -144,6 +173,7 @@ public class MediaControlPanel { // mStateListener to be unregistered in detach. mMediaNotifView.addOnAttachStateChangeListener(mStateListener); mMediaManager = manager; + mLocalMediaManager = routeManager; mActionIds = actionIds; mForegroundExecutor = foregroundExecutor; mBackgroundExecutor = backgroundExecutor; @@ -176,7 +206,7 @@ public class MediaControlPanel { * @param device */ public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, - int bgColor, PendingIntent contentIntent, String appNameString, MediaDevice device) { + int bgColor, PendingIntent contentIntent, String appNameString) { mToken = token; mForegroundColor = iconColor; mBackgroundColor = bgColor; @@ -253,9 +283,9 @@ public class MediaControlPanel { // Transfer chip mSeamless = mMediaNotifView.findViewById(R.id.media_seamless); - if (mSeamless != null) { + if (mSeamless != null && mLocalMediaManager != null) { mSeamless.setVisibility(View.VISIBLE); - updateDevice(device); + updateDevice(mLocalMediaManager.getCurrentConnectedDevice()); ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class); mSeamless.setOnClickListener(v -> { final Intent intent = new Intent() @@ -366,7 +396,7 @@ public class MediaControlPanel { * Update the current device information * @param device device information to display */ - public void updateDevice(MediaDevice device) { + private void updateDevice(MediaDevice device) { if (mSeamless == null) { return; } @@ -456,6 +486,10 @@ public class MediaControlPanel { Assert.isMainThread(); if (!mIsRegistered) { mMediaManager.addCallback(mMediaListener); + if (mLocalMediaManager != null) { + mLocalMediaManager.registerCallback(mDeviceCallback); + mLocalMediaManager.startScan(); + } mIsRegistered = true; } } @@ -463,6 +497,10 @@ public class MediaControlPanel { private void makeInactive() { Assert.isMainThread(); if (mIsRegistered) { + if (mLocalMediaManager != null) { + mLocalMediaManager.stopScan(); + mLocalMediaManager.unregisterCallback(mDeviceCallback); + } mMediaManager.removeCallback(mMediaListener); mIsRegistered = false; } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControllerFactory.java b/packages/SystemUI/src/com/android/systemui/media/MediaControllerFactory.java new file mode 100644 index 000000000000..71bc7c20c026 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControllerFactory.java @@ -0,0 +1,45 @@ +/* + * 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.media; + +import android.content.Context; +import android.media.session.MediaController; +import android.media.session.MediaSession; + +import javax.inject.Inject; + +/** + * Testable wrapper around {@link MediaController} constructor. + */ +public class MediaControllerFactory { + + private final Context mContext; + + @Inject + public MediaControllerFactory(Context context) { + mContext = context; + } + + /** + * Creates a new MediaController from a session's token. + * + * @param token The token for the session. This value must never be null. + */ + public MediaController create(MediaSession.Token token) { + return new MediaController(mContext, token); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt index aa5ebaa22f2d..b7658a9f178d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt @@ -46,19 +46,6 @@ class SeekBarObserver(view: View) : Observer<SeekBarViewModel.Progress> { /** Updates seek bar views when the data model changes. */ @UiThread override fun onChanged(data: SeekBarViewModel.Progress) { - if (data.enabled && seekBarView.visibility == View.GONE) { - seekBarView.visibility = View.VISIBLE - elapsedTimeView.visibility = View.VISIBLE - totalTimeView.visibility = View.VISIBLE - } else if (!data.enabled && seekBarView.visibility == View.VISIBLE) { - seekBarView.visibility = View.GONE - elapsedTimeView.visibility = View.GONE - totalTimeView.visibility = View.GONE - return - } - - // TODO: update the style of the disabled progress bar - seekBarView.setEnabled(data.seekAvailable) data.color?.let { var tintList = ColorStateList.valueOf(it) @@ -71,6 +58,17 @@ class SeekBarObserver(view: View) : Observer<SeekBarViewModel.Progress> { totalTimeView.setTextColor(it) } + if (!data.enabled) { + seekBarView.setEnabled(false) + seekBarView.getThumb().setAlpha(0) + elapsedTimeView.setText("") + totalTimeView.setText("") + return + } + + seekBarView.getThumb().setAlpha(if (data.seekAvailable) 255 else 0) + seekBarView.setEnabled(data.seekAvailable) + data.elapsedTime?.let { seekBarView.setProgress(it) elapsedTimeView.setText(DateUtils.formatElapsedTime( diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt index cf8f26841cf9..dd83e42cde2d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt @@ -34,8 +34,13 @@ private const val POSITION_UPDATE_INTERVAL_MILLIS = 100L /** ViewModel for seek bar in QS media player. */ class SeekBarViewModel(val bgExecutor: DelayableExecutor) { + private var _data = Progress(false, false, null, null, null) + set(value) { + field = value + _progress.postValue(value) + } private val _progress = MutableLiveData<Progress>().apply { - postValue(Progress(false, false, null, null, null)) + postValue(_data) } val progress: LiveData<Progress> get() = _progress @@ -73,7 +78,7 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) { val position = playbackState?.position?.toInt() val duration = mediaMetadata?.getLong(MediaMetadata.METADATA_KEY_DURATION)?.toInt() val enabled = if (duration != null && duration <= 0) false else true - _progress.postValue(Progress(enabled, seekAvailable, position, duration, color)) + _data = Progress(enabled, seekAvailable, position, duration, color) if (shouldPollPlaybackPosition()) { checkPlaybackPosition() } @@ -82,8 +87,8 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) { @AnyThread private fun checkPlaybackPosition(): Runnable = bgExecutor.executeDelayed({ val currentPosition = controller?.playbackState?.position?.toInt() - if (currentPosition != null && _progress.value!!.elapsedTime != currentPosition) { - _progress.postValue(_progress.value!!.copy(elapsedTime = currentPosition)) + if (currentPosition != null && _data.elapsedTime != currentPosition) { + _data = _data.copy(elapsedTime = currentPosition) } if (shouldPollPlaybackPosition()) { checkPlaybackPosition() diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java index d219a9e65a3c..dba43430b490 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java @@ -319,6 +319,7 @@ public class PipAnimationController { getSurfaceTransactionHelper() .crop(tx, leash, getDestinationBounds()) .round(tx, leash, shouldApplyCornerRadius()); + tx.show(leash); tx.apply(); } }; @@ -359,6 +360,7 @@ public class PipAnimationController { getSurfaceTransactionHelper() .alpha(tx, leash, 1f) .round(tx, leash, shouldApplyCornerRadius()); + tx.show(leash); tx.apply(); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java index 1868536dca98..e24d29f1aedf 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java @@ -231,7 +231,12 @@ public class PipBoundsHandler { /** * @return {@link Rect} of the destination PiP window bounds. */ - Rect getDestinationBounds(float aspectRatio, Rect bounds, Size minimalSize) { + Rect getDestinationBounds(ComponentName componentName, float aspectRatio, Rect bounds, + Size minimalSize) { + if (!componentName.equals(mLastPipComponentName)) { + onResetReentryBoundsUnchecked(); + mLastPipComponentName = componentName; + } final Rect destinationBounds; if (bounds == null) { final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize); @@ -246,11 +251,7 @@ public class PipBoundsHandler { transformBoundsToAspectRatio(destinationBounds, aspectRatio, false /* useCurrentMinEdgeSize */); } - if (destinationBounds.equals(bounds)) { - return bounds; - } mAspectRatio = aspectRatio; - onResetReentryBoundsUnchecked(); mLastDestinationBounds.set(destinationBounds); return destinationBounds; } @@ -483,6 +484,7 @@ public class PipBoundsHandler { pw.println(prefix + TAG); pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName); pw.println(innerPrefix + "mReentrySnapFraction=" + mReentrySnapFraction); + pw.println(innerPrefix + "mReentrySize=" + mReentrySize); pw.println(innerPrefix + "mDisplayInfo=" + mDisplayInfo); pw.println(innerPrefix + "mDefaultAspectRatio=" + mDefaultAspectRatio); pw.println(innerPrefix + "mMinAspectRatio=" + mMinAspectRatio); diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index d9872d7dcf17..0125153542c1 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -103,6 +103,7 @@ public class PipTaskOrganizer extends TaskOrganizer { @Override public void onPipAnimationEnd(SurfaceControl.Transaction tx, PipAnimationController.PipTransitionAnimator animator) { + finishResize(tx, animator.getDestinationBounds(), animator.getTransitionDirection()); mMainHandler.post(() -> { for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) { final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); @@ -110,7 +111,6 @@ public class PipTaskOrganizer extends TaskOrganizer { animator.getTransitionDirection()); } }); - finishResize(tx, animator.getDestinationBounds(), animator.getTransitionDirection()); } @Override @@ -126,7 +126,7 @@ public class PipTaskOrganizer extends TaskOrganizer { }; @SuppressWarnings("unchecked") - private Handler.Callback mUpdateCallbacks = (msg) -> { + private final Handler.Callback mUpdateCallbacks = (msg) -> { SomeArgs args = (SomeArgs) msg.obj; Consumer<Rect> updateBoundsCallback = (Consumer<Rect>) args.arg1; switch (msg.what) { @@ -247,7 +247,7 @@ public class PipTaskOrganizer extends TaskOrganizer { public void onTaskAppeared(ActivityManager.RunningTaskInfo info) { Objects.requireNonNull(info, "Requires RunningTaskInfo"); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - getAspectRatioOrDefault(info.pictureInPictureParams), + info.topActivity, getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */, getMinimalSize(info.topActivityInfo)); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); mTaskInfo = info; @@ -282,7 +282,7 @@ public class PipTaskOrganizer extends TaskOrganizer { */ @Override public void onTaskVanished(ActivityManager.RunningTaskInfo info) { - WindowContainerToken token = info.token; + final WindowContainerToken token = info.token; Objects.requireNonNull(token, "Requires valid WindowContainerToken"); if (token.asBinder() != mToken.asBinder()) { Log.wtf(TAG, "Unrecognized token: " + token); @@ -297,13 +297,14 @@ public class PipTaskOrganizer extends TaskOrganizer { @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { + Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken"); final PictureInPictureParams newParams = info.pictureInPictureParams; if (!shouldUpdateDestinationBounds(newParams)) { Log.d(TAG, "Ignored onTaskInfoChanged with PiP param: " + newParams); return; } final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - getAspectRatioOrDefault(newParams), + info.topActivity, getAspectRatioOrDefault(newParams), null /* bounds */, getMinimalSize(info.topActivityInfo)); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); scheduleAnimateResizePip(destinationBounds, mEnterExitAnimationDuration, @@ -317,17 +318,28 @@ public class PipTaskOrganizer extends TaskOrganizer { /** * TODO(b/152809058): consolidate the display info handling logic in SysUI + * + * @param destinationBoundsOut the current destination bounds will be populated to this param */ @SuppressWarnings("unchecked") - public void onMovementBoundsChanged(boolean fromImeAdjustment, boolean fromShelfAdjustment) { + public void onMovementBoundsChanged(Rect destinationBoundsOut, boolean fromRotation, + boolean fromImeAdjustment, boolean fromShelfAdjustment) { final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController.getCurrentAnimator(); if (animator == null || !animator.isRunning() || animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) { + if (mInPip && fromRotation) { + // this could happen if rotation finishes before the animation + mLastReportedBounds.set(destinationBoundsOut); + scheduleFinishResizePip(mLastReportedBounds); + } else if (!mLastReportedBounds.isEmpty()) { + destinationBoundsOut.set(mLastReportedBounds); + } return; } final Rect currentDestinationBounds = animator.getDestinationBounds(); + destinationBoundsOut.set(currentDestinationBounds); if (!fromImeAdjustment && !fromShelfAdjustment && mPipBoundsHandler.getDisplayBounds().contains(currentDestinationBounds)) { // no need to update the destination bounds, bail early @@ -335,13 +347,14 @@ public class PipTaskOrganizer extends TaskOrganizer { } final Rect newDestinationBounds = mPipBoundsHandler.getDestinationBounds( - getAspectRatioOrDefault(mTaskInfo.pictureInPictureParams), + mTaskInfo.topActivity, getAspectRatioOrDefault(mTaskInfo.pictureInPictureParams), null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo)); if (newDestinationBounds.equals(currentDestinationBounds)) return; if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) { animator.updateEndValue(newDestinationBounds); } animator.setDestinationBounds(newDestinationBounds); + destinationBoundsOut.set(newDestinationBounds); } /** @@ -369,7 +382,7 @@ public class PipTaskOrganizer extends TaskOrganizer { @PipAnimationController.TransitionDirection int direction, int durationMs, Consumer<Rect> updateBoundsCallback) { if (!mInPip) { - // Ignore animation when we are no longer in PIP + // can be initiated in other component, ignore if we are no longer in PIP return; } SomeArgs args = SomeArgs.obtain(); @@ -421,6 +434,10 @@ public class PipTaskOrganizer extends TaskOrganizer { private void scheduleFinishResizePip(SurfaceControl.Transaction tx, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, Consumer<Rect> updateBoundsCallback) { + if (!mInPip) { + // can be initiated in other component, ignore if we are no longer in PIP + return; + } SomeArgs args = SomeArgs.obtain(); args.arg1 = updateBoundsCallback; args.arg2 = tx; @@ -435,7 +452,7 @@ public class PipTaskOrganizer extends TaskOrganizer { public void scheduleOffsetPip(Rect originalBounds, int offset, int duration, Consumer<Rect> updateBoundsCallback) { if (!mInPip) { - // Ignore offsets when we are no longer in PIP + // can be initiated in other component, ignore if we are no longer in PIP return; } SomeArgs args = SomeArgs.obtain(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java deleted file mode 100644 index b7258117c48c..000000000000 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipDismissViewController.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.pip.phone; - -import android.content.Context; -import android.graphics.PixelFormat; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.VibrationEffect; -import android.os.Vibrator; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; -import android.widget.FrameLayout; - -import com.android.systemui.Interpolators; -import com.android.systemui.R; -import com.android.systemui.shared.system.WindowManagerWrapper; - -/** - * Displays the dismiss UI and target for floating objects. - */ -public class PipDismissViewController { - - // This delay controls how long to wait before we show the target when the user first moves - // the PIP, to prevent the target from animating if the user just wants to fling the PIP - public static final int SHOW_TARGET_DELAY = 100; - private static final int SHOW_TARGET_DURATION = 350; - private static final int HIDE_TARGET_DURATION = 225; - - private Context mContext; - private WindowManager mWindowManager; - private View mDismissView; - - // Used for dismissing a bubble -- bubble should be in the target to be considered a dismiss - private View mTargetView; - private int mTargetSlop; - private Point mWindowSize; - private int[] mLoc = new int[2]; - private boolean mIntersecting; - private Vibrator mVibe; - - public PipDismissViewController(Context context) { - mContext = context; - mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - mVibe = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - } - - /** - * Creates the dismiss target for showing via {@link #showDismissTarget()}. - */ - public void createDismissTarget() { - if (mDismissView == null) { - // Determine sizes for the view - final Rect stableInsets = new Rect(); - WindowManagerWrapper.getInstance().getStableInsets(stableInsets); - mWindowSize = new Point(); - mWindowManager.getDefaultDisplay().getRealSize(mWindowSize); - final int gradientHeight = mContext.getResources().getDimensionPixelSize( - R.dimen.pip_dismiss_gradient_height); - final int bottomMargin = mContext.getResources().getDimensionPixelSize( - R.dimen.pip_dismiss_text_bottom_margin); - mTargetSlop = mContext.getResources().getDimensionPixelSize( - R.dimen.bubble_dismiss_slop); - - // Create a new view for the dismiss target - LayoutInflater inflater = LayoutInflater.from(mContext); - mDismissView = inflater.inflate(R.layout.pip_dismiss_view, null); - mDismissView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); - mDismissView.forceHasOverlappingRendering(false); - - // Set the gradient background - Drawable gradient = mContext.getResources().getDrawable(R.drawable.pip_dismiss_scrim); - gradient.setAlpha((int) (255 * 0.85f)); - mDismissView.setBackground(gradient); - - // Adjust bottom margins of the text - mTargetView = mDismissView.findViewById(R.id.pip_dismiss_text); - FrameLayout.LayoutParams tlp = (FrameLayout.LayoutParams) mTargetView.getLayoutParams(); - tlp.bottomMargin = stableInsets.bottom + bottomMargin; - mTargetView.setLayoutParams(tlp); - - // Add the target to the window - LayoutParams lp = new LayoutParams( - LayoutParams.MATCH_PARENT, gradientHeight, - 0, mWindowSize.y - gradientHeight, - LayoutParams.TYPE_NAVIGATION_BAR_PANEL, - LayoutParams.FLAG_LAYOUT_IN_SCREEN - | LayoutParams.FLAG_NOT_TOUCHABLE - | LayoutParams.FLAG_NOT_FOCUSABLE, - PixelFormat.TRANSLUCENT); - lp.setTitle("pip-dismiss-overlay"); - lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; - lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; - lp.setFitInsetsTypes(0 /* types */); - mWindowManager.addView(mDismissView, lp); - } - mDismissView.animate().cancel(); - } - - - /** - * Updates the dismiss target based on location of the view, only used for bubbles not for PIP. - * - * @return whether the view is within the dismiss target. - */ - public boolean updateTarget(View view) { - if (mDismissView == null) { - return false; - } - if (mDismissView.getAlpha() > 0) { - view.getLocationOnScreen(mLoc); - Rect viewRect = new Rect(mLoc[0], mLoc[1], mLoc[0] + view.getWidth(), - mLoc[1] + view.getHeight()); - mTargetView.getLocationOnScreen(mLoc); - Rect targetRect = new Rect(mLoc[0], mLoc[1], mLoc[0] + mTargetView.getWidth(), - mLoc[1] + mTargetView.getHeight()); - expandRect(targetRect, mTargetSlop); - boolean intersecting = targetRect.intersect(viewRect); - if (intersecting != mIntersecting) { - // TODO: is this the right effect? - mVibe.vibrate(VibrationEffect.get(intersecting - ? VibrationEffect.EFFECT_CLICK - : VibrationEffect.EFFECT_TICK)); - } - mIntersecting = intersecting; - return intersecting; - } - return false; - } - - /** - * Shows the dismiss target. - */ - public void showDismissTarget() { - mDismissView.animate() - .alpha(1f) - .setInterpolator(Interpolators.LINEAR) - .setStartDelay(SHOW_TARGET_DELAY) - .setDuration(SHOW_TARGET_DURATION) - .start(); - } - - /** - * Hides and destroys the dismiss target. - */ - public void destroyDismissTarget() { - if (mDismissView != null) { - mDismissView.animate() - .alpha(0f) - .setInterpolator(Interpolators.LINEAR) - .setStartDelay(0) - .setDuration(HIDE_TARGET_DURATION) - .withEndAction(new Runnable() { - @Override - public void run() { - mWindowManager.removeViewImmediate(mDismissView); - mDismissView = null; - } - }) - .start(); - } - } - - private void expandRect(Rect outRect, int expandAmount) { - outRect.left = Math.max(0, outRect.left - expandAmount); - outRect.top = Math.max(0, outRect.top - expandAmount); - outRect.right = Math.min(mWindowSize.x, outRect.right + expandAmount); - outRect.bottom = Math.min(mWindowSize.y, outRect.bottom + expandAmount); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 918c45b52d61..c3779efcf4b2 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.IActivityManager; @@ -96,8 +97,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mTmpNormalBounds, displayId, fromRotation, toRotation, t); if (changed) { - updateMovementBounds(mTmpNormalBounds, false /* fromImeAdjustment */, - false /* fromShelfAdjustment */); + updateMovementBounds(mTmpNormalBounds, true /* fromRotation */, + false /* fromImeAdjustment */, false /* fromShelfAdjustment */); } }; @@ -160,9 +161,9 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } @Override - public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment) { - mHandler.post(() -> updateMovementBounds(animatingBounds, fromImeAdjustment, - false /* fromShelfAdjustment */)); + public void onMovementBoundsChanged(boolean fromImeAdjustment) { + mHandler.post(() -> updateMovementBounds(null /* toBounds */, + false /* fromRotation */, fromImeAdjustment, false /* fromShelfAdjustment */)); } @Override @@ -293,7 +294,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio if (changed) { mTouchHandler.onShelfVisibilityChanged(visible, height); updateMovementBounds(mPipBoundsHandler.getLastDestinationBounds(), - false /* fromImeAdjustment */, true /* fromShelfAdjustment */); + false /* fromRotation */, false /* fromImeAdjustment */, + true /* fromShelfAdjustment */); } }); } @@ -352,17 +354,19 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mMenuController.onPinnedStackAnimationEnded(); } - private void updateMovementBounds(Rect animatingBounds, boolean fromImeAdjustment, - boolean fromShelfAdjustment) { + private void updateMovementBounds(@Nullable Rect toBounds, boolean fromRotation, + boolean fromImeAdjustment, boolean fromShelfAdjustment) { // Populate inset / normal bounds and DisplayInfo from mPipBoundsHandler before - // passing to mTouchHandler, mTouchHandler would rely on the bounds calculated by - // mPipBoundsHandler with up-to-dated information + // passing to mTouchHandler/mPipTaskOrganizer + final Rect outBounds = new Rect(toBounds); mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, - animatingBounds, mTmpDisplayInfo); + outBounds, mTmpDisplayInfo); + // mTouchHandler would rely on the bounds populated from mPipTaskOrganizer + mPipTaskOrganizer.onMovementBoundsChanged(outBounds, fromRotation, + fromImeAdjustment, fromShelfAdjustment); mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, - animatingBounds, fromImeAdjustment, fromShelfAdjustment, + outBounds, fromImeAdjustment, fromShelfAdjustment, mTmpDisplayInfo.rotation); - mPipTaskOrganizer.onMovementBoundsChanged(fromImeAdjustment, fromShelfAdjustment); } public void dump(PrintWriter pw) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 8397c65dbdb0..a8a5d896537f 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -16,16 +16,12 @@ package com.android.systemui.pip.phone; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.ActivityManager.StackInfo; import android.app.IActivityTaskManager; import android.content.Context; -import android.graphics.Point; -import android.graphics.PointF; import android.graphics.Rect; import android.os.Debug; import android.os.RemoteException; @@ -40,6 +36,7 @@ import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.util.animation.FloatProperties; import com.android.systemui.util.animation.PhysicsAnimator; +import com.android.systemui.util.magnetictarget.MagnetizedObject; import java.io.PrintWriter; import java.util.function.Consumer; @@ -61,9 +58,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, /** Friction to use for PIP when it moves via physics fling animations. */ private static final float DEFAULT_FRICTION = 2f; - // The fraction of the stack height that the user has to drag offscreen to dismiss the PiP - private static final float DISMISS_OFFSCREEN_FRACTION = 0.3f; - private final Context mContext; private final IActivityTaskManager mActivityTaskManager; private final PipTaskOrganizer mPipTaskOrganizer; @@ -103,7 +97,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, /** * Update listener that resizes the PIP to {@link #mAnimatedBounds}. */ - private final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener = + final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener = (target, values) -> resizePipUnchecked(mAnimatedBounds); /** FlingConfig instances provided to PhysicsAnimator for fling gestures. */ @@ -122,6 +116,13 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private final Consumer<Rect> mUpdateBoundsCallback = mBounds::set; + /** + * Whether we're springing to the touch event location (vs. moving it to that position + * instantly). We spring-to-touch after PIP is dragged out of the magnetic target, since it was + * 'stuck' in the target and needs to catch up to the touch location. + */ + private boolean mSpringingToTouch = false; + public PipMotionHelper(Context context, IActivityTaskManager activityTaskManager, PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController, PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils, @@ -166,15 +167,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, */ void synchronizePinnedStackBounds() { cancelAnimations(); - try { - StackInfo stackInfo = mActivityTaskManager.getStackInfo( - WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); - if (stackInfo != null) { - mBounds.set(stackInfo.bounds); - } - } catch (RemoteException e) { - Log.w(TAG, "Failed to get pinned stack bounds"); - } + mBounds.set(mPipTaskOrganizer.getLastReportedBounds()); } /** @@ -211,9 +204,35 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, mFloatingContentCoordinator.onContentMoved(this); } - cancelAnimations(); - resizePipUnchecked(toBounds); - mBounds.set(toBounds); + if (!mSpringingToTouch) { + // If we are moving PIP directly to the touch event locations, cancel any animations and + // move PIP to the given bounds. + cancelAnimations(); + resizePipUnchecked(toBounds); + mBounds.set(toBounds); + } else { + // If PIP is 'catching up' after being stuck in the dismiss target, update the animation + // to spring towards the new touch location. + mAnimatedBoundsPhysicsAnimator + .spring(FloatProperties.RECT_X, toBounds.left, mSpringConfig) + .spring(FloatProperties.RECT_Y, toBounds.top, mSpringConfig) + .withEndActions(() -> mSpringingToTouch = false); + + startBoundsAnimator(toBounds.left /* toX */, toBounds.top /* toY */); + } + } + + /** Set whether we're springing-to-touch to catch up after being stuck in the dismiss target. */ + void setSpringingToTouch(boolean springingToTouch) { + if (springingToTouch) { + mAnimatedBounds.set(mBounds); + } + + mSpringingToTouch = springingToTouch; + } + + void prepareForAnimation() { + mAnimatedBounds.set(mBounds); } /** @@ -278,24 +297,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, } /** - * @return whether the PiP at the current bounds should be dismissed. - */ - boolean shouldDismissPip() { - Point displaySize = new Point(); - mContext.getDisplay().getRealSize(displaySize); - final int y = displaySize.y - mStableInsets.bottom; - if (mBounds.bottom > y) { - float offscreenFraction = (float) (mBounds.bottom - y) / mBounds.height(); - return offscreenFraction >= DISMISS_OFFSCREEN_FRACTION; - } - return false; - } - - /** * Flings the PiP to the closest snap target. */ void flingToSnapTarget( - float velocityX, float velocityY, Runnable updateAction, @Nullable Runnable endAction) { + float velocityX, float velocityY, + @Nullable Runnable updateAction, @Nullable Runnable endAction) { mAnimatedBounds.set(mBounds); mAnimatedBoundsPhysicsAnimator .flingThenSpring( @@ -303,9 +309,13 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, true /* flingMustReachMinOrMax */) .flingThenSpring( FloatProperties.RECT_Y, velocityY, mFlingConfigY, mSpringConfig) - .addUpdateListener((target, values) -> updateAction.run()) .withEndActions(endAction); + if (updateAction != null) { + mAnimatedBoundsPhysicsAnimator.addUpdateListener( + (target, values) -> updateAction.run()); + } + final float xEndValue = velocityX < 0 ? mMovementBounds.left : mMovementBounds.right; final float estimatedFlingYEndValue = PhysicsAnimator.estimateFlingEndValue(mBounds.top, velocityY, mFlingConfigY); @@ -338,16 +348,14 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, * Animates the dismissal of the PiP off the edge of the screen. */ void animateDismiss(float velocityX, float velocityY, @Nullable Runnable updateAction) { - final float velocity = PointF.length(velocityX, velocityY); - final boolean isFling = velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond(); - final Point dismissEndPoint = getDismissEndPoint(mBounds, velocityX, velocityY, isFling); - mAnimatedBounds.set(mBounds); - // Animate to the dismiss end point, and then dismiss PIP. + // Animate off the bottom of the screen, then dismiss PIP. mAnimatedBoundsPhysicsAnimator - .spring(FloatProperties.RECT_X, dismissEndPoint.x, velocityX, mSpringConfig) - .spring(FloatProperties.RECT_Y, dismissEndPoint.y, velocityY, mSpringConfig) + .spring(FloatProperties.RECT_Y, + mBounds.bottom + mBounds.height(), + velocityY, + mSpringConfig) .withEndActions(this::dismissPip); // If we were provided with an update action, run it whenever there's an update. @@ -356,7 +364,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, (target, values) -> updateAction.run()); } - startBoundsAnimator(dismissEndPoint.x /* toX */, dismissEndPoint.y /* toY */); + startBoundsAnimator(mBounds.left /* toX */, mBounds.bottom + mBounds.height() /* toY */); } /** @@ -408,6 +416,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private void cancelAnimations() { mAnimatedBoundsPhysicsAnimator.cancel(); mAnimatingToBounds.setEmpty(); + mSpringingToTouch = false; } /** Set new fling configs whose min/max values respect the given movement bounds. */ @@ -426,7 +435,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, * the 'real' bounds to equal the final animated bounds. */ private void startBoundsAnimator(float toX, float toY) { - cancelAnimations(); + if (!mSpringingToTouch) { + cancelAnimations(); + } // Set animatingToBounds directly to avoid allocating a new Rect, but then call // setAnimatingToBounds to run the normal logic for changing animatingToBounds. @@ -484,47 +495,29 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, } /** - * @return the coordinates the PIP should animate to based on the direction of velocity when - * dismissing. + * Returns a MagnetizedObject wrapper for PIP's animated bounds. This is provided to the + * magnetic dismiss target so it can calculate PIP's size and position. */ - private Point getDismissEndPoint(Rect pipBounds, float velX, float velY, boolean isFling) { - Point displaySize = new Point(); - mContext.getDisplay().getRealSize(displaySize); - final float bottomBound = displaySize.y + pipBounds.height() * .1f; - if (isFling && velX != 0 && velY != 0) { - // Line is defined by: y = mx + b, m = slope, b = y-intercept - // Find the slope - final float slope = velY / velX; - // Sub in slope and PiP position to solve for y-intercept: b = y - mx - final float yIntercept = pipBounds.top - slope * pipBounds.left; - // Now find the point on this line when y = bottom bound: x = (y - b) / m - final float x = (bottomBound - yIntercept) / slope; - return new Point((int) x, (int) bottomBound); - } else { - // If it wasn't a fling the velocity on 'up' is not reliable for direction of movement, - // just animate downwards. - return new Point(pipBounds.left, (int) bottomBound); - } - } + MagnetizedObject<Rect> getMagnetizedPip() { + return new MagnetizedObject<Rect>( + mContext, mAnimatedBounds, FloatProperties.RECT_X, FloatProperties.RECT_Y) { + @Override + public float getWidth(@NonNull Rect animatedPipBounds) { + return animatedPipBounds.width(); + } - /** - * @return whether the gesture it towards the dismiss area based on the velocity when - * dismissing. - */ - public boolean isGestureToDismissArea(Rect pipBounds, float velX, float velY, - boolean isFling) { - Point endpoint = getDismissEndPoint(pipBounds, velX, velY, isFling); - // Center the point - endpoint.x += pipBounds.width() / 2; - endpoint.y += pipBounds.height() / 2; - - // The dismiss area is the middle third of the screen, half the PIP's height from the bottom - Point size = new Point(); - mContext.getDisplay().getRealSize(size); - final int left = size.x / 3; - Rect dismissArea = new Rect(left, size.y - (pipBounds.height() / 2), left * 2, - size.y + pipBounds.height()); - return dismissArea.contains(endpoint.x, endpoint.y); + @Override + public float getHeight(@NonNull Rect animatedPipBounds) { + return animatedPipBounds.height(); + } + + @Override + public void getLocationOnScreen( + @NonNull Rect animatedPipBounds, @NonNull int[] loc) { + loc[0] = animatedPipBounds.left; + loc[1] = animatedPipBounds.top; + } + }; } public void dump(PrintWriter pw, String prefix) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 7cc2759ad59a..350ce293a13f 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -20,11 +20,13 @@ import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STAT import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_FULL; import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_NONE; +import android.annotation.SuppressLint; import android.app.IActivityManager; import android.app.IActivityTaskManager; import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; +import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; @@ -33,14 +35,23 @@ import android.os.RemoteException; import android.util.Log; import android.util.Pair; import android.util.Size; +import android.view.Gravity; import android.view.IPinnedStackController; import android.view.InputEvent; import android.view.MotionEvent; +import android.view.View; import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.dynamicanimation.animation.DynamicAnimation; +import androidx.dynamicanimation.animation.SpringForce; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.logging.MetricsLoggerWrapper; @@ -51,7 +62,10 @@ import com.android.systemui.pip.PipTaskOrganizer; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.util.DeviceConfigProxy; +import com.android.systemui.util.DismissCircleView; import com.android.systemui.util.FloatingContentCoordinator; +import com.android.systemui.util.animation.PhysicsAnimator; +import com.android.systemui.util.magnetictarget.MagnetizedObject; import java.io.PrintWriter; @@ -62,9 +76,6 @@ import java.io.PrintWriter; public class PipTouchHandler { private static final String TAG = "PipTouchHandler"; - // Allow the PIP to be flung from anywhere on the screen to the bottom to be dismissed. - private static final boolean ENABLE_FLING_DISMISS = false; - private static final int SHOW_DISMISS_AFFORDANCE_DELAY = 225; private static final int BOTTOM_OFFSET_BUFFER_DP = 1; @@ -73,17 +84,45 @@ public class PipTouchHandler { // Allow PIP to resize to a slightly bigger state upon touch private final boolean mEnableResize; private final Context mContext; + private final WindowManager mWindowManager; private final IActivityManager mActivityManager; private final PipBoundsHandler mPipBoundsHandler; private PipResizeGestureHandler mPipResizeGestureHandler; private IPinnedStackController mPinnedStackController; private final PipMenuActivityController mMenuController; - private final PipDismissViewController mDismissViewController; private final PipSnapAlgorithm mSnapAlgorithm; private final AccessibilityManager mAccessibilityManager; private boolean mShowPipMenuOnAnimationEnd = false; + /** + * MagnetizedObject wrapper for PIP. This allows the magnetic target library to locate and move + * PIP. + */ + private MagnetizedObject<Rect> mMagnetizedPip; + + /** + * Container for the dismiss circle, so that it can be animated within the container via + * translation rather than within the WindowManager via slow layout animations. + */ + private ViewGroup mTargetViewContainer; + + /** Circle view used to render the dismiss target. */ + private DismissCircleView mTargetView; + + /** + * MagneticTarget instance wrapping the target view and allowing us to set its magnetic radius. + */ + private MagnetizedObject.MagneticTarget mMagneticTarget; + + /** PhysicsAnimator instance for animating the dismiss target in/out. */ + private PhysicsAnimator<View> mMagneticTargetAnimator; + + /** Default configuration to use for springing the dismiss target in/out. */ + private final PhysicsAnimator.SpringConfig mTargetSpringConfig = + new PhysicsAnimator.SpringConfig( + SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_NO_BOUNCY); + // The current movement bounds private Rect mMovementBounds = new Rect(); // The current resized bounds, changed by user resize. @@ -104,21 +143,20 @@ public class PipTouchHandler { private int mDeferResizeToNormalBoundsUntilRotation = -1; private int mDisplayRotation; + /** + * Runnable that can be posted delayed to show the target. This needs to be saved as a member + * variable so we can pass it to removeCallbacks. + */ + private Runnable mShowTargetAction = this::showDismissTargetMaybe; + private Handler mHandler = new Handler(); - private Runnable mShowDismissAffordance = new Runnable() { - @Override - public void run() { - if (mEnableDismissDragToEdge) { - mDismissViewController.showDismissTarget(); - } - } - }; // Behaviour states private int mMenuState = MENU_STATE_NONE; private boolean mIsImeShowing; private int mImeHeight; private int mImeOffset; + private int mDismissAreaHeight; private boolean mIsShelfShowing; private int mShelfHeight; private int mMovementBoundsExtraOffsets; @@ -168,6 +206,7 @@ public class PipTouchHandler { } } + @SuppressLint("InflateParams") public PipTouchHandler(Context context, IActivityManager activityManager, IActivityTaskManager activityTaskManager, PipMenuActivityController menuController, InputConsumerController inputConsumerController, @@ -180,9 +219,9 @@ public class PipTouchHandler { mContext = context; mActivityManager = activityManager; mAccessibilityManager = context.getSystemService(AccessibilityManager.class); + mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); mMenuController = menuController; mMenuController.addListener(new PipMenuListener()); - mDismissViewController = new PipDismissViewController(context); mSnapAlgorithm = pipSnapAlgorithm; mFlingAnimationUtils = new FlingAnimationUtils(context.getResources().getDisplayMetrics(), 2.5f); @@ -200,6 +239,7 @@ public class PipTouchHandler { mExpandedShortestEdgeSize = res.getDimensionPixelSize( R.dimen.pip_expanded_shortest_edge_size); mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset); + mDismissAreaHeight = res.getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height); mEnableDismissDragToEdge = res.getBoolean(R.bool.config_pipEnableDismissDragToEdge); mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu); @@ -212,6 +252,56 @@ public class PipTouchHandler { mFloatingContentCoordinator = floatingContentCoordinator; mConnection = new PipAccessibilityInteractionConnection(mMotionHelper, this::onAccessibilityShowMenu, mHandler); + + final int targetSize = res.getDimensionPixelSize(R.dimen.dismiss_circle_size); + mTargetView = new DismissCircleView(context); + final FrameLayout.LayoutParams newParams = + new FrameLayout.LayoutParams(targetSize, targetSize); + newParams.gravity = Gravity.CENTER; + mTargetView.setLayoutParams(newParams); + + mTargetViewContainer = new FrameLayout(context); + mTargetViewContainer.setClipChildren(false); + mTargetViewContainer.addView(mTargetView); + + mMagnetizedPip = mMotionHelper.getMagnetizedPip(); + mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0); + mMagnetizedPip.setPhysicsAnimatorUpdateListener(mMotionHelper.mResizePipUpdateListener); + mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() { + @Override + public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) { + mMotionHelper.prepareForAnimation(); + + // Show the dismiss target, in case the initial touch event occurred within the + // magnetic field radius. + showDismissTargetMaybe(); + } + + @Override + public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target, + float velX, float velY, boolean wasFlungOut) { + if (wasFlungOut) { + mMotionHelper.flingToSnapTarget(velX, velY, null, null); + hideDismissTarget(); + } else { + mMotionHelper.setSpringingToTouch(true); + } + } + + @Override + public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) { + mHandler.post(() -> { + mMotionHelper.animateDismiss(0, 0, null); + hideDismissTarget(); + }); + + + MetricsLoggerWrapper.logPictureInPictureDismissByDrag(mContext, + PipUtils.getTopPipActivity(mContext, mActivityManager)); + } + }); + + mMagneticTargetAnimator = PhysicsAnimator.getInstance(mTargetView); } public void setTouchGesture(PipTouchGesture gesture) { @@ -231,7 +321,8 @@ public class PipTouchHandler { } public void onActivityPinned() { - cleanUpDismissTarget(); + createOrUpdateDismissTarget(); + mShowPipMenuOnAnimationEnd = true; mPipResizeGestureHandler.onActivityPinned(); mFloatingContentCoordinator.onContentAdded(mMotionHelper); @@ -264,6 +355,9 @@ public class PipTouchHandler { public void onConfigurationChanged() { mMotionHelper.onConfigurationChanged(); mMotionHelper.synchronizePinnedStackBounds(); + + // Recreate the dismiss target for the new orientation. + createOrUpdateDismissTarget(); } public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { @@ -285,11 +379,18 @@ public class PipTouchHandler { } // Re-calculate the expanded bounds - mNormalBounds = normalBounds; + mNormalBounds.set(normalBounds); Rect normalMovementBounds = new Rect(); mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalMovementBounds, bottomOffset); + if (mMovementBounds.isEmpty()) { + // mMovementBounds is not initialized yet and a clean movement bounds without + // bottom offset shall be used later in this function. + mSnapAlgorithm.getMovementBounds(curBounds, insetBounds, mMovementBounds, + 0 /* bottomOffset */); + } + // Calculate the expanded size float aspectRatio = (float) normalBounds.width() / normalBounds.height(); Point displaySize = new Point(); @@ -335,8 +436,8 @@ public class PipTouchHandler { // Update the movement bounds after doing the calculations based on the old movement bounds // above - mNormalMovementBounds = normalMovementBounds; - mExpandedMovementBounds = expandedMovementBounds; + mNormalMovementBounds.set(normalMovementBounds); + mExpandedMovementBounds.set(expandedMovementBounds); mDisplayRotation = displayRotation; mInsetBounds.set(insetBounds); updateMovementBounds(); @@ -351,6 +452,91 @@ public class PipTouchHandler { } } + /** Adds the magnetic target view to the WindowManager so it's ready to be animated in. */ + private void createOrUpdateDismissTarget() { + if (!mTargetViewContainer.isAttachedToWindow()) { + mHandler.removeCallbacks(mShowTargetAction); + mMagneticTargetAnimator.cancel(); + + mTargetViewContainer.setVisibility(View.INVISIBLE); + + try { + mWindowManager.addView(mTargetViewContainer, getDismissTargetLayoutParams()); + } catch (IllegalStateException e) { + // This shouldn't happen, but if the target is already added, just update its layout + // params. + mWindowManager.updateViewLayout( + mTargetViewContainer, getDismissTargetLayoutParams()); + } + } else { + mWindowManager.updateViewLayout(mTargetViewContainer, getDismissTargetLayoutParams()); + } + } + + /** Returns layout params for the dismiss target, using the latest display metrics. */ + private WindowManager.LayoutParams getDismissTargetLayoutParams() { + final Point windowSize = new Point(); + mWindowManager.getDefaultDisplay().getRealSize(windowSize); + + final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + WindowManager.LayoutParams.MATCH_PARENT, + mDismissAreaHeight, + 0, windowSize.y - mDismissAreaHeight, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSLUCENT); + + lp.setTitle("pip-dismiss-overlay"); + lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; + lp.setFitInsetsTypes(0 /* types */); + + return lp; + } + + /** Makes the dismiss target visible and animates it in, if it isn't already visible. */ + private void showDismissTargetMaybe() { + createOrUpdateDismissTarget(); + + if (mTargetViewContainer.getVisibility() != View.VISIBLE) { + + mTargetView.setTranslationY(mTargetViewContainer.getHeight()); + mTargetViewContainer.setVisibility(View.VISIBLE); + + // Set the magnetic field radius to half of PIP's width. + mMagneticTarget.setMagneticFieldRadiusPx(mMotionHelper.getBounds().width()); + + // Cancel in case we were in the middle of animating it out. + mMagneticTargetAnimator.cancel(); + mMagneticTargetAnimator + .spring(DynamicAnimation.TRANSLATION_Y, 0f, mTargetSpringConfig) + .start(); + } + } + + /** Animates the magnetic dismiss target out and then sets it to GONE. */ + private void hideDismissTarget() { + mHandler.removeCallbacks(mShowTargetAction); + mMagneticTargetAnimator + .spring(DynamicAnimation.TRANSLATION_Y, + mTargetViewContainer.getHeight(), + mTargetSpringConfig) + .withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE)) + .start(); + } + + /** + * Removes the dismiss target and cancels any pending callbacks to show it. + */ + private void cleanUpDismissTarget() { + mHandler.removeCallbacks(mShowTargetAction); + + if (mTargetViewContainer.isAttachedToWindow()) { + mWindowManager.removeViewImmediate(mTargetViewContainer); + } + } + private void onRegistrationChanged(boolean isRegistered) { mAccessibilityManager.setPictureInPictureActionReplacingConnection(isRegistered ? mConnection : null); @@ -375,8 +561,24 @@ public class PipTouchHandler { if (mPinnedStackController == null) { return true; } + MotionEvent ev = (MotionEvent) inputEvent; + if (mMagnetizedPip.maybeConsumeMotionEvent(ev)) { + // If the first touch event occurs within the magnetic field, pass the ACTION_DOWN event + // to the touch state. Touch state needs a DOWN event in order to later process MOVE + // events it'll receive if the object is dragged out of the magnetic field. + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mTouchState.onTouchEvent(ev); + } + + // Continue tracking velocity when the object is in the magnetic field, since we want to + // respect touch input velocity if the object is dragged out and then flung. + mTouchState.addMovementToVelocityTracker(ev); + + return true; + } + // Update the touch state mTouchState.onTouchEvent(ev); @@ -413,8 +615,14 @@ public class PipTouchHandler { break; } case MotionEvent.ACTION_HOVER_ENTER: - mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(), - mMovementBounds, false /* allowMenuTimeout */, false /* willResizeMenu */); + // If Touch Exploration is enabled, some a11y services (e.g. Talkback) is probably + // on and changing MotionEvents into HoverEvents. + // Let's not enable menu show/hide for a11y services. + if (!mAccessibilityManager.isTouchExplorationEnabled()) { + mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(), + mMovementBounds, false /* allowMenuTimeout */, + false /* willResizeMenu */); + } case MotionEvent.ACTION_HOVER_MOVE: { if (!shouldDeliverToMenu && !mSendingHoverAccessibilityEvents) { sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); @@ -423,7 +631,12 @@ public class PipTouchHandler { break; } case MotionEvent.ACTION_HOVER_EXIT: { - mMenuController.hideMenu(); + // If Touch Exploration is enabled, some a11y services (e.g. Talkback) is probably + // on and changing MotionEvents into HoverEvents. + // Let's not enable menu show/hide for a11y services. + if (!mAccessibilityManager.isTouchExplorationEnabled()) { + mMenuController.hideMenu(); + } if (!shouldDeliverToMenu && mSendingHoverAccessibilityEvents) { sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); mSendingHoverAccessibilityEvents = false; @@ -600,17 +813,13 @@ public class PipTouchHandler { mDelta.set(0f, 0f); mStartPosition.set(bounds.left, bounds.top); mMovementWithinDismiss = touchState.getDownTouchPosition().y >= mMovementBounds.bottom; + mMotionHelper.setSpringingToTouch(false); // If the menu is still visible then just poke the menu // so that it will timeout after the user stops touching it if (mMenuState != MENU_STATE_NONE) { mMenuController.pokeMenu(); } - - if (mEnableDismissDragToEdge) { - mDismissViewController.createDismissTarget(); - mHandler.postDelayed(mShowDismissAffordance, SHOW_DISMISS_AFFORDANCE_DELAY); - } } @Override @@ -623,8 +832,10 @@ public class PipTouchHandler { mSavedSnapFraction = -1f; if (mEnableDismissDragToEdge) { - mHandler.removeCallbacks(mShowDismissAffordance); - mDismissViewController.showDismissTarget(); + if (mTargetViewContainer.getVisibility() != View.VISIBLE) { + mHandler.removeCallbacks(mShowTargetAction); + showDismissTargetMaybe(); + } } } @@ -644,10 +855,6 @@ public class PipTouchHandler { mTmpBounds.offsetTo((int) left, (int) top); mMotionHelper.movePip(mTmpBounds, true /* isDragging */); - if (mEnableDismissDragToEdge) { - updateDismissFraction(); - } - final PointF curPos = touchState.getLastTouchPosition(); if (mMovementWithinDismiss) { // Track if movement remains near the bottom edge to identify swipe to dismiss @@ -661,9 +868,7 @@ public class PipTouchHandler { @Override public boolean onUp(PipTouchState touchState) { if (mEnableDismissDragToEdge) { - // Clean up the dismiss target regardless of the touch state in case the touch - // enabled state changes while the user is interacting - cleanUpDismissTarget(); + hideDismissTarget(); } if (!touchState.isUserInteracting()) { @@ -671,26 +876,8 @@ public class PipTouchHandler { } final PointF vel = touchState.getVelocity(); - final boolean isHorizontal = Math.abs(vel.x) > Math.abs(vel.y); final float velocity = PointF.length(vel.x, vel.y); final boolean isFling = velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond(); - final boolean isUpWithinDimiss = ENABLE_FLING_DISMISS - && touchState.getLastTouchPosition().y >= mMovementBounds.bottom - && mMotionHelper.isGestureToDismissArea(mMotionHelper.getBounds(), vel.x, - vel.y, isFling); - final boolean isFlingToBot = isFling && vel.y > 0 && !isHorizontal - && (mMovementWithinDismiss || isUpWithinDimiss); - if (mEnableDismissDragToEdge) { - // Check if the user dragged or flung the PiP offscreen to dismiss it - if (mMotionHelper.shouldDismissPip() || isFlingToBot) { - MetricsLoggerWrapper.logPictureInPictureDismissByDrag(mContext, - PipUtils.getTopPipActivity(mContext, mActivityManager)); - mMotionHelper.animateDismiss( - vel.x, vel.y, - PipTouchHandler.this::updateDismissFraction /* updateAction */); - return true; - } - } if (touchState.isDragging()) { Runnable endAction = null; @@ -749,14 +936,6 @@ public class PipTouchHandler { } /** - * Removes the dismiss target and cancels any pending callbacks to show it. - */ - private void cleanUpDismissTarget() { - mHandler.removeCallbacks(mShowDismissAffordance); - mDismissViewController.destroyDismissTarget(); - } - - /** * @return whether the menu will resize as a part of showing the full menu. */ private boolean willResizeMenu() { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java index e3f65ef812fb..dc286c1c2de5 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java @@ -92,7 +92,7 @@ public class PipTouchState { // Initialize the velocity tracker initOrResetVelocityTracker(); - addMovement(ev); + addMovementToVelocityTracker(ev); mActivePointerId = ev.getPointerId(0); if (DEBUG) { @@ -120,7 +120,7 @@ public class PipTouchState { } // Update the velocity tracker - addMovement(ev); + addMovementToVelocityTracker(ev); int pointerIndex = ev.findPointerIndex(mActivePointerId); if (pointerIndex == -1) { Log.e(TAG, "Invalid active pointer id on MOVE: " + mActivePointerId); @@ -151,7 +151,7 @@ public class PipTouchState { } // Update the velocity tracker - addMovement(ev); + addMovementToVelocityTracker(ev); int pointerIndex = ev.getActionIndex(); int pointerId = ev.getPointerId(pointerIndex); @@ -174,7 +174,7 @@ public class PipTouchState { } // Update the velocity tracker - addMovement(ev); + addMovementToVelocityTracker(ev); mVelocityTracker.computeCurrentVelocity(1000, mViewConfig.getScaledMaximumFlingVelocity()); mVelocity.set(mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity()); @@ -318,6 +318,20 @@ public class PipTouchState { return -1; } + void addMovementToVelocityTracker(MotionEvent event) { + if (mVelocityTracker == null) { + return; + } + + // Add movement to velocity tracker using raw screen X and Y coordinates instead + // of window coordinates because the window frame may be moving at the same time. + float deltaX = event.getRawX() - event.getX(); + float deltaY = event.getRawY() - event.getY(); + event.offsetLocation(deltaX, deltaY); + mVelocityTracker.addMovement(event); + event.offsetLocation(-deltaX, -deltaY); + } + private void initOrResetVelocityTracker() { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); @@ -333,16 +347,6 @@ public class PipTouchState { } } - private void addMovement(MotionEvent event) { - // Add movement to velocity tracker using raw screen X and Y coordinates instead - // of window coordinates because the window frame may be moving at the same time. - float deltaX = event.getRawX() - event.getX(); - float deltaY = event.getRawY() - event.getY(); - event.offsetLocation(deltaX, deltaY); - mVelocityTracker.addMovement(event); - event.offsetLocation(-deltaX, -deltaY); - } - public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java index 9c175bc2b756..8efeef1ffa0a 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java @@ -30,6 +30,14 @@ import com.android.systemui.R; */ public class PipControlsView extends LinearLayout { + public PipControlsView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService( diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 52c8960d1ccf..3a2d786cebe4 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -208,12 +208,13 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } @Override - public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment) { + public void onMovementBoundsChanged(boolean fromImeAdjustment) { mHandler.post(() -> { // Populate the inset / normal bounds and DisplayInfo from mPipBoundsHandler first. + final Rect destinationBounds = new Rect(); mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, - animatingBounds, mTmpDisplayInfo); - mDefaultPipBounds.set(animatingBounds); + destinationBounds, mTmpDisplayInfo); + mDefaultPipBounds.set(destinationBounds); }); } @@ -239,6 +240,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mInitialized = true; mContext = context; mPipBoundsHandler = pipBoundsHandler; + // Ensure that we have the display info in case we get calls to update the bounds before the + // listener calls back + final DisplayInfo displayInfo = new DisplayInfo(); + context.getDisplay().getDisplayInfo(displayInfo); + mPipBoundsHandler.onDisplayInfoChanged(displayInfo); + mResizeAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler, @@ -289,7 +296,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mMediaSessionManager = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE); - mPipTaskOrganizer.registerPipTransitionCallback(this); try { WindowManagerWrapper.getInstance().addPinnedStackListener(mPinnedStackListener); @@ -334,6 +340,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio * Shows the picture-in-picture menu if an activity is in picture-in-picture mode. */ public void showPictureInPictureMenu() { + if (DEBUG) Log.d(TAG, "showPictureInPictureMenu(), current state=" + getStateDescription()); + if (getState() == STATE_PIP) { resizePinnedStack(STATE_PIP_MENU); } @@ -343,10 +351,18 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio * Closes PIP (PIPed activity and PIP system UI). */ public void closePip() { + if (DEBUG) Log.d(TAG, "closePip(), current state=" + getStateDescription()); + closePipInternal(true); } private void closePipInternal(boolean removePipStack) { + if (DEBUG) { + Log.d(TAG, + "closePipInternal() removePipStack=" + removePipStack + ", current state=" + + getStateDescription()); + } + mState = STATE_NO_PIP; mPipTaskId = TASK_ID_NO_PIP; mPipMediaController = null; @@ -371,6 +387,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio * Moves the PIPed activity to the fullscreen and closes PIP system UI. */ void movePipToFullscreen() { + if (DEBUG) Log.d(TAG, "movePipToFullscreen(), current state=" + getStateDescription()); + mPipTaskId = TASK_ID_NO_PIP; for (int i = mListeners.size() - 1; i >= 0; --i) { mListeners.get(i).onMoveToFullscreen(); @@ -386,6 +404,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio public void suspendPipResizing(int reason) { if (DEBUG) Log.d(TAG, "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2)); + mSuspendPipResizingReason |= reason; } @@ -408,7 +427,11 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio * @param state In Pip state also used to determine the new size for the Pip. */ void resizePinnedStack(int state) { - if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state, new Exception()); + if (DEBUG) { + Log.d(TAG, "resizePinnedStack() state=" + stateToName(state) + ", current state=" + + getStateDescription(), new Exception()); + } + boolean wasStateNoPip = (mState == STATE_NO_PIP); for (int i = mListeners.size() - 1; i >= 0; --i) { mListeners.get(i).onPipResizeAboutToStart(); @@ -418,7 +441,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio if (DEBUG) Log.d(TAG, "resizePinnedStack() deferring" + " mSuspendPipResizingReason=" + mSuspendPipResizingReason + " mResumeResizePinnedStackRunnableState=" - + mResumeResizePinnedStackRunnableState); + + stateToName(mResumeResizePinnedStackRunnableState)); return; } mState = state; @@ -439,8 +462,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mCurrentPipBounds = mPipBounds; break; } - mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, mResizeAnimationDuration, - null); + if (mCurrentPipBounds != null) { + mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, mResizeAnimationDuration, + null); + } else { + mPipTaskOrganizer.dismissPip(mResizeAnimationDuration); + } } /** @@ -458,7 +485,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio * stack to the centered PIP bound {@link R.config_centeredPictureInPictureBounds}. */ private void showPipMenu() { - if (DEBUG) Log.d(TAG, "showPipMenu()"); + if (DEBUG) Log.d(TAG, "showPipMenu(), current state=" + getStateDescription()); + mState = STATE_PIP_MENU; for (int i = mListeners.size() - 1; i >= 0; --i) { mListeners.get(i).onShowPipMenu(); @@ -712,6 +740,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio private void onPipTransitionFinishedOrCanceled() { if (DEBUG) Log.d(TAG, "onPipTransitionFinishedOrCanceled()"); + if (getState() == STATE_PIP_MENU) { showPipMenu(); } @@ -753,4 +782,28 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio WindowManagerWrapper.getInstance().setPipVisibility(visible); }); } + + private String getStateDescription() { + if (mSuspendPipResizingReason == 0) { + return stateToName(mState); + } + return stateToName(mResumeResizePinnedStackRunnableState) + " (while " + stateToName(mState) + + " is suspended)"; + } + + private static String stateToName(int state) { + switch (state) { + case STATE_NO_PIP: + return "NO_PIP"; + + case STATE_PIP: + return "PIP"; + + case STATE_PIP_MENU: + return "PIP_MENU"; + + default: + return "UNKNOWN(" + state + ")"; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java index f43f8e795fe6..c7e77ccfa488 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java @@ -22,6 +22,7 @@ import android.app.Activity; import android.content.Intent; import android.content.pm.ParceledListSlice; import android.os.Bundle; +import android.util.Log; import com.android.systemui.R; import com.android.systemui.pip.tv.dagger.TvPipComponent; @@ -34,6 +35,7 @@ import javax.inject.Inject; * Activity to show the PIP menu to control PIP. */ public class PipMenuActivity extends Activity implements PipManager.Listener { + private static final boolean DEBUG = false; private static final String TAG = "PipMenuActivity"; static final String EXTRA_CUSTOM_ACTIONS = "custom_actions"; @@ -47,7 +49,6 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { private boolean mRestorePipSizeWhenClose; private PipControlsViewController mPipControlsViewController; - @Inject public PipMenuActivity(TvPipComponent.Builder pipComponentBuilder, PipManager pipManager) { super(); @@ -57,6 +58,8 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { @Override protected void onCreate(Bundle bundle) { + if (DEBUG) Log.d(TAG, "onCreate()"); + super.onCreate(bundle); if (!mPipManager.isPipShown()) { finish(); @@ -81,13 +84,18 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { @Override protected void onNewIntent(Intent intent) { + if (DEBUG) Log.d(TAG, "onNewIntent(), intent=" + intent); super.onNewIntent(intent); onPipMenuActionsChanged(getIntent().getParcelableExtra(EXTRA_CUSTOM_ACTIONS)); } private void restorePipAndFinish() { + if (DEBUG) Log.d(TAG, "restorePipAndFinish()"); + if (mRestorePipSizeWhenClose) { + if (DEBUG) Log.d(TAG, " > restoring to the default position"); + // When PIP menu activity is closed, restore to the default position. mPipManager.resizePinnedStack(PipManager.STATE_PIP); } @@ -96,12 +104,16 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { @Override public void onResume() { + if (DEBUG) Log.d(TAG, "onResume()"); + super.onResume(); mFadeInAnimation.start(); } @Override public void onPause() { + if (DEBUG) Log.d(TAG, "onPause()"); + super.onPause(); mFadeOutAnimation.start(); restorePipAndFinish(); @@ -109,6 +121,8 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { @Override protected void onDestroy() { + if (DEBUG) Log.d(TAG, "onDestroy()"); + super.onDestroy(); mPipManager.removeListener(this); mPipManager.resumePipResizing( @@ -117,29 +131,41 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { @Override public void onBackPressed() { + if (DEBUG) Log.d(TAG, "onBackPressed()"); + restorePipAndFinish(); } @Override - public void onPipEntered() { } + public void onPipEntered() { + if (DEBUG) Log.d(TAG, "onPipEntered()"); + } @Override public void onPipActivityClosed() { + if (DEBUG) Log.d(TAG, "onPipActivityClosed()"); + finish(); } @Override public void onPipMenuActionsChanged(ParceledListSlice actions) { + if (DEBUG) Log.d(TAG, "onPipMenuActionsChanged()"); + boolean hasCustomActions = actions != null && !actions.getList().isEmpty(); mPipControlsViewController.setActions( hasCustomActions ? actions.getList() : Collections.EMPTY_LIST); } @Override - public void onShowPipMenu() { } + public void onShowPipMenu() { + if (DEBUG) Log.d(TAG, "onShowPipMenu()"); + } @Override public void onMoveToFullscreen() { + if (DEBUG) Log.d(TAG, "onMoveToFullscreen()"); + // Moving PIP to fullscreen is implemented by resizing PINNED_STACK with null bounds. // This conflicts with restoring PIP position, so disable it. mRestorePipSizeWhenClose = false; @@ -148,8 +174,17 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { @Override public void onPipResizeAboutToStart() { + if (DEBUG) Log.d(TAG, "onPipResizeAboutToStart()"); + finish(); mPipManager.suspendPipResizing( PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH); } + + @Override + public void finish() { + if (DEBUG) Log.d(TAG, "finish()", new RuntimeException()); + + super.finish(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java index 339a408d501a..e636707a9722 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java @@ -34,7 +34,7 @@ import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.TextView; -import com.android.settingslib.media.MediaDevice; +import com.android.settingslib.media.LocalMediaManager; import com.android.systemui.R; import com.android.systemui.media.MediaControlPanel; import com.android.systemui.media.SeekBarObserver; @@ -74,9 +74,10 @@ public class QSMediaPlayer extends MediaControlPanel { * @param backgroundExecutor */ public QSMediaPlayer(Context context, ViewGroup parent, NotificationMediaManager manager, - Executor foregroundExecutor, DelayableExecutor backgroundExecutor) { - super(context, parent, manager, R.layout.qs_media_panel, QS_ACTION_IDS, foregroundExecutor, - backgroundExecutor); + LocalMediaManager routeManager, Executor foregroundExecutor, + DelayableExecutor backgroundExecutor) { + super(context, parent, manager, routeManager, R.layout.qs_media_panel, QS_ACTION_IDS, + foregroundExecutor, backgroundExecutor); mParent = (QSPanel) parent; mBackgroundExecutor = backgroundExecutor; mSeekBarViewModel = new SeekBarViewModel(backgroundExecutor); @@ -101,12 +102,12 @@ public class QSMediaPlayer extends MediaControlPanel { * @param device current playback device */ public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, - int bgColor, View actionsContainer, Notification notif, MediaDevice device) { + int bgColor, View actionsContainer, Notification notif) { String appName = Notification.Builder.recoverBuilder(getContext(), notif) .loadHeaderAppName(); super.setMediaSession(token, icon, iconColor, bgColor, notif.contentIntent, - appName, device); + appName); // Media controls LinearLayout parentActionsLayout = (LinearLayout) actionsContainer; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index c8412fffd143..0566b2e621db 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -47,7 +47,6 @@ import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.media.InfoMediaManager; import com.android.settingslib.media.LocalMediaManager; -import com.android.settingslib.media.MediaDevice; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.R; @@ -75,7 +74,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.concurrent.Executor; import java.util.stream.Collectors; @@ -105,8 +103,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private final LocalBluetoothManager mLocalBluetoothManager; private final Executor mForegroundExecutor; private final DelayableExecutor mBackgroundExecutor; - private LocalMediaManager mLocalMediaManager; - private MediaDevice mDevice; private boolean mUpdateCarousel = false; protected boolean mExpanded; @@ -130,34 +126,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private BrightnessMirrorController mBrightnessMirrorController; private View mDivider; - private final LocalMediaManager.DeviceCallback mDeviceCallback = - new LocalMediaManager.DeviceCallback() { - @Override - public void onDeviceListUpdate(List<MediaDevice> devices) { - if (mLocalMediaManager == null) { - return; - } - MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice(); - // Check because this can be called several times while changing devices - if (mDevice == null || !mDevice.equals(currentDevice)) { - mDevice = currentDevice; - for (QSMediaPlayer p : mMediaPlayers) { - p.updateDevice(mDevice); - } - } - } - - @Override - public void onSelectedDeviceStateChanged(MediaDevice device, int state) { - if (mDevice == null || !mDevice.equals(device)) { - mDevice = device; - for (QSMediaPlayer p : mMediaPlayers) { - p.updateDevice(mDevice); - } - } - } - }; - @Inject public QSPanel( @Named(VIEW_CONTEXT) Context context, @@ -277,7 +245,14 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne if (player == null) { Log.d(TAG, "creating new player"); - player = new QSMediaPlayer(mContext, this, mNotificationMediaManager, + // Set up listener for device changes + // TODO: integrate with MediaTransferManager? + InfoMediaManager imm = new InfoMediaManager(mContext, notif.getPackageName(), + notif.getNotification(), mLocalBluetoothManager); + LocalMediaManager routeManager = new LocalMediaManager(mContext, mLocalBluetoothManager, + imm, notif.getPackageName()); + + player = new QSMediaPlayer(mContext, this, mNotificationMediaManager, routeManager, mForegroundExecutor, mBackgroundExecutor); player.setListening(mListening); if (player.isPlaying()) { @@ -292,22 +267,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne Log.d(TAG, "setting player session"); player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer, - notif.getNotification(), mDevice); + notif.getNotification()); if (mMediaPlayers.size() > 0) { ((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE); - - if (mLocalMediaManager == null) { - // Set up listener for device changes - // TODO: integrate with MediaTransferManager? - InfoMediaManager imm = - new InfoMediaManager(mContext, null, null, mLocalBluetoothManager); - mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager, imm, - null); - mLocalMediaManager.startScan(); - mDevice = mLocalMediaManager.getCurrentConnectedDevice(); - mLocalMediaManager.registerCallback(mDeviceCallback); - } } } @@ -330,11 +293,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mMediaCarousel.removeView(player.getView()); if (mMediaPlayers.size() == 0) { ((View) mMediaCarousel.getParent()).setVisibility(View.GONE); - if (mLocalMediaManager != null) { - mLocalMediaManager.stopScan(); - mLocalMediaManager.unregisterCallback(mDeviceCallback); - mLocalMediaManager = null; - } } return true; } @@ -404,11 +362,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mBrightnessMirrorController.removeCallback(this); } mDumpManager.unregisterDumpable(getDumpableTag()); - if (mLocalMediaManager != null) { - mLocalMediaManager.stopScan(); - mLocalMediaManager.unregisterCallback(mDeviceCallback); - mLocalMediaManager = null; - } super.onDetachedFromWindow(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java index 0c5019491a59..0ba4cb159024 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java @@ -53,7 +53,7 @@ public class QuickQSMediaPlayer extends MediaControlPanel { */ public QuickQSMediaPlayer(Context context, ViewGroup parent, NotificationMediaManager manager, Executor foregroundExecutor, Executor backgroundExecutor) { - super(context, parent, manager, R.layout.qqs_media_panel, QQS_ACTION_IDS, + super(context, parent, manager, null, R.layout.qqs_media_panel, QQS_ACTION_IDS, foregroundExecutor, backgroundExecutor); } @@ -84,7 +84,7 @@ public class QuickQSMediaPlayer extends MediaControlPanel { return; } - super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, null, null); + super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, null); LinearLayout parentActionsLayout = (LinearLayout) actionsContainer; int i = 0; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 8fa64d3aaf0c..e6876bd98d21 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -66,7 +66,10 @@ public class QuickQSPanel extends QSPanel { private int mMaxTiles; protected QSPanel mFullPanel; private QuickQSMediaPlayer mMediaPlayer; + /** Whether or not the QS media player feature is enabled. */ private boolean mUsingMediaPlayer; + /** Whether or not the QuickQSPanel currently contains a media player. */ + private boolean mHasMediaPlayer; private LinearLayout mHorizontalLinearLayout; // Only used with media @@ -185,8 +188,8 @@ public class QuickQSPanel extends QSPanel { boolean switchTileLayout() { if (!mUsingMediaPlayer) return false; - if (mMediaPlayer.hasMediaSession() - && mHorizontalLinearLayout.getVisibility() == View.GONE) { + mHasMediaPlayer = mMediaPlayer.hasMediaSession(); + if (mHasMediaPlayer && mHorizontalLinearLayout.getVisibility() == View.GONE) { mHorizontalLinearLayout.setVisibility(View.VISIBLE); ((View) mRegularTileLayout).setVisibility(View.GONE); mTileLayout.setListening(false); @@ -198,8 +201,7 @@ public class QuickQSPanel extends QSPanel { if (mHost != null) setTiles(mHost.getTiles()); mTileLayout.setListening(mListening); return true; - } else if (!mMediaPlayer.hasMediaSession() - && mHorizontalLinearLayout.getVisibility() == View.VISIBLE) { + } else if (!mHasMediaPlayer && mHorizontalLinearLayout.getVisibility() == View.VISIBLE) { mHorizontalLinearLayout.setVisibility(View.GONE); ((View) mRegularTileLayout).setVisibility(View.VISIBLE); mTileLayout.setListening(false); @@ -215,8 +217,9 @@ public class QuickQSPanel extends QSPanel { return false; } - public boolean hasMediaPlayerSession() { - return mMediaPlayer.hasMediaSession(); + /** Returns true if this panel currently contains a media player. */ + public boolean hasMediaPlayer() { + return mHasMediaPlayer; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 11b625f41737..90dc38f3ad12 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -22,10 +22,8 @@ import static com.android.systemui.util.Utils.useQsMediaPlayer; import android.annotation.ColorInt; import android.app.ActivityManager; import android.app.AlarmManager; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; @@ -49,13 +47,16 @@ import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; import com.android.settingslib.Utils; import com.android.systemui.BatteryMeterView; import com.android.systemui.DualToneHandler; import com.android.systemui.R; -import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; @@ -70,6 +71,7 @@ import com.android.systemui.statusbar.policy.Clock; import com.android.systemui.statusbar.policy.DateView; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.RingerModeTracker; import java.util.ArrayList; import java.util.List; @@ -86,7 +88,7 @@ import javax.inject.Named; */ public class QuickStatusBarHeader extends RelativeLayout implements View.OnClickListener, NextAlarmController.NextAlarmChangeCallback, - ZenModeController.Callback { + ZenModeController.Callback, LifecycleOwner { private static final String TAG = "QuickStatusBarHeader"; private static final boolean DEBUG = false; @@ -137,15 +139,9 @@ public class QuickStatusBarHeader extends RelativeLayout implements private DateView mDateView; private BatteryMeterView mBatteryRemainingIcon; - private BroadcastDispatcher mBroadcastDispatcher; + // Used for RingerModeTracker + private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this); - private final BroadcastReceiver mRingerReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - mRingerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1); - updateStatusText(); - } - }; private boolean mHasTopCutout = false; private int mRoundedCornerPadding = 0; @@ -154,7 +150,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements NextAlarmController nextAlarmController, ZenModeController zenModeController, StatusBarIconController statusBarIconController, ActivityStarter activityStarter, - CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher) { + CommandQueue commandQueue, RingerModeTracker ringerModeTracker) { super(context, attrs); mAlarmController = nextAlarmController; mZenController = zenModeController; @@ -162,8 +158,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements mActivityStarter = activityStarter; mDualToneHandler = new DualToneHandler( new ContextThemeWrapper(context, R.style.QSHeaderTheme)); - mBroadcastDispatcher = broadcastDispatcher; mCommandQueue = commandQueue; + ringerModeTracker.getRingerModeInternal().observe(this, ringer -> { + mRingerMode = ringer; + updateStatusText(); + }); } @Override @@ -344,7 +343,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements if (mQsDisabled) { lp.height = resources.getDimensionPixelSize( com.android.internal.R.dimen.quick_qs_offset_height); - } else if (useQsMediaPlayer(mContext) && mHeaderQsPanel.hasMediaPlayerSession()) { + } else if (useQsMediaPlayer(mContext) && mHeaderQsPanel.hasMediaPlayer()) { lp.height = Math.max(getMinimumHeight(), resources.getDimensionPixelSize( com.android.internal.R.dimen.quick_qs_total_height_with_media)); @@ -484,12 +483,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements if (listening) { mZenController.addCallback(this); mAlarmController.addCallback(this); - mBroadcastDispatcher.registerReceiver(mRingerReceiver, - new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)); + mLifecycle.setCurrentState(Lifecycle.State.RESUMED); } else { mZenController.removeCallback(this); mAlarmController.removeCallback(this); - mBroadcastDispatcher.unregisterReceiver(mRingerReceiver); + mLifecycle.setCurrentState(Lifecycle.State.DESTROYED); } } @@ -586,4 +584,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements lp.rightMargin = sideMargins; } } + + @NonNull + @Override + public Lifecycle getLifecycle() { + return mLifecycle; + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java index bc1c1e12203e..2f582727c766 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java @@ -38,6 +38,7 @@ import com.android.systemui.R; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.statusbar.policy.LocationController; import java.text.DateFormat; import java.time.LocalTime; @@ -60,12 +61,14 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements private static final String PATTERN_HOUR_NINUTE_24 = "HH:mm"; private final ColorDisplayManager mManager; + private final LocationController mLocationController; private NightDisplayListener mListener; private boolean mIsListening; @Inject - public NightDisplayTile(QSHost host) { + public NightDisplayTile(QSHost host, LocationController locationController) { super(host); + mLocationController = locationController; mManager = mContext.getSystemService(ColorDisplayManager.class); mListener = new NightDisplayListener(mContext, new Handler(Looper.myLooper())); } @@ -132,6 +135,7 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements private String getSecondaryLabel(boolean isNightLightActivated) { switch (mManager.getNightDisplayAutoMode()) { case ColorDisplayManager.AUTO_MODE_TWILIGHT: + if (!mLocationController.isLocationEnabled()) return null; // Auto mode related to sunrise & sunset. If the light is on, it's guaranteed to be // turned off at sunrise. If it's off, it's guaranteed to be turned on at sunset. return isNightLightActivated diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java index 666323766c12..9cee7e7ccba4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java @@ -72,6 +72,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> state.value = isRecording || isStarting; state.state = (isRecording || isStarting) ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; + state.label = mContext.getString(R.string.quick_settings_screen_record_label); if (isRecording) { state.icon = ResourceIcon.get(R.drawable.ic_qs_screenrecord); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java index b90ca01df481..7b83c20d4b86 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java @@ -31,6 +31,7 @@ import com.android.systemui.qs.QSHost; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.LocationController; import java.time.LocalTime; import java.time.format.DateTimeFormatter; @@ -51,13 +52,15 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements com.android.internal.R.drawable.ic_qs_ui_mode_night); private final UiModeManager mUiModeManager; private final BatteryController mBatteryController; + private final LocationController mLocationController; @Inject public UiModeNightTile(QSHost host, ConfigurationController configurationController, - BatteryController batteryController) { + BatteryController batteryController, LocationController locationController) { super(host); mBatteryController = batteryController; mUiModeManager = mContext.getSystemService(UiModeManager.class); + mLocationController = locationController; configurationController.observe(getLifecycle(), this); batteryController.observe(getLifecycle(), this); } @@ -97,7 +100,8 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements if (powerSave) { state.secondaryLabel = mContext.getResources().getString( R.string.quick_settings_dark_mode_secondary_label_battery_saver); - } else if (uiMode == UiModeManager.MODE_NIGHT_AUTO) { + } else if (uiMode == UiModeManager.MODE_NIGHT_AUTO + && mLocationController.isLocationEnabled()) { state.secondaryLabel = mContext.getResources().getString(nightMode ? R.string.quick_settings_dark_mode_secondary_label_until_sunrise : R.string.quick_settings_dark_mode_secondary_label_on_at_sunset); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java index 4f9052709870..447f48b5db94 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java @@ -18,6 +18,8 @@ package com.android.systemui.qs.tiles; import android.content.Context; import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -29,6 +31,7 @@ import com.android.settingslib.RestrictedLockUtils; import com.android.systemui.R; import com.android.systemui.qs.PseudoGridView; import com.android.systemui.statusbar.policy.UserSwitcherController; + /** * Quick settings detail view for user switching. */ @@ -101,6 +104,19 @@ public class UserDetailView extends PseudoGridView { return v; } + private static Drawable getDrawable(Context context, + UserSwitcherController.UserRecord item) { + Drawable icon = getIconDrawable(context, item); + int iconColorRes = item.isCurrent ? R.color.qs_user_switcher_selected_avatar_icon_color + : R.color.qs_user_switcher_avatar_icon_color; + icon.setTint(context.getResources().getColor(iconColorRes, context.getTheme())); + + int bgRes = item.isCurrent ? R.drawable.bg_avatar_selected : R.drawable.qs_bg_avatar; + Drawable bg = context.getDrawable(bgRes); + LayerDrawable drawable = new LayerDrawable(new Drawable[]{bg, icon}); + return drawable; + } + @Override public void onClick(View view) { UserSwitcherController.UserRecord tag = diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 1780fb1848e7..e1cc0b0c90c2 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -422,6 +422,8 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mDismissButton.setVisibility(View.GONE); mScreenshotView.setVisibility(View.GONE); mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null); + mScreenshotView.setContentDescription( + mContext.getResources().getString(R.string.screenshot_preview_description)); } /** @@ -606,6 +608,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset Log.e(TAG, "Intent cancelled", e); } }); + mScreenshotView.setContentDescription(action.title); } mActionsView.addView(actionChip); } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 366ef931e1f5..2df450604d3b 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -1042,7 +1042,8 @@ public class DividerView extends FrameLayout implements OnTouchListener, dockedTaskRect = dockedTaskRect == null ? dockedRect : dockedTaskRect; otherTaskRect = otherTaskRect == null ? otherRect : otherTaskRect; - mDividerPositionX = dockedRect.right; + mDividerPositionX = mSplitLayout.getPrimarySplitSide() == DOCKED_RIGHT + ? otherRect.right : dockedRect.right; mDividerPositionY = dockedRect.bottom; if (DEBUG) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java index 3b8addb85d85..92f6b4a2d8c4 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitDisplayLayout.java @@ -101,7 +101,16 @@ public class SplitDisplayLayout { } int getPrimarySplitSide() { - return mDisplayLayout.isLandscape() ? DOCKED_LEFT : DOCKED_TOP; + switch (mDisplayLayout.getNavigationBarPosition(mContext.getResources())) { + case DisplayLayout.NAV_BAR_BOTTOM: + return mDisplayLayout.isLandscape() ? DOCKED_LEFT : DOCKED_TOP; + case DisplayLayout.NAV_BAR_LEFT: + return DOCKED_RIGHT; + case DisplayLayout.NAV_BAR_RIGHT: + return DOCKED_LEFT; + default: + return DOCKED_INVALID; + } } boolean isMinimized() { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java index 91d638e70677..a4b1310687aa 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java @@ -105,10 +105,6 @@ class SplitScreenTaskOrganizer extends TaskOrganizer { mDivider.getHandler().post(() -> handleTaskInfoChanged(taskInfo)); } - @Override - public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { - } - /** * This is effectively a finite state machine which moves between the various split-screen * presentations based on the contents of the split regions. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index fd44f04a0d80..0d7715958995 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -37,6 +37,7 @@ import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK import com.android.systemui.statusbar.phone.NotificationShadeWindowController import com.android.systemui.statusbar.phone.PanelExpansionListener +import com.android.systemui.statusbar.phone.ScrimController import com.android.systemui.statusbar.policy.KeyguardStateController import java.io.FileDescriptor import java.io.PrintWriter @@ -74,6 +75,7 @@ class NotificationShadeDepthController @Inject constructor( var shadeSpring = DepthAnimation() @VisibleForTesting var globalActionsSpring = DepthAnimation() + var showingHomeControls: Boolean = false @VisibleForTesting var brightnessMirrorSpring = DepthAnimation() @@ -105,6 +107,16 @@ class NotificationShadeDepthController @Inject constructor( } /** + * Force stop blur effect when necessary. + */ + private var scrimsVisible: Boolean = false + set(value) { + if (field == value) return + field = value + scheduleUpdate() + } + + /** * Blur radius of the wake-up animation on this frame. */ private var wakeAndUnlockBlurRadius = 0 @@ -133,7 +145,20 @@ class NotificationShadeDepthController @Inject constructor( shadeRadius = 0f } } - val blur = max(shadeRadius.toInt(), globalActionsSpring.radius) + + // Home controls have black background, this means that we should not have blur when they + // are fully visible, otherwise we'll enter Client Composition unnecessarily. + var globalActionsRadius = globalActionsSpring.radius + if (showingHomeControls) { + globalActionsRadius = 0 + } + var blur = max(shadeRadius.toInt(), globalActionsRadius) + + // Make blur be 0 if it is necessary to stop blur effect. + if (scrimsVisible) { + blur = 0 + } + blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur) try { wallpaperManager.setWallpaperZoomOut(root.windowToken, @@ -193,6 +218,10 @@ class NotificationShadeDepthController @Inject constructor( brightnessMirrorSpring.finishIfRunning() } } + + override fun onDozeAmountChanged(linear: Float, eased: Float) { + wakeAndUnlockBlurRadius = blurUtils.blurRadiusOfRatio(eased) + } } init { @@ -201,6 +230,10 @@ class NotificationShadeDepthController @Inject constructor( keyguardStateController.addCallback(keyguardStateCallback) } statusBarStateController.addCallback(statusBarStateCallback) + notificationShadeWindowController.setScrimsVisibilityListener { + // Stop blur effect when scrims is opaque to avoid unnecessary GPU composition. + visibility -> scrimsVisible = visibility == ScrimController.OPAQUE + } } /** @@ -216,7 +249,8 @@ class NotificationShadeDepthController @Inject constructor( private fun updateShadeBlur() { var newBlur = 0 - if (statusBarStateController.state == StatusBarState.SHADE) { + val state = statusBarStateController.state + if (state == StatusBarState.SHADE || state == StatusBarState.SHADE_LOCKED) { newBlur = blurUtils.blurRadiusOfRatio(shadeExpansion) } shadeSpring.animateTo(newBlur) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt index 1696f0715865..53ec57090321 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt @@ -103,12 +103,20 @@ class ConversationNotificationManager @Inject constructor( override fun onEntryInflated(entry: NotificationEntry) { if (!entry.ranking.isConversation) return fun updateCount(isExpanded: Boolean) { - if (isExpanded && !notifPanelCollapsed) { + if (isExpanded && (!notifPanelCollapsed || entry.isPinnedAndExpanded())) { resetCount(entry.key) entry.row?.let(::resetBadgeUi) } } - entry.row?.setOnExpansionChangedListener(::updateCount) + entry.row?.setOnExpansionChangedListener { isExpanded -> + if (entry.row?.isShown == true && isExpanded) { + entry.row.performOnIntrinsicHeightReached { + updateCount(isExpanded) + } + } else { + updateCount(isExpanded) + } + } updateCount(entry.row?.isExpanded == true) } @@ -169,7 +177,8 @@ class ConversationNotificationManager @Inject constructor( private fun resetBadgeUi(row: ExpandableNotificationRow): Unit = (row.layouts?.asSequence() ?: emptySequence()) - .mapNotNull { layout -> layout.contractedChild as? ConversationLayout } + .flatMap { layout -> layout.allViews.asSequence()} + .mapNotNull { view -> view as? ConversationLayout } .forEach { convoLayout -> convoLayout.setUnreadCount(0) } private data class ConversationState(val unreadCount: Int, val notification: Notification) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationChannelHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationChannelHelper.java new file mode 100644 index 000000000000..ff945d15a4ed --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationChannelHelper.java @@ -0,0 +1,84 @@ +/* + * 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.statusbar.notification; + +import android.app.INotificationManager; +import android.app.Notification; +import android.app.NotificationChannel; +import android.content.Context; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.UserHandle; +import android.text.TextUtils; +import android.util.Slog; + +import com.android.systemui.R; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +/** + * Helps SystemUI create notification channels. + */ +public class NotificationChannelHelper { + private static final String TAG = "NotificationChannelHelper"; + + /** Creates a conversation channel based on the shortcut info or notification title. */ + public static NotificationChannel createConversationChannelIfNeeded( + Context context, + INotificationManager notificationManager, + NotificationEntry entry, + NotificationChannel channel) { + if (!TextUtils.isEmpty(channel.getConversationId())) { + return channel; + } + final String conversationId = entry.getSbn().getShortcutId(context); + final String pkg = entry.getSbn().getPackageName(); + final int appUid = entry.getSbn().getUid(); + if (TextUtils.isEmpty(conversationId) || TextUtils.isEmpty(pkg)) { + return channel; + } + + String name; + if (entry.getRanking().getShortcutInfo() != null) { + name = entry.getRanking().getShortcutInfo().getShortLabel().toString(); + } else { + Bundle extras = entry.getSbn().getNotification().extras; + String nameString = extras.getString(Notification.EXTRA_CONVERSATION_TITLE); + if (TextUtils.isEmpty(nameString)) { + nameString = extras.getString(Notification.EXTRA_TITLE); + } + name = nameString; + } + + // If this channel is not already a customized conversation channel, create + // a custom channel + try { + // TODO: When shortcuts are enforced remove this and use the shortcut label for naming + channel.setName(context.getString( + R.string.notification_summary_message_format, + name, channel.getName())); + notificationManager.createConversationNotificationChannelForPackage( + pkg, appUid, entry.getSbn().getKey(), channel, + conversationId); + channel = notificationManager.getConversationNotificationChannel( + context.getOpPackageName(), UserHandle.getUserId(appUid), pkg, + channel.getId(), false, conversationId); + } catch (RemoteException e) { + Slog.e(TAG, "Could not create conversation channel", e); + } + return channel; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java index c8b34f1f5b27..4e6df0ad1ba4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java @@ -75,6 +75,9 @@ public final class NotificationClicker implements View.OnClickListener { // We never want to open the app directly if the user clicks in between // the notifications. return; + } else if (row.areGutsExposed()) { + // ignore click if guts are exposed + return; } // Mark notification for one frame. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 295adae9c9ee..d37e16b17620 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -24,6 +24,7 @@ import static com.android.systemui.statusbar.notification.row.NotificationRowCon import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Notification; +import android.os.SystemClock; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.NotificationListenerService.RankingMap; @@ -87,14 +88,11 @@ import dagger.Lazy; * @see #getActiveNotificationUnfiltered(String) to check if a key exists * @see #getPendingNotificationsIterator() for an iterator over the pending notifications * @see #getPendingOrActiveNotif(String) to find a notification exists for that key in any list - * @see #getPendingAndActiveNotifications() to get the entire set of Notifications that we're - * aware of * @see #getActiveNotificationsForCurrentUser() to see every notification that the current user owns */ public class NotificationEntryManager implements CommonNotifCollection, Dumpable, - InflationCallback, VisualStabilityManager.Callback { private static final String TAG = "NotificationEntryMgr"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -308,12 +306,7 @@ public class NotificationEntryManager implements * * WARNING: this will call back into us. Don't hold any locks. */ - @Override - public void handleInflationException(NotificationEntry n, Exception e) { - handleInflationException(n.getSbn(), e); - } - - public void handleInflationException(StatusBarNotification n, Exception e) { + private void handleInflationException(StatusBarNotification n, Exception e) { removeNotificationInternal( n.getKey(), null, null, true /* forceRemove */, false /* removedByUser */, REASON_ERROR); @@ -322,30 +315,37 @@ public class NotificationEntryManager implements } } - @Override - public void onAsyncInflationFinished(NotificationEntry entry) { - mPendingNotifications.remove(entry.getKey()); - // If there was an async task started after the removal, we don't want to add it back to - // the list, otherwise we might get leaks. - if (!entry.isRowRemoved()) { - boolean isNew = getActiveNotificationUnfiltered(entry.getKey()) == null; - mLogger.logNotifInflated(entry.getKey(), isNew); - if (isNew) { - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onEntryInflated(entry); - } - addActiveNotification(entry); - updateNotifications("onAsyncInflationFinished"); - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onNotificationAdded(entry); - } - } else { - for (NotificationEntryListener listener : mNotificationEntryListeners) { - listener.onEntryReinflated(entry); + private final InflationCallback mInflationCallback = new InflationCallback() { + @Override + public void handleInflationException(NotificationEntry entry, Exception e) { + NotificationEntryManager.this.handleInflationException(entry.getSbn(), e); + } + + @Override + public void onAsyncInflationFinished(NotificationEntry entry) { + mPendingNotifications.remove(entry.getKey()); + // If there was an async task started after the removal, we don't want to add it back to + // the list, otherwise we might get leaks. + if (!entry.isRowRemoved()) { + boolean isNew = getActiveNotificationUnfiltered(entry.getKey()) == null; + mLogger.logNotifInflated(entry.getKey(), isNew); + if (isNew) { + for (NotificationEntryListener listener : mNotificationEntryListeners) { + listener.onEntryInflated(entry); + } + addActiveNotification(entry); + updateNotifications("onAsyncInflationFinished"); + for (NotificationEntryListener listener : mNotificationEntryListeners) { + listener.onNotificationAdded(entry); + } + } else { + for (NotificationEntryListener listener : mNotificationEntryListeners) { + listener.onEntryReinflated(entry); + } } } } - } + }; private final NotificationHandler mNotifListener = new NotificationHandler() { @Override @@ -555,7 +555,11 @@ public class NotificationEntryManager implements NotificationEntry entry = new NotificationEntry( notification, ranking, - mFgsFeatureController.isForegroundServiceDismissalEnabled()); + mFgsFeatureController.isForegroundServiceDismissalEnabled(), + SystemClock.uptimeMillis()); + for (NotifCollectionListener listener : mNotifCollectionListeners) { + listener.onEntryBind(entry, notification); + } mAllNotifications.add(entry); mLeakDetector.trackInstance(entry); @@ -567,8 +571,10 @@ public class NotificationEntryManager implements // Construct the expanded view. if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { mNotificationRowBinderLazy.get() - .inflateViews(entry, () -> performRemoveNotification(notification, - REASON_CANCEL)); + .inflateViews( + entry, + () -> performRemoveNotification(notification, REASON_CANCEL), + mInflationCallback); } abortExistingInflation(key, "addNotification"); @@ -611,7 +617,9 @@ public class NotificationEntryManager implements updateRankingAndSort(ranking, "updateNotificationInternal"); StatusBarNotification oldSbn = entry.getSbn(); entry.setSbn(notification); - mGroupManager.onEntryUpdated(entry, oldSbn); + for (NotifCollectionListener listener : mNotifCollectionListeners) { + listener.onEntryBind(entry, notification); + } mGroupManager.onEntryUpdated(entry, oldSbn); mLogger.logNotifUpdated(entry.getKey()); for (NotificationEntryListener listener : mNotificationEntryListeners) { @@ -623,8 +631,10 @@ public class NotificationEntryManager implements if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { mNotificationRowBinderLazy.get() - .inflateViews(entry, () -> performRemoveNotification(notification, - REASON_CANCEL)); + .inflateViews( + entry, + () -> performRemoveNotification(notification, REASON_CANCEL), + mInflationCallback); } updateNotifications("updateNotificationInternal"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java index 9c2cac71925e..a3621b6cabf6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java @@ -47,6 +47,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.Notification; import android.os.RemoteException; +import android.os.SystemClock; import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; @@ -64,6 +65,7 @@ import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.notification.collection.coalescer.CoalescedEvent; import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer; import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer.BatchableNotificationHandler; +import com.android.systemui.statusbar.notification.collection.notifcollection.BindEntryEvent; import com.android.systemui.statusbar.notification.collection.notifcollection.CleanUpEntryEvent; import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; @@ -387,7 +389,8 @@ public class NotifCollection implements Dumpable { if (entry == null) { // A new notification! - entry = new NotificationEntry(sbn, ranking); + entry = new NotificationEntry(sbn, ranking, SystemClock.uptimeMillis()); + mEventQueue.add(new BindEntryEvent(entry, sbn)); mNotificationSet.put(sbn.getKey(), entry); mLogger.logNotifPosted(sbn.getKey()); @@ -408,6 +411,7 @@ public class NotifCollection implements Dumpable { entry.mCancellationReason = REASON_NOT_CANCELED; entry.setSbn(sbn); + mEventQueue.add(new BindEntryEvent(entry, sbn)); mLogger.logNotifUpdated(sbn.getKey()); mEventQueue.add(new EntryUpdatedEvent(entry)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java index 1f6413b525cb..d081e114855e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java @@ -47,7 +47,6 @@ public class NotifInflaterImpl implements NotifInflater { private final NotifPipeline mNotifPipeline; private NotificationRowBinderImpl mNotificationRowBinder; - private InflationCallback mExternalInflationCallback; @Inject public NotifInflaterImpl( @@ -66,17 +65,11 @@ public class NotifInflaterImpl implements NotifInflater { */ public void setRowBinder(NotificationRowBinderImpl rowBinder) { mNotificationRowBinder = rowBinder; - mNotificationRowBinder.setInflationCallback(mInflationCallback); } @Override - public void setInflationCallback(InflationCallback callback) { - mExternalInflationCallback = callback; - } - - @Override - public void rebindViews(NotificationEntry entry) { - inflateViews(entry); + public void rebindViews(NotificationEntry entry, InflationCallback callback) { + inflateViews(entry, callback); } /** @@ -84,11 +77,14 @@ public class NotifInflaterImpl implements NotifInflater { * views are bound. */ @Override - public void inflateViews(NotificationEntry entry) { + public void inflateViews(NotificationEntry entry, InflationCallback callback) { try { - requireBinder().inflateViews(entry, getDismissCallback(entry)); + requireBinder().inflateViews( + entry, + getDismissCallback(entry), + wrapInflationCallback(callback)); } catch (InflationException e) { - // logged in mInflationCallback.handleInflationException + mNotifErrorManager.setInflationError(entry, e); } } @@ -121,6 +117,26 @@ public class NotifInflaterImpl implements NotifInflater { }; } + private NotificationContentInflater.InflationCallback wrapInflationCallback( + InflationCallback callback) { + return new NotificationContentInflater.InflationCallback() { + @Override + public void handleInflationException( + NotificationEntry entry, + Exception e) { + mNotifErrorManager.setInflationError(entry, e); + } + + @Override + public void onAsyncInflationFinished(NotificationEntry entry) { + mNotifErrorManager.clearInflationError(entry); + if (callback != null) { + callback.onInflationFinished(entry); + } + } + }; + } + private NotificationRowBinderImpl requireBinder() { if (mNotificationRowBinder == null) { throw new RuntimeException("NotificationRowBinder must be attached before using " @@ -128,22 +144,4 @@ public class NotifInflaterImpl implements NotifInflater { } return mNotificationRowBinder; } - - private final NotificationContentInflater.InflationCallback mInflationCallback = - new NotificationContentInflater.InflationCallback() { - @Override - public void handleInflationException( - NotificationEntry entry, - Exception e) { - mNotifErrorManager.setInflationError(entry, e); - } - - @Override - public void onAsyncInflationFinished(NotificationEntry entry) { - mNotifErrorManager.clearInflationError(entry); - if (mExternalInflationCallback != null) { - mExternalInflationCallback.onInflationFinished(entry); - } - } - }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index dd7be2775209..749c3e4c9d0d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -35,6 +35,7 @@ import static com.android.systemui.statusbar.notification.stack.NotificationSect import static java.util.Objects.requireNonNull; +import android.annotation.CurrentTimeMillisLong; import android.app.Notification; import android.app.Notification.MessagingStyle.Message; import android.app.NotificationChannel; @@ -93,6 +94,7 @@ public final class NotificationEntry extends ListEntry { private final String mKey; private StatusBarNotification mSbn; private Ranking mRanking; + private long mCreationTime; /* * Bookkeeping members @@ -171,21 +173,29 @@ public final class NotificationEntry extends ListEntry { private boolean mAllowFgsDismissal; private int mBucket = BUCKET_ALERTING; + /** + * @param sbn the StatusBarNotification from system server + * @param ranking also from system server + * @param creationTime SystemClock.uptimeMillis of when we were created + */ public NotificationEntry( @NonNull StatusBarNotification sbn, - @NonNull Ranking ranking) { - this(sbn, ranking, false); + @NonNull Ranking ranking, + long creationTime) { + this(sbn, ranking, false, creationTime); } public NotificationEntry( @NonNull StatusBarNotification sbn, @NonNull Ranking ranking, - boolean allowFgsDismissal + boolean allowFgsDismissal, + long creationTime ) { super(requireNonNull(Objects.requireNonNull(sbn).getKey())); requireNonNull(ranking); + mCreationTime = creationTime; mKey = sbn.getKey(); setSbn(sbn); setRanking(ranking); @@ -238,6 +248,21 @@ public final class NotificationEntry extends ListEntry { } /** + * A timestamp of SystemClock.uptimeMillis() of when this entry was first created, regardless + * of any changes to the data presented. It is set once on creation and will never change, and + * allows us to know exactly how long this notification has been alive for in our listener + * service. It is entirely unrelated to the information inside of the notification. + * + * This is different to Notification#when because it persists throughout updates, whereas + * system server treats every single call to notify() as a new notification and we handle + * updates to NotificationEntry locally. + */ + @CurrentTimeMillisLong + public long getCreationTime() { + return mCreationTime; + } + + /** * Should only be called by NotificationEntryManager and friends. * TODO: Make this package-private */ @@ -383,15 +408,6 @@ public final class NotificationEntry extends ListEntry { return wasBubble != isBubble(); } - /** - * Resets the notification entry to be re-used. - */ - public void reset() { - if (row != null) { - row.reset(); - } - } - @NotificationSectionsManager.PriorityBucket public int getBucket() { return mBucket; @@ -601,6 +617,13 @@ public final class NotificationEntry extends ListEntry { return row != null && row.isPinned(); } + /** + * Is this entry pinned and was expanded while doing so + */ + public boolean isPinnedAndExpanded() { + return row != null && row.isPinnedAndExpanded(); + } + public void setRowPinned(boolean pinned) { if (row != null) row.setPinned(pinned); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt new file mode 100644 index 000000000000..1c1b2bb087f0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt @@ -0,0 +1,56 @@ +/* + * 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.statusbar.notification.collection + +import android.content.Context +import android.content.pm.PackageManager +import android.service.notification.StatusBarNotification +import android.util.Log +import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener +import com.android.systemui.statusbar.phone.StatusBar +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class TargetSdkResolver @Inject constructor( + private val context: Context, + private val collection: CommonNotifCollection +) { + init { + collection.addCollectionListener(object : NotifCollectionListener { + override fun onEntryBind(entry: NotificationEntry, sbn: StatusBarNotification) { + entry.targetSdk = resolveNotificationSdk(sbn) + } + }) + } + + private fun resolveNotificationSdk(sbn: StatusBarNotification): Int { + val pmUser = StatusBar.getPackageManagerForUser(context, sbn.user.identifier) + var targetSdk = 0 + // Extract target SDK version. + try { + val info = pmUser.getApplicationInfo(sbn.packageName, 0) + targetSdk = info.targetSdkVersion + } catch (ex: PackageManager.NameNotFoundException) { + Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.packageName, ex) + } + return targetSdk + } + + private val TAG = "TargetSdkResolver" +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java index 9973ef9ae14e..0e8dd5e24e91 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java @@ -72,7 +72,6 @@ public class PreparationCoordinator implements Coordinator { ) { mLogger = logger; mNotifInflater = notifInflater; - mNotifInflater.setInflationCallback(mInflationCallback); mNotifErrorManager = errorManager; mNotifErrorManager.addInflationErrorListener(mInflationErrorListener); mViewBarn = viewBarn; @@ -218,11 +217,11 @@ public class PreparationCoordinator implements Coordinator { private void inflateEntry(NotificationEntry entry, String reason) { abortInflation(entry, reason); - mNotifInflater.inflateViews(entry); + mNotifInflater.inflateViews(entry, mInflationCallback); } private void rebind(NotificationEntry entry, String reason) { - mNotifInflater.rebindViews(entry); + mNotifInflater.rebindViews(entry, mInflationCallback); } private void abortInflation(NotificationEntry entry, String reason) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java index ea0ece444a67..e3d76113d537 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.java @@ -24,22 +24,20 @@ import com.android.systemui.statusbar.notification.collection.coordinator.Prepar * main thread. When the inflation is finished, NotifInflater will trigger its InflationCallback. */ public interface NotifInflater { - - /** - * Callback used when inflation is finished. - */ - void setInflationCallback(InflationCallback callback); - /** * Called to rebind the entry's views. + * + * @param callback callback called after inflation finishes */ - void rebindViews(NotificationEntry entry); + void rebindViews(NotificationEntry entry, InflationCallback callback); /** * Called to inflate the views of an entry. Views are not considered inflated until all of its * views are bound. Once all views are inflated, the InflationCallback is triggered. + * + * @param callback callback called after inflation finishes */ - void inflateViews(NotificationEntry entry); + void inflateViews(NotificationEntry entry, InflationCallback callback); /** * Request to stop the inflation of an entry. For example, called when a notification is diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java index 3f500644b184..f4c4924b4b9a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java @@ -22,6 +22,7 @@ import com.android.systemui.statusbar.NotificationUiAdjustment; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder; /** * Used by the {@link NotificationEntryManager}. When notifications are added or updated, the binder @@ -37,7 +38,8 @@ public interface NotificationRowBinder { */ void inflateViews( NotificationEntry entry, - Runnable onDismissRunnable) + Runnable onDismissRunnable, + NotificationRowContentBinder.InflationCallback callback) throws InflationException; /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java index 32f1822804f8..73f12f86e52e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java @@ -16,13 +16,11 @@ package com.android.systemui.statusbar.notification.collection.inflation; +import static java.util.Objects.requireNonNull; + import android.annotation.Nullable; import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; import android.os.Build; -import android.service.notification.StatusBarNotification; -import android.util.Log; import android.view.ViewGroup; import com.android.internal.util.NotificationMessagingUtil; @@ -44,9 +42,6 @@ import com.android.systemui.statusbar.notification.row.RowContentBindStage; import com.android.systemui.statusbar.notification.row.RowInflaterTask; import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.phone.StatusBar; - -import java.util.Objects; import javax.inject.Inject; import javax.inject.Provider; @@ -72,7 +67,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { private NotificationPresenter mPresenter; private NotificationListContainer mListContainer; - private NotificationRowContentBinder.InflationCallback mInflationCallback; private BindRowCallback mBindRowCallback; private NotificationClicker mNotificationClicker; @@ -113,10 +107,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { mIconManager.attach(); } - public void setInflationCallback(NotificationRowContentBinder.InflationCallback callback) { - mInflationCallback = callback; - } - public void setNotificationClicker(NotificationClicker clicker) { mNotificationClicker = clicker; } @@ -125,17 +115,19 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { * Inflates the views for the given entry (possibly asynchronously). */ @Override - public void inflateViews(NotificationEntry entry, Runnable onDismissRunnable) + public void inflateViews( + NotificationEntry entry, + Runnable onDismissRunnable, + NotificationRowContentBinder.InflationCallback callback) throws InflationException { ViewGroup parent = mListContainer.getViewParentForNotification(entry); - PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext, - entry.getSbn().getUser().getIdentifier()); - final StatusBarNotification sbn = entry.getSbn(); if (entry.rowExists()) { mIconManager.updateIcons(entry); - entry.reset(); - updateNotification(entry, pmUser, sbn, entry.getRow()); + ExpandableNotificationRow row = entry.getRow(); + row.reset(); + updateRow(entry, row); + inflateContentViews(entry, row, callback); entry.getRowController().setOnDismissRunnable(onDismissRunnable); } else { mIconManager.createIcons(entry); @@ -147,7 +139,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { .expandableNotificationRow(row) .notificationEntry(entry) .onDismissRunnable(onDismissRunnable) - .inflationCallback(mInflationCallback) .rowContentBindStage(mRowContentBindStage) .onExpandClickListener(mPresenter) .build(); @@ -155,26 +146,34 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { component.getExpandableNotificationRowController(); rowController.init(); entry.setRowController(rowController); - bindRow(entry, pmUser, sbn, row); - updateNotification(entry, pmUser, sbn, row); + bindRow(entry, row); + updateRow(entry, row); + inflateContentViews(entry, row, callback); }); } } - //TODO: This method associates a row with an entry, but eventually needs to not do that - private void bindRow(NotificationEntry entry, PackageManager pmUser, - StatusBarNotification sbn, ExpandableNotificationRow row) { + /** + * Bind row to various controllers and managers. This is only called when the row is first + * created. + * + * TODO: This method associates a row with an entry, but eventually needs to not do that + */ + private void bindRow(NotificationEntry entry, ExpandableNotificationRow row) { mListContainer.bindRow(row); mNotificationRemoteInputManager.bindRow(row); + row.setOnActivatedListener(mPresenter); entry.setRow(row); row.setEntry(entry); mNotifBindPipeline.manageRow(entry, row); - mBindRowCallback.onBindRow(entry, pmUser, sbn, row); + mBindRowCallback.onBindRow(row); } /** * Updates the views bound to an entry when the entry's ranking changes, either in-place or by * reinflating them. + * + * TODO: Should this method be in this class? */ @Override public void onNotificationRankingUpdated( @@ -184,11 +183,10 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { NotificationUiAdjustment newAdjustment) { if (NotificationUiAdjustment.needReinflate(oldAdjustment, newAdjustment)) { if (entry.rowExists()) { - entry.reset(); - PackageManager pmUser = StatusBar.getPackageManagerForUser( - mContext, - entry.getSbn().getUser().getIdentifier()); - updateNotification(entry, pmUser, entry.getSbn(), entry.getRow()); + ExpandableNotificationRow row = entry.getRow(); + row.reset(); + updateRow(entry, row); + inflateContentViews(entry, row, null /* callback */); } else { // Once the RowInflaterTask is done, it will pick up the updated entry, so // no-op here. @@ -202,59 +200,53 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { } } - private void updateNotification( + /** + * Update row after the notification has updated. + * + * @param entry notification that has updated + */ + private void updateRow( NotificationEntry entry, - PackageManager pmUser, - StatusBarNotification sbn, ExpandableNotificationRow row) { - - // Extract target SDK version. - try { - ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0); - entry.targetSdk = info.targetSdkVersion; - } catch (PackageManager.NameNotFoundException ex) { - Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex); - } row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP); - // TODO: should this be happening somewhere else? - mIconManager.updateIconTags(entry, entry.targetSdk); - - row.setOnActivatedListener(mPresenter); + // bind the click event to the content area + requireNonNull(mNotificationClicker).register(row, entry.getSbn()); + } + /** + * Inflate the row's basic content views. + */ + private void inflateContentViews( + NotificationEntry entry, + ExpandableNotificationRow row, + NotificationRowContentBinder.InflationCallback inflationCallback) { final boolean useIncreasedCollapsedHeight = - mMessagingUtil.isImportantMessaging(sbn, entry.getImportance()); + mMessagingUtil.isImportantMessaging(entry.getSbn(), entry.getImportance()); final boolean isLowPriority = entry.isAmbient(); RowContentBindParams params = mRowContentBindStage.getStageParams(entry); params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight); params.setUseLowPriority(entry.isAmbient()); - //TODO: Replace this API with RowContentBindParams directly + // TODO: Replace this API with RowContentBindParams directly. Also move to a separate + // redaction controller. row.setNeedsRedaction(mNotificationLockscreenUserManager.needsRedaction(entry)); + params.rebindAllContentViews(); mRowContentBindStage.requestRebind(entry, en -> { row.setUsesIncreasedCollapsedHeight(useIncreasedCollapsedHeight); row.setIsLowPriority(isLowPriority); - mInflationCallback.onAsyncInflationFinished(en); + inflationCallback.onAsyncInflationFinished(en); }); - - // bind the click event to the content area - Objects.requireNonNull(mNotificationClicker).register(row, sbn); } /** Callback for when a row is bound to an entry. */ public interface BindRowCallback { /** - * Called when a new notification and row is created. - * - * @param entry entry for the notification - * @param pmUser package manager for user - * @param sbn notification - * @param row row for the notification + * Called when a new row is created and bound to a notification. */ - void onBindRow(NotificationEntry entry, PackageManager pmUser, - StatusBarNotification sbn, ExpandableNotificationRow row); + void onBindRow(ExpandableNotificationRow row); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java index 41ca52d5a626..59f119e987b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.collection.notifcollection; import android.service.notification.NotificationListenerService; +import android.service.notification.StatusBarNotification; import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -25,6 +26,15 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; * Listener interface for {@link NotificationEntry} events. */ public interface NotifCollectionListener { + + /** + * Called when the entry is having a new status bar notification bound to it. This should + * be used to initialize any derivative state on the entry that needs to update when the + * notification is updated. + */ + default void onEntryBind(NotificationEntry entry, StatusBarNotification sbn) { + } + /** * Called whenever a new {@link NotificationEntry} is initialized. This should be used for * initializing any decorated state tied to the notification. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt index 2ef0368061ba..2810b891373f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.collection.notifcollection import android.service.notification.NotificationListenerService.RankingMap +import android.service.notification.StatusBarNotification import com.android.systemui.statusbar.notification.collection.NotifCollection import com.android.systemui.statusbar.notification.collection.NotificationEntry @@ -37,6 +38,15 @@ sealed class NotifEvent { abstract fun dispatchToListener(listener: NotifCollectionListener) } +data class BindEntryEvent( + val entry: NotificationEntry, + val sbn: StatusBarNotification +) : NotifEvent() { + override fun dispatchToListener(listener: NotifCollectionListener) { + listener.onEntryBind(entry, sbn) + } +} + data class InitEntryEvent( val entry: NotificationEntry ) : NotifEvent() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt index da8ad2da5c87..08be4f872415 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt @@ -172,18 +172,6 @@ class IconManager @Inject constructor( } } - /** - * Updates tags on the icon views to match the posting app's target SDK level - * - * Note that this method MUST be called after both [createIcons] and [updateIcons]. - */ - fun updateIconTags(entry: NotificationEntry, targetSdk: Int) { - setTagOnIconViews( - entry.icons, - R.id.icon_is_pre_L, - targetSdk < Build.VERSION_CODES.LOLLIPOP) - } - private fun updateIconsSafe(entry: NotificationEntry) { try { updateIcons(entry) @@ -259,6 +247,7 @@ class IconManager @Inject constructor( iconView: StatusBarIconView ) { iconView.setShowsConversation(showsConversation(entry, iconView, iconDescriptor)) + iconView.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP) if (!iconView.set(iconDescriptor)) { throw InflationException("Couldn't create icon $iconDescriptor") } @@ -326,20 +315,13 @@ class IconManager @Inject constructor( val usedInSensitiveContext = iconView === entry.icons.shelfIcon || iconView === entry.icons.aodIcon val isSmallIcon = iconDescriptor.icon.equals(entry.sbn.notification.smallIcon) - return isImportantConversation(entry) && !isSmallIcon - && (!usedInSensitiveContext || !entry.isSensitive) + return isImportantConversation(entry) && !isSmallIcon && + (!usedInSensitiveContext || !entry.isSensitive) } private fun isImportantConversation(entry: NotificationEntry): Boolean { return entry.ranking.channel != null && entry.ranking.channel.isImportantConversation } - - private fun setTagOnIconViews(icons: IconPack, key: Int, tag: Any) { - icons.statusBarIcon?.setTag(key, tag) - icons.shelfIcon?.setTag(key, tag) - icons.aodIcon?.setTag(key, tag) - icons.centeredIcon?.setTag(key, tag) - } } private const val TAG = "IconManager"
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index d1cceaeb6dd5..5fac5b1cf159 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -108,8 +108,6 @@ class NotificationsControllerImpl @Inject constructor( if (featureFlags.isNewNotifPipelineRenderingEnabled) { // TODO } else { - notificationRowBinder.setInflationCallback(entryManager) - remoteInputUriController.attach(entryManager) groupAlertTransferHelper.bind(entryManager, groupManager) headsUpManager.addListener(groupManager) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 2917346153d2..85090dcbf748 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -70,6 +70,7 @@ import com.android.internal.widget.CachingIconView; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; @@ -284,6 +285,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (isPinned()) { nowExpanded = !mExpandedWhenPinned; mExpandedWhenPinned = nowExpanded; + // Also notify any expansion changed listeners. This is necessary since the + // expansion doesn't actually change (it's already system expanded) but it + // changes visually + if (mExpansionChangedListener != null) { + mExpansionChangedListener.onExpansionChanged(nowExpanded); + } } else { nowExpanded = !isExpanded(); setUserExpanded(nowExpanded); @@ -326,6 +333,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private NotificationInlineImageResolver mImageResolver; private NotificationMediaManager mMediaManager; @Nullable private OnExpansionChangedListener mExpansionChangedListener; + @Nullable private Runnable mOnIntrinsicHeightReachedRunnable; private SystemNotificationAsyncTask mSystemNotificationAsyncTask = new SystemNotificationAsyncTask(); @@ -358,6 +366,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return Arrays.copyOf(mLayouts, mLayouts.length); } + /** + * Is this entry pinned and was expanded while doing so + */ + public boolean isPinnedAndExpanded() { + if (!isPinned()) { + return false; + } + return mExpandedWhenPinned; + } + @Override public boolean isGroupExpansionChanging() { if (isChildInGroup()) { @@ -562,6 +580,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } } + /** Call when bubble state has changed and the button on the notification should be updated. */ + public void updateBubbleButton() { + for (NotificationContentView l : mLayouts) { + l.updateBubbleButton(mEntry); + } + } + @VisibleForTesting void updateShelfIconColor() { StatusBarIconView expandedIcon = mEntry.getIcons().getShelfIcon(); @@ -1069,6 +1094,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView updateClickAndFocus(); } + /** The click listener for the bubble button. */ + public View.OnClickListener getBubbleClickListener() { + return new View.OnClickListener() { + @Override + public void onClick(View v) { + Dependency.get(BubbleController.class) + .onUserChangedBubble(mEntry, !mEntry.isBubble() /* createBubble */); + mHeadsUpManager.removeNotification(mEntry.getKey(), true /* releaseImmediately */); + } + }; + } + private void updateClickAndFocus() { boolean normalChild = !isChildInGroup() || isGroupExpanded(); boolean clickable = mOnClickListener != null && normalChild; @@ -1250,7 +1287,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mNotificationColor; } - private void updateNotificationColor() { + public void updateNotificationColor() { Configuration currentConfig = getResources().getConfiguration(); boolean nightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; @@ -1596,6 +1633,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mFalsingManager = falsingManager; mStatusbarStateController = statusBarStateController; mPeopleNotificationIdentifier = peopleNotificationIdentifier; + for (NotificationContentView l : mLayouts) { + l.setPeopleNotificationIdentifier(mPeopleNotificationIdentifier); + } } private void initDimens() { @@ -2690,6 +2730,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (mMenuRow != null && mMenuRow.getMenuView() != null) { mMenuRow.onParentHeightUpdate(); } + handleIntrinsicHeightReached(); } @Override @@ -2907,6 +2948,24 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mExpansionChangedListener = listener; } + /** + * Perform an action when the notification height has reached its intrinsic height. + * + * @param runnable the runnable to run + */ + public void performOnIntrinsicHeightReached(@Nullable Runnable runnable) { + mOnIntrinsicHeightReachedRunnable = runnable; + handleIntrinsicHeightReached(); + } + + private void handleIntrinsicHeightReached() { + if (mOnIntrinsicHeightReachedRunnable != null + && getActualHeight() == getIntrinsicHeight()) { + mOnIntrinsicHeightReachedRunnable.run(); + mOnIntrinsicHeightReachedRunnable = null; + } + } + @Override public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfoInternal(info); @@ -2965,9 +3024,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView default: if (action == R.id.action_snooze) { NotificationMenuRowPlugin provider = getProvider(); - if (provider == null && mMenuRow != null) { - provider = createMenu(); - } else { + if (provider == null) { return false; } MenuItem snoozeMenu = provider.getSnoozeMenuItem(getContext()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java index 8b3d06b97882..f8d9c4648ac9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java @@ -60,7 +60,6 @@ public class ExpandableNotificationRowController { private final HeadsUpManager mHeadsUpManager; private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener; private final StatusBarStateController mStatusBarStateController; - private final NotificationRowContentBinder.InflationCallback mInflationCallback; private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger = this::logNotificationExpansion; @@ -82,7 +81,6 @@ public class ExpandableNotificationRowController { NotificationLogger notificationLogger, HeadsUpManager headsUpManager, ExpandableNotificationRow.OnExpandClickListener onExpandClickListener, StatusBarStateController statusBarStateController, - NotificationRowContentBinder.InflationCallback inflationCallback, NotificationGutsManager notificationGutsManager, @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, @DismissRunnable Runnable onDismissRunnable, FalsingManager falsingManager, @@ -101,7 +99,6 @@ public class ExpandableNotificationRowController { mHeadsUpManager = headsUpManager; mOnExpandClickListener = onExpandClickListener; mStatusBarStateController = statusBarStateController; - mInflationCallback = inflationCallback; mNotificationGutsManager = notificationGutsManager; mOnDismissRunnable = onDismissRunnable; mOnAppOpsClickListener = mNotificationGutsManager::openGuts; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java index 893e8490eb90..e4e3ebcf7671 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipeline.java @@ -151,9 +151,12 @@ public final class NotifBindPipeline { * the real work once rather than repeatedly start and cancel it. */ private void requestPipelineRun(NotificationEntry entry) { - mLogger.logRequestPipelineRun(entry.getKey()); - final BindEntry bindEntry = getBindEntry(entry); + if (bindEntry.row == null) { + // Row is not managed yet but may be soon. Stop for now. + return; + } + mLogger.logRequestPipelineRun(entry.getKey()); // Abort any existing pipeline run mStage.abortStage(entry, bindEntry.row); @@ -177,10 +180,6 @@ public final class NotifBindPipeline { final BindEntry bindEntry = mBindEntries.get(entry); final ExpandableNotificationRow row = bindEntry.row; - if (row == null) { - // Row is not managed yet but may be soon. Stop for now. - return; - } mStage.executeStage(entry, row, (en) -> onPipelineComplete(en)); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index b18bf01ea91f..bd1745eaa028 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -16,12 +16,18 @@ package com.android.systemui.statusbar.notification.row; + +import static android.provider.Settings.Global.NOTIFICATION_BUBBLES; + +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.Build; +import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; import android.util.ArraySet; @@ -46,6 +52,7 @@ import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.TransformableView; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -117,6 +124,7 @@ public class NotificationContentView extends FrameLayout { private NotificationGroupManager mGroupManager; private RemoteInputController mRemoteInputController; private Runnable mExpandedVisibleListener; + private PeopleNotificationIdentifier mPeopleIdentifier; /** * List of listeners for when content views become inactive (i.e. not the showing view). */ @@ -453,6 +461,9 @@ public class NotificationContentView extends FrameLayout { mExpandedChild = child; mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child, mContainingNotification); + if (mContainingNotification != null) { + applyBubbleAction(mExpandedChild, mContainingNotification.getEntry()); + } } /** @@ -492,6 +503,9 @@ public class NotificationContentView extends FrameLayout { mHeadsUpChild = child; mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child, mContainingNotification); + if (mContainingNotification != null) { + applyBubbleAction(mHeadsUpChild, mContainingNotification.getEntry()); + } } @Override @@ -988,6 +1002,14 @@ public class NotificationContentView extends FrameLayout { } } + public @NonNull View[] getAllViews() { + return new View[] { + mContractedChild, + mHeadsUpChild, + mExpandedChild, + mSingleLineView }; + } + public NotificationViewWrapper getVisibleWrapper(int visibleType) { switch (visibleType) { case VISIBLE_TYPE_EXPANDED: @@ -1129,6 +1151,8 @@ public class NotificationContentView extends FrameLayout { mForceSelectNextLayout = true; mPreviousExpandedRemoteInputIntent = null; mPreviousHeadsUpRemoteInputIntent = null; + applyBubbleAction(mExpandedChild, entry); + applyBubbleAction(mHeadsUpChild, entry); } private void updateAllSingleLineViews() { @@ -1299,6 +1323,58 @@ public class NotificationContentView extends FrameLayout { return null; } + /** + * Call to update state of the bubble button (i.e. does it show bubble or unbubble or no + * icon at all). + * + * @param entry the new entry to use. + */ + public void updateBubbleButton(NotificationEntry entry) { + applyBubbleAction(mExpandedChild, entry); + } + + private boolean isBubblesEnabled() { + return Settings.Global.getInt(mContext.getContentResolver(), + NOTIFICATION_BUBBLES, 0) == 1; + } + + private void applyBubbleAction(View layout, NotificationEntry entry) { + if (layout == null || mContainingNotification == null || mPeopleIdentifier == null) { + return; + } + ImageView bubbleButton = layout.findViewById(com.android.internal.R.id.bubble_button); + View actionContainer = layout.findViewById(com.android.internal.R.id.actions_container); + if (bubbleButton == null || actionContainer == null) { + return; + } + boolean isPerson = + mPeopleIdentifier.getPeopleNotificationType(entry.getSbn(), entry.getRanking()) + != PeopleNotificationIdentifier.TYPE_NON_PERSON; + boolean showButton = isBubblesEnabled() + && isPerson + && entry.getBubbleMetadata() != null; + if (showButton) { + Drawable d = mContext.getResources().getDrawable(entry.isBubble() + ? R.drawable.ic_stop_bubble + : R.drawable.ic_create_bubble); + mContainingNotification.updateNotificationColor(); + final int tint = mContainingNotification.getNotificationColor(); + d.setTint(tint); + + String contentDescription = mContext.getResources().getString(entry.isBubble() + ? R.string.notification_conversation_unbubble + : R.string.notification_conversation_bubble); + + bubbleButton.setContentDescription(contentDescription); + bubbleButton.setImageDrawable(d); + bubbleButton.setOnClickListener(mContainingNotification.getBubbleClickListener()); + bubbleButton.setVisibility(VISIBLE); + actionContainer.setVisibility(VISIBLE); + } else { + bubbleButton.setVisibility(GONE); + } + } + private void applySmartReplyView( SmartRepliesAndActions smartRepliesAndActions, NotificationEntry entry) { @@ -1503,6 +1579,10 @@ public class NotificationContentView extends FrameLayout { mContainingNotification = containingNotification; } + public void setPeopleNotificationIdentifier(PeopleNotificationIdentifier peopleIdentifier) { + mPeopleIdentifier = peopleIdentifier; + } + public void requestSelectLayout(boolean needsAnimation) { selectLayout(needsAnimation, false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java index 6fc1264d69e2..a27199370b16 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java @@ -17,6 +17,8 @@ package com.android.systemui.statusbar.notification.row; import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; @@ -38,11 +40,9 @@ import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.graphics.drawable.Icon; -import android.os.Bundle; import android.os.Handler; import android.os.Parcelable; import android.os.RemoteException; -import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.transition.ChangeBounds; @@ -51,7 +51,6 @@ import android.transition.TransitionManager; import android.transition.TransitionSet; import android.util.AttributeSet; import android.util.Log; -import android.util.Slog; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.widget.ImageView; @@ -62,6 +61,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.notification.ConversationIconFactory; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.statusbar.notification.NotificationChannelHelper; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -203,7 +203,8 @@ public class NotificationConversationInfo extends LinearLayout implements } mShortcutInfo = entry.getRanking().getShortcutInfo(); - createConversationChannelIfNeeded(); + mNotificationChannel = NotificationChannelHelper.createConversationChannelIfNeeded( + getContext(), mINotificationManager, entry, mNotificationChannel); bindHeader(); bindActions(); @@ -212,27 +213,6 @@ public class NotificationConversationInfo extends LinearLayout implements done.setOnClickListener(mOnDone); } - void createConversationChannelIfNeeded() { - // If this channel is not already a customized conversation channel, create - // a custom channel - if (TextUtils.isEmpty(mNotificationChannel.getConversationId())) { - try { - // TODO: remove - mNotificationChannel.setName(mContext.getString( - R.string.notification_summary_message_format, - getName(), mNotificationChannel.getName())); - mINotificationManager.createConversationNotificationChannelForPackage( - mPackageName, mAppUid, mSbn.getKey(), mNotificationChannel, - mConversationId); - mNotificationChannel = mINotificationManager.getConversationNotificationChannel( - mContext.getOpPackageName(), UserHandle.getUserId(mAppUid), mPackageName, - mNotificationChannel.getId(), false, mConversationId); - } catch (RemoteException e) { - Slog.e(TAG, "Could not create conversation channel", e); - } - } - } - private void bindActions() { // TODO: b/152050825 @@ -316,24 +296,6 @@ public class NotificationConversationInfo extends LinearLayout implements } } - private void bindName() { - TextView name = findViewById(R.id.name); - name.setText(getName()); - } - - private String getName() { - if (mShortcutInfo != null) { - return mShortcutInfo.getShortLabel().toString(); - } else { - Bundle extras = mSbn.getNotification().extras; - String nameString = extras.getString(Notification.EXTRA_CONVERSATION_TITLE); - if (TextUtils.isEmpty(nameString)) { - nameString = extras.getString(Notification.EXTRA_TITLE); - } - return nameString; - } - } - private void bindPackage() { ApplicationInfo info; try { @@ -598,6 +560,13 @@ public class NotificationConversationInfo extends LinearLayout implements !mChannelToUpdate.isImportantConversation()); if (mChannelToUpdate.isImportantConversation()) { mChannelToUpdate.setAllowBubbles(true); + int currentPref = + mINotificationManager.getBubblePreferenceForPackage( + mAppPkg, mAppUid); + if (currentPref == BUBBLE_PREFERENCE_NONE) { + mINotificationManager.setBubblesAllowed(mAppPkg, mAppUid, + BUBBLE_PREFERENCE_SELECTED); + } } mChannelToUpdate.setImportance(Math.max( mChannelToUpdate.getOriginalImportance(), IMPORTANCE_DEFAULT)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java index d65f2c53598c..e56771c62bb5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java @@ -79,6 +79,7 @@ public class NotificationSnooze extends LinearLayout private NotificationSwipeActionHelper mSnoozeListener; private StatusBarNotification mSbn; + private View mSnoozeView; private TextView mSelectedOptionText; private TextView mUndoButton; private ImageView mExpandButton; @@ -122,7 +123,8 @@ public class NotificationSnooze extends LinearLayout protected void onFinishInflate() { super.onFinishInflate(); mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.snooze_snackbar_min_height); - findViewById(R.id.notification_snooze).setOnClickListener(this); + mSnoozeView = findViewById(R.id.notification_snooze); + mSnoozeView.setOnClickListener(this); mSelectedOptionText = (TextView) findViewById(R.id.snooze_option_default); mUndoButton = (TextView) findViewById(R.id.undo); mUndoButton.setOnClickListener(this); @@ -147,16 +149,6 @@ public class NotificationSnooze extends LinearLayout } @Override - public void onInitializeAccessibilityEvent(AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(event); - if (mGutsContainer != null && mGutsContainer.isExposed()) { - if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { - event.getText().add(mSelectedOptionText.getText()); - } - } - } - - @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); info.addAction(new AccessibilityAction(R.id.action_snooze_undo, @@ -341,12 +333,22 @@ public class NotificationSnooze extends LinearLayout mSelectedOptionText.setText(option.getConfirmation()); showSnoozeOptions(false); hideSelectedOption(); - sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); if (userAction) { + mSnoozeView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); logOptionSelection(MetricsEvent.NOTIFICATION_SELECT_SNOOZE, option); } } + @Override + public boolean requestAccessibilityFocus() { + if (mExpanded) { + return super.requestAccessibilityFocus(); + } else { + mSnoozeView.requestAccessibilityFocus(); + return false; + } + } + private void logOptionSelection(int category, SnoozeOption option) { int index = mSnoozeOptions.indexOf(option); long duration = TimeUnit.MINUTES.toMillis(option.getMinutesToSnoozeFor()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java index 6d6d3e446f53..9846f2dcd170 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java @@ -25,7 +25,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; -import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder; import com.android.systemui.statusbar.notification.row.RowContentBindStage; import com.android.systemui.statusbar.phone.StatusBar; @@ -60,8 +59,6 @@ public interface ExpandableNotificationRowComponent { @BindsInstance Builder rowContentBindStage(RowContentBindStage rowContentBindStage); @BindsInstance - Builder inflationCallback(NotificationRowContentBinder.InflationCallback inflationCallback); - @BindsInstance Builder onExpandClickListener(ExpandableNotificationRow.OnExpandClickListener presenter); ExpandableNotificationRowComponent build(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java index 5205bab8fea3..7ac066277c86 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java @@ -169,7 +169,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { @Override public void onContentUpdated(ExpandableNotificationRow row) { super.onContentUpdated(row); - mIsLowPriority = row.isLowPriority(); + mIsLowPriority = row.getEntry().isAmbient(); mTransformLowPriorityTitle = !row.isChildInGroup() && !row.isSummaryWithChildren(); ArraySet<View> previousViews = mTransformationHelper.getAllTransformingViews(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index fb88ea534a91..8c9bb6c75828 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -34,6 +34,7 @@ import com.android.internal.util.LatencyTracker; import com.android.keyguard.KeyguardConstants; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.keyguard.KeyguardViewController; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.dagger.qualifiers.Main; @@ -145,7 +146,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private final Context mContext; private final int mWakeUpDelay; private int mMode; - private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + private KeyguardViewController mKeyguardViewController; private DozeScrimController mDozeScrimController; private KeyguardViewMediator mKeyguardViewMediator; private ScrimController mScrimController; @@ -204,9 +205,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp dumpManager.registerDumpable(getClass().getName(), this); } - public void setStatusBarKeyguardViewManager( - StatusBarKeyguardViewManager statusBarKeyguardViewManager) { - mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; + public void setKeyguardViewController(KeyguardViewController keyguardViewController) { + mKeyguardViewController = keyguardViewController; } private final Runnable mReleaseBiometricWakeLockRunnable = new Runnable() { @@ -328,7 +328,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp case MODE_DISMISS_BOUNCER: case MODE_UNLOCK_FADING: Trace.beginSection("MODE_DISMISS_BOUNCER or MODE_UNLOCK_FADING"); - mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated( + mKeyguardViewController.notifyKeyguardAuthenticated( false /* strongAuth */); Trace.endSection(); break; @@ -376,7 +376,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private void showBouncer() { if (mMode == MODE_SHOW_BOUNCER) { - mStatusBarKeyguardViewManager.showBouncer(false); + mKeyguardViewController.showBouncer(false); } mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */, false /* delayed */, BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR); @@ -431,7 +431,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp boolean deviceDreaming = mUpdateMonitor.isDreaming(); if (!mUpdateMonitor.isDeviceInteractive()) { - if (!mStatusBarKeyguardViewManager.isShowing()) { + if (!mKeyguardViewController.isShowing()) { return MODE_ONLY_WAKE; } else if (mDozeScrimController.isPulsing() && unlockingAllowed) { return MODE_WAKE_AND_UNLOCK_PULSING; @@ -444,12 +444,12 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp if (unlockingAllowed && deviceDreaming) { return MODE_WAKE_AND_UNLOCK_FROM_DREAM; } - if (mStatusBarKeyguardViewManager.isShowing()) { - if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) { + if (mKeyguardViewController.isShowing()) { + if (mKeyguardViewController.bouncerIsOrWillBeShowing() && unlockingAllowed) { return MODE_DISMISS_BOUNCER; } else if (unlockingAllowed) { return MODE_UNLOCK_COLLAPSING; - } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) { + } else if (!mKeyguardViewController.isBouncerShowing()) { return MODE_SHOW_BOUNCER; } } @@ -463,7 +463,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp boolean bypass = mKeyguardBypassController.getBypassEnabled(); if (!mUpdateMonitor.isDeviceInteractive()) { - if (!mStatusBarKeyguardViewManager.isShowing()) { + if (!mKeyguardViewController.isShowing()) { return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE; } else if (!unlockingAllowed) { return bypass ? MODE_SHOW_BOUNCER : MODE_NONE; @@ -484,8 +484,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp if (unlockingAllowed && deviceDreaming) { return bypass ? MODE_WAKE_AND_UNLOCK_FROM_DREAM : MODE_ONLY_WAKE; } - if (mStatusBarKeyguardViewManager.isShowing()) { - if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) { + if (mKeyguardViewController.isShowing()) { + if (mKeyguardViewController.bouncerIsOrWillBeShowing() && unlockingAllowed) { if (bypass && mKeyguardBypassController.canPlaySubtleWindowAnimations()) { return MODE_UNLOCK_FADING; } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index f06cfec9480a..82e02b47974c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -203,7 +203,9 @@ public class KeyguardBouncer { Log.wtf(TAG, "onFullyShown when view was null"); } else { mKeyguardView.onResume(); - mRoot.announceForAccessibility(mKeyguardView.getAccessibilityTitleForCurrentMode()); + if (mRoot != null) { + mRoot.announceForAccessibility(mKeyguardView.getAccessibilityTitleForCurrentMode()); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java index d70484e9cf41..a19d35ac4e81 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java @@ -50,19 +50,22 @@ public class LockIcon extends KeyguardAffordanceView { static final int STATE_BIOMETRICS_ERROR = 3; private float mDozeAmount; private int mIconColor; - private StateProvider mStateProvider; private int mOldState; + private int mState; private boolean mPulsing; private boolean mDozing; private boolean mKeyguardJustShown; + private boolean mPredrawRegistered; private final SparseArray<Drawable> mDrawableCache = new SparseArray<>(); private final OnPreDrawListener mOnPreDrawListener = new OnPreDrawListener() { @Override public boolean onPreDraw() { getViewTreeObserver().removeOnPreDrawListener(this); + mPredrawRegistered = false; - int newState = mStateProvider.getState(); + int newState = mState; + mOldState = mState; Drawable icon = getIcon(newState); setImageDrawable(icon, false); @@ -80,7 +83,7 @@ public class LockIcon extends KeyguardAffordanceView { @Override public void onAnimationEnd(Drawable drawable) { if (getDrawable() == animation - && newState == mStateProvider.getState() + && newState == mState && newState == STATE_SCANNING_FACE) { animation.start(); } else { @@ -100,10 +103,6 @@ public class LockIcon extends KeyguardAffordanceView { super(context, attrs); } - void setStateProvider(StateProvider stateProvider) { - mStateProvider = stateProvider; - } - @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); @@ -135,13 +134,16 @@ public class LockIcon extends KeyguardAffordanceView { return false; } - void update(int oldState, boolean pulsing, boolean dozing, boolean keyguardJustShown) { - mOldState = oldState; + void update(int newState, boolean pulsing, boolean dozing, boolean keyguardJustShown) { + mState = newState; mPulsing = pulsing; mDozing = dozing; mKeyguardJustShown = keyguardJustShown; - getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener); + if (!mPredrawRegistered) { + mPredrawRegistered = true; + getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener); + } } void setDozeAmount(float dozeAmount) { @@ -175,7 +177,7 @@ public class LockIcon extends KeyguardAffordanceView { return mDrawableCache.get(iconRes); } - static int getIconForState(int state) { + private static int getIconForState(int state) { int iconRes; switch (state) { case STATE_LOCKED: @@ -196,7 +198,7 @@ public class LockIcon extends KeyguardAffordanceView { return iconRes; } - static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing, + private static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing, boolean dozing, boolean keyguardJustShown) { // Never animate when screen is off @@ -260,9 +262,4 @@ public class LockIcon extends KeyguardAffordanceView { } return LOCK_ANIM_RES_IDS[0][lockAnimIndex]; } - - interface StateProvider { - int getState(); - } - } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java index f7c861b84a68..a633e1979bad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java @@ -352,7 +352,6 @@ public class LockscreenLockIconController { mLockIcon.setOnClickListener(this::handleClick); mLockIcon.setOnLongClickListener(this::handleLongClick); mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate); - mLockIcon.setStateProvider(this::getState); if (mLockIcon.isAttachedToWindow()) { mOnAttachStateChangeListener.onViewAttachedToWindow(mLockIcon); @@ -462,7 +461,7 @@ public class LockscreenLockIconController { shouldUpdate = false; } if (shouldUpdate && mLockIcon != null) { - mLockIcon.update(mLastState, mPulsing, mDozing, mKeyguardJustShown); + mLockIcon.update(state, mPulsing, mDozing, mKeyguardJustShown); } mLastState = state; mKeyguardJustShown = false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java index e1e679f06eef..462b42a44c17 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java @@ -61,6 +61,7 @@ import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; +import java.util.function.Consumer; import javax.inject.Inject; import javax.inject.Singleton; @@ -92,6 +93,7 @@ public class NotificationShadeWindowController implements Callback, Dumpable, private final State mCurrentState = new State(); private OtherwisedCollapsedListener mListener; private ForcePluginOpenListener mForcePluginOpenListener; + private Consumer<Integer> mScrimsVisibilityListener; private final ArrayList<WeakReference<StatusBarWindowCallback>> mCallbacks = Lists.newArrayList(); @@ -150,6 +152,16 @@ public class NotificationShadeWindowController implements Callback, Dumpable, mCallbacks.add(new WeakReference<StatusBarWindowCallback>(callback)); } + /** + * Register a listener to monitor scrims visibility + * @param listener A listener to monitor scrims visibility + */ + public void setScrimsVisibilityListener(Consumer<Integer> listener) { + if (listener != null && mScrimsVisibilityListener != listener) { + mScrimsVisibilityListener = listener; + } + } + private boolean shouldEnableKeyguardScreenRotation() { Resources res = mContext.getResources(); return SystemProperties.getBoolean("lockscreen.rot_override", false) @@ -477,6 +489,7 @@ public class NotificationShadeWindowController implements Callback, Dumpable, public void setScrimsVisibility(int scrimsVisibility) { mCurrentState.mScrimsVisibility = scrimsVisibility; apply(mCurrentState); + mScrimsVisibilityListener.accept(scrimsVisibility); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 14af466a2424..d4f4d3bfbb54 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -39,6 +39,8 @@ import android.telecom.TelecomManager; import android.text.format.DateFormat; import android.util.Log; +import androidx.lifecycle.Observer; + import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.DisplayId; @@ -64,6 +66,7 @@ import com.android.systemui.statusbar.policy.RotationLockController.RotationLock import com.android.systemui.statusbar.policy.SensorPrivacyController; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.RingerModeTracker; import com.android.systemui.util.time.DateFormatUtil; import java.util.Locale; @@ -109,7 +112,6 @@ public class PhoneStatusBarPolicy private final SharedPreferences mSharedPreferences; private final DateFormatUtil mDateFormatUtil; private final TelecomManager mTelecomManager; - private final AudioManager mAudioManager; private final Handler mHandler = new Handler(); private final CastController mCast; @@ -132,6 +134,7 @@ public class PhoneStatusBarPolicy private final Executor mUiBgExecutor; private final SensorPrivacyController mSensorPrivacyController; private final RecordingController mRecordingController; + private final RingerModeTracker mRingerModeTracker; private boolean mZenVisible; private boolean mVolumeVisible; @@ -154,10 +157,11 @@ public class PhoneStatusBarPolicy KeyguardStateController keyguardStateController, LocationController locationController, SensorPrivacyController sensorPrivacyController, IActivityManager iActivityManager, - AlarmManager alarmManager, UserManager userManager, AudioManager audioManager, + AlarmManager alarmManager, UserManager userManager, RecordingController recordingController, @Nullable TelecomManager telecomManager, @DisplayId int displayId, - @Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil) { + @Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil, + RingerModeTracker ringerModeTracker) { mIconController = iconController; mCommandQueue = commandQueue; mBroadcastDispatcher = broadcastDispatcher; @@ -179,8 +183,8 @@ public class PhoneStatusBarPolicy mSensorPrivacyController = sensorPrivacyController; mRecordingController = recordingController; mUiBgExecutor = uiBgExecutor; - mAudioManager = audioManager; mTelecomManager = telecomManager; + mRingerModeTracker = ringerModeTracker; mSlotCast = resources.getString(com.android.internal.R.string.status_bar_cast); mSlotHotspot = resources.getString(com.android.internal.R.string.status_bar_hotspot); @@ -208,8 +212,7 @@ public class PhoneStatusBarPolicy public void init() { // listen for broadcasts IntentFilter filter = new IntentFilter(); - filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); - filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION); + filter.addAction(AudioManager.ACTION_HEADSET_PLUG); filter.addAction(Intent.ACTION_SIM_STATE_CHANGED); filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED); @@ -217,6 +220,10 @@ public class PhoneStatusBarPolicy filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); mBroadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter, mHandler); + Observer<Integer> observer = ringer -> mHandler.post(this::updateVolumeZen); + + mRingerModeTracker.getRingerMode().observeForever(observer); + mRingerModeTracker.getRingerModeInternal().observeForever(observer); // listen for user / profile change. try { @@ -350,14 +357,18 @@ public class PhoneStatusBarPolicy } if (!ZenModeConfig.isZenOverridingRinger(zen, mZenController.getConsolidatedPolicy())) { - if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) { - volumeVisible = true; - volumeIconId = R.drawable.stat_sys_ringer_vibrate; - volumeDescription = mResources.getString(R.string.accessibility_ringer_vibrate); - } else if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) { - volumeVisible = true; - volumeIconId = R.drawable.stat_sys_ringer_silent; - volumeDescription = mResources.getString(R.string.accessibility_ringer_silent); + final Integer ringerModeInternal = + mRingerModeTracker.getRingerModeInternal().getValue(); + if (ringerModeInternal != null) { + if (ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) { + volumeVisible = true; + volumeIconId = R.drawable.stat_sys_ringer_vibrate; + volumeDescription = mResources.getString(R.string.accessibility_ringer_vibrate); + } else if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) { + volumeVisible = true; + volumeIconId = R.drawable.stat_sys_ringer_silent; + volumeDescription = mResources.getString(R.string.accessibility_ringer_silent); + } } } @@ -616,10 +627,6 @@ public class PhoneStatusBarPolicy public void onReceive(Context context, Intent intent) { String action = intent.getAction(); switch (action) { - case AudioManager.RINGER_MODE_CHANGED_ACTION: - case AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION: - updateVolumeZen(); - break; case Intent.ACTION_SIM_STATE_CHANGED: // Avoid rebroadcast because SysUI is direct boot aware. if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index fa55b74606c2..900b3ea97010 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -488,11 +488,9 @@ public class StatusBar extends SystemUI implements DemoMode, WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT); final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean( com.android.internal.R.bool.config_dozeSupportsAodWallpaper); - final boolean imageWallpaperInAmbient = !mDozeParameters.getDisplayNeedsBlanking(); // If WallpaperInfo is null, it must be ImageWallpaper. final boolean supportsAmbientMode = deviceSupportsAodWallpaper - && ((info == null && imageWallpaperInAmbient) - || (info != null && info.supportsAmbientMode())); + && (info != null && info.supportsAmbientMode()); mNotificationShadeWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode); mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode); @@ -1399,7 +1397,7 @@ public class StatusBar extends SystemUI implements DemoMode, mStackScroller, mKeyguardBypassController, mFalsingManager); mKeyguardIndicationController .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); - mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); + mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager); mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 45719c7f3936..ed25db40fea6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -744,14 +744,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb return false; } + @Override public boolean isBouncerShowing() { return mBouncer.isShowing(); } - /** - * When bouncer is fully visible or {@link KeyguardBouncer#show(boolean)} was called but - * animation didn't finish yet. - */ + @Override public boolean bouncerIsOrWillBeShowing() { return mBouncer.isShowing() || mBouncer.inTransit(); } @@ -918,6 +916,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } @Override + public void setKeyguardGoingAwayState(boolean isKeyguardGoingAway) { + mNotificationShadeWindowController.setKeyguardGoingAway(isKeyguardGoingAway); + } + + @Override public void onCancelClicked() { // No-op } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 79cea91b8612..aecbb9097c7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -22,7 +22,6 @@ import static com.android.systemui.statusbar.phone.StatusBar.SPEW; import android.annotation.Nullable; import android.app.KeyguardManager; import android.content.Context; -import android.content.pm.PackageManager; import android.os.RemoteException; import android.os.ServiceManager; import android.service.notification.StatusBarNotification; @@ -355,8 +354,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } @Override - public void onBindRow(NotificationEntry entry, PackageManager pmUser, - StatusBarNotification sbn, ExpandableNotificationRow row) { + public void onBindRow(ExpandableNotificationRow row) { row.setAboveShelfChangedListener(mAboveShelfObserver); row.setSecureStateProvider(mKeyguardStateController::canDismissLockScreen); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index bf5900ff24bb..95b41a141244 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -71,7 +71,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC protected boolean mPluggedIn; protected boolean mCharging; private boolean mCharged; - private boolean mPowerSave; + protected boolean mPowerSave; private boolean mAodPowerSave; private boolean mTestmode = false; private boolean mHasReceivedBattery = false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java index 7d5498157136..45e47f1f763f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java @@ -21,6 +21,8 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; import android.database.DataSetObserver; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -294,6 +296,21 @@ public class KeyguardUserSwitcher { return convertView; } + private static Drawable getDrawable(Context context, + UserSwitcherController.UserRecord item) { + Drawable drawable = getIconDrawable(context, item); + int iconColorRes = item.isCurrent ? R.color.kg_user_switcher_selected_avatar_icon_color + : R.color.kg_user_switcher_avatar_icon_color; + drawable.setTint(context.getResources().getColor(iconColorRes, context.getTheme())); + + if (item.isCurrent) { + Drawable bg = context.getDrawable(R.drawable.bg_avatar_selected); + drawable = new LayerDrawable(new Drawable[]{bg, drawable}); + } + + return drawable; + } + @Override public void onClick(View v) { UserSwitcherController.UserRecord user = (UserSwitcherController.UserRecord) v.getTag(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 69eaaa4f54a9..bb0b5e00ff67 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -31,7 +31,6 @@ import android.content.IntentFilter; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.graphics.Bitmap; -import android.graphics.PorterDuff.Mode; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Handler; @@ -52,7 +51,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.UserIcons; import com.android.settingslib.RestrictedLockUtilsInternal; -import com.android.settingslib.Utils; import com.android.systemui.Dumpable; import com.android.systemui.GuestResumeSessionReceiver; import com.android.systemui.Prefs; @@ -684,18 +682,17 @@ public class UserSwitcherController implements Dumpable { } } - public Drawable getDrawable(Context context, UserRecord item) { + protected static Drawable getIconDrawable(Context context, UserRecord item) { + int iconRes; if (item.isAddUser) { - return context.getDrawable(R.drawable.ic_add_circle_qs); - } - Drawable icon = UserIcons.getDefaultUserIcon( - context.getResources(), item.resolveId(), /* light= */ false); - if (item.isGuest) { - icon.setColorFilter(Utils.getColorAttrDefaultColor(context, - android.R.attr.colorForeground), - Mode.SRC_IN); + iconRes = R.drawable.ic_add_circle; + } else if (item.isGuest) { + iconRes = R.drawable.ic_avatar_guest_user; + } else { + iconRes = R.drawable.ic_avatar_user; } - return icon; + + return context.getDrawable(iconRes); } public void refresh() { diff --git a/packages/SystemUI/src/com/android/systemui/util/RelativeTouchListener.kt b/packages/SystemUI/src/com/android/systemui/util/RelativeTouchListener.kt new file mode 100644 index 000000000000..d65b285adb0c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/RelativeTouchListener.kt @@ -0,0 +1,162 @@ +/* + * 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.util + +import android.graphics.PointF +import android.os.Handler +import android.view.MotionEvent +import android.view.VelocityTracker +import android.view.View +import android.view.ViewConfiguration +import kotlin.math.hypot + +/** + * Listener which receives [onDown], [onMove], and [onUp] events, with relevant information about + * the coordinates of the touch and the view relative to the initial ACTION_DOWN event and the + * view's initial position. + */ +abstract class RelativeTouchListener : View.OnTouchListener { + + /** + * Called when an ACTION_DOWN event is received for the given view. + * + * @return False if the object is not interested in MotionEvents at this time, or true if we + * should consume this event and subsequent events, and begin calling [onMove]. + */ + abstract fun onDown(v: View, ev: MotionEvent): Boolean + + /** + * Called when an ACTION_MOVE event is received for the given view. This signals that the view + * is being dragged. + * + * @param viewInitialX The view's translationX value when this touch gesture started. + * @param viewInitialY The view's translationY value when this touch gesture started. + * @param dx Horizontal distance covered since the initial ACTION_DOWN event, in pixels. + * @param dy Vertical distance covered since the initial ACTION_DOWN event, in pixels. + */ + abstract fun onMove( + v: View, + ev: MotionEvent, + viewInitialX: Float, + viewInitialY: Float, + dx: Float, + dy: Float + ) + + /** + * Called when an ACTION_UP event is received for the given view. This signals that a drag or + * fling gesture has completed. + * + * @param viewInitialX The view's translationX value when this touch gesture started. + * @param viewInitialY The view's translationY value when this touch gesture started. + * @param dx Horizontal distance covered, in pixels. + * @param dy Vertical distance covered, in pixels. + * @param velX The final horizontal velocity of the gesture, in pixels/second. + * @param velY The final vertical velocity of the gesture, in pixels/second. + */ + abstract fun onUp( + v: View, + ev: MotionEvent, + viewInitialX: Float, + viewInitialY: Float, + dx: Float, + dy: Float, + velX: Float, + velY: Float + ) + + /** The raw coordinates of the last ACTION_DOWN event. */ + private val touchDown = PointF() + + /** The coordinates of the view, at the time of the last ACTION_DOWN event. */ + private val viewPositionOnTouchDown = PointF() + + private val velocityTracker = VelocityTracker.obtain() + + private var touchSlop: Int = -1 + private var movedEnough = false + + private val handler = Handler() + private var performedLongClick = false + + @Suppress("UNCHECKED_CAST") + override fun onTouch(v: View, ev: MotionEvent): Boolean { + addMovement(ev) + + val dx = ev.rawX - touchDown.x + val dy = ev.rawY - touchDown.y + + when (ev.action) { + MotionEvent.ACTION_DOWN -> { + if (!onDown(v, ev)) { + return false + } + + // Grab the touch slop, it might have changed if the config changed since the + // last gesture. + touchSlop = ViewConfiguration.get(v.context).scaledTouchSlop + + touchDown.set(ev.rawX, ev.rawY) + viewPositionOnTouchDown.set(v.translationX, v.translationY) + + performedLongClick = false + handler.postDelayed({ + performedLongClick = v.performLongClick() + }, ViewConfiguration.getLongPressTimeout().toLong()) + } + + MotionEvent.ACTION_MOVE -> { + if (!movedEnough && hypot(dx, dy) > touchSlop && !performedLongClick) { + movedEnough = true + handler.removeCallbacksAndMessages(null) + } + + if (movedEnough) { + onMove(v, ev, viewPositionOnTouchDown.x, viewPositionOnTouchDown.y, dx, dy) + } + } + + MotionEvent.ACTION_UP -> { + if (movedEnough) { + velocityTracker.computeCurrentVelocity(1000 /* units */) + onUp(v, ev, viewPositionOnTouchDown.x, viewPositionOnTouchDown.y, dx, dy, + velocityTracker.xVelocity, velocityTracker.yVelocity) + } else if (!performedLongClick) { + v.performClick() + } else { + handler.removeCallbacksAndMessages(null) + } + + velocityTracker.clear() + movedEnough = false + } + } + + return true + } + + /** + * Adds a movement to the velocity tracker using raw screen coordinates. + */ + private fun addMovement(event: MotionEvent) { + val deltaX = event.rawX - event.x + val deltaY = event.rawY - event.y + event.offsetLocation(deltaX, deltaY) + velocityTracker.addMovement(event) + event.offsetLocation(-deltaX, -deltaY) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/util/RingerModeTracker.kt b/packages/SystemUI/src/com/android/systemui/util/RingerModeTracker.kt new file mode 100644 index 000000000000..047298e6ed81 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/RingerModeTracker.kt @@ -0,0 +1,25 @@ +/* + * 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.util + +import androidx.lifecycle.LiveData + +interface RingerModeTracker { + + val ringerMode: LiveData<Int> + val ringerModeInternal: LiveData<Int> +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/util/RingerModeTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/util/RingerModeTrackerImpl.kt new file mode 100644 index 000000000000..58684c386995 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/RingerModeTrackerImpl.kt @@ -0,0 +1,89 @@ +/* + * 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.util + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.media.AudioManager +import android.os.UserHandle +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.dagger.qualifiers.Background +import java.util.concurrent.Executor +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class RingerModeTrackerImpl @Inject constructor( + audioManager: AudioManager, + broadcastDispatcher: BroadcastDispatcher, + @Background executor: Executor +) : RingerModeTracker { + + override val ringerMode: LiveData<Int> = RingerModeLiveData( + broadcastDispatcher, + executor, + AudioManager.RINGER_MODE_CHANGED_ACTION, + audioManager::getRingerMode + ) + + override val ringerModeInternal: LiveData<Int> = RingerModeLiveData( + broadcastDispatcher, + executor, + AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, + audioManager::getRingerModeInternal + ) +} + +class RingerModeLiveData( + private val broadcastDispatcher: BroadcastDispatcher, + private val executor: Executor, + intent: String, + private val getter: () -> Int +) : MutableLiveData<Int>() { + + private val filter = IntentFilter(intent) + var initialSticky: Boolean = false + private set + + private val receiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + initialSticky = isInitialStickyBroadcast + postValue(intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1)) + } + } + + override fun getValue(): Int { + return super.getValue() ?: -1 + } + + override fun onActive() { + super.onActive() + broadcastDispatcher.registerReceiver(receiver, filter, executor, UserHandle.ALL) + executor.execute { + postValue(getter()) + } + } + + override fun onInactive() { + super.onInactive() + broadcastDispatcher.unregisterReceiver(receiver) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt index 812a1e4bc121..f27bdbfbeda0 100644 --- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt +++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt @@ -160,6 +160,18 @@ abstract class MagnetizedObject<T : Any>( lateinit var magnetListener: MagnetizedObject.MagnetListener /** + * Optional update listener to provide to the PhysicsAnimator that is used to spring the object + * into the target. + */ + var physicsAnimatorUpdateListener: PhysicsAnimator.UpdateListener<T>? = null + + /** + * Optional end listener to provide to the PhysicsAnimator that is used to spring the object + * into the target. + */ + var physicsAnimatorEndListener: PhysicsAnimator.EndListener<T>? = null + + /** * Sets whether forcefully flinging the object vertically towards a target causes it to be * attracted to the target and then released immediately, despite never being dragged within the * magnetic field. @@ -479,6 +491,14 @@ abstract class MagnetizedObject<T : Any>( .spring(yProperty, yProperty.getValue(underlyingObject) + yDiff, velY, springConfig) + if (physicsAnimatorUpdateListener != null) { + animator.addUpdateListener(physicsAnimatorUpdateListener!!) + } + + if (physicsAnimatorEndListener != null) { + animator.addEndListener(physicsAnimatorEndListener!!) + } + if (after != null) { animator.withEndActions(after) } @@ -560,13 +580,15 @@ abstract class MagnetizedObject<T : Any>( private val tempLoc = IntArray(2) fun updateLocationOnScreen() { - targetView.getLocationOnScreen(tempLoc) - - // Add half of the target size to get the center, and subtract translation since the - // target could be animating in while we're doing this calculation. - centerOnScreen.set( - tempLoc[0] + targetView.width / 2f - targetView.translationX, - tempLoc[1] + targetView.height / 2f - targetView.translationY) + targetView.post { + targetView.getLocationOnScreen(tempLoc) + + // Add half of the target size to get the center, and subtract translation since the + // target could be animating in while we're doing this calculation. + centerOnScreen.set( + tempLoc[0] + targetView.width / 2f - targetView.translationX, + tempLoc[1] + targetView.height / 2f - targetView.translationY) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index 73532632c875..f19c49cc123f 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -55,6 +55,8 @@ import android.util.Log; import android.util.Slog; import android.view.accessibility.AccessibilityManager; +import androidx.lifecycle.Observer; + import com.android.internal.annotations.GuardedBy; import com.android.settingslib.volume.MediaSessions; import com.android.systemui.Dumpable; @@ -64,6 +66,8 @@ import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.util.RingerModeLiveData; +import com.android.systemui.util.RingerModeTracker; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -122,6 +126,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private final NotificationManager mNoMan; private final SettingObserver mObserver; private final Receiver mReceiver = new Receiver(); + private final RingerModeObservers mRingerModeObservers; private final MediaSessions mMediaSessions; protected C mCallbacks = new C(); private final State mState = new State(); @@ -145,7 +150,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa @Inject public VolumeDialogControllerImpl(Context context, BroadcastDispatcher broadcastDispatcher, - Optional<Lazy<StatusBar>> statusBarOptionalLazy) { + Optional<Lazy<StatusBar>> statusBarOptionalLazy, RingerModeTracker ringerModeTracker) { mContext = context.getApplicationContext(); // TODO(b/150663459): remove this TV workaround once StatusBar is "unbound" on TVs if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) { @@ -164,6 +169,11 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa mAudio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); mObserver = new SettingObserver(mWorker); + mRingerModeObservers = new RingerModeObservers( + (RingerModeLiveData) ringerModeTracker.getRingerMode(), + (RingerModeLiveData) ringerModeTracker.getRingerModeInternal() + ); + mRingerModeObservers.init(); mBroadcastDispatcher = broadcastDispatcher; mObserver.init(); mReceiver.init(); @@ -246,6 +256,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa mMediaSessions.destroy(); mObserver.destroy(); mReceiver.destroy(); + mRingerModeObservers.destroy(); mWorkerThread.quitSafely(); } @@ -528,7 +539,8 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa ss.name = STREAMS.get(stream); checkRoutedToBluetoothW(stream); } - updateRingerModeExternalW(mAudio.getRingerMode()); + // We are not destroyed so this is listening and has updated information + updateRingerModeExternalW(mRingerModeObservers.mRingerMode.getValue()); updateZenModeW(); updateZenConfig(); updateEffectsSuppressorW(mNoMan.getEffectsSuppressor()); @@ -575,7 +587,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa Events.writeEvent(Events.EVENT_MUTE_CHANGED, stream, muted); } if (muted && isRinger(stream)) { - updateRingerModeInternalW(mAudio.getRingerModeInternal()); + updateRingerModeInternalW(mRingerModeObservers.mRingerModeInternal.getValue()); } return true; } @@ -964,6 +976,79 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa } } + private final class RingerModeObservers { + + private final RingerModeLiveData mRingerMode; + private final RingerModeLiveData mRingerModeInternal; + + private final Observer<Integer> mRingerModeObserver = new Observer<Integer>() { + @Override + public void onChanged(Integer value) { + mWorker.post(() -> { + final int rm = value; + if (mRingerMode.getInitialSticky()) { + mState.ringerModeExternal = rm; + } + if (D.BUG) { + Log.d(TAG, "onChange ringer_mode rm=" + + Util.ringerModeToString(rm)); + } + if (updateRingerModeExternalW(rm)) { + mCallbacks.onStateChanged(mState); + } + } + ); + } + }; + + private final Observer<Integer> mRingerModeInternalObserver = new Observer<Integer>() { + @Override + public void onChanged(Integer value) { + mWorker.post(() -> { + final int rm = value; + if (mRingerModeInternal.getInitialSticky()) { + mState.ringerModeInternal = rm; + } + if (D.BUG) { + Log.d(TAG, "onChange internal_ringer_mode rm=" + + Util.ringerModeToString(rm)); + } + if (updateRingerModeInternalW(rm)) { + mCallbacks.onStateChanged(mState); + } + } + ); + } + }; + + RingerModeObservers(RingerModeLiveData ringerMode, + RingerModeLiveData ringerModeInternal) { + mRingerMode = ringerMode; + mRingerModeInternal = ringerModeInternal; + } + + public void init() { + int initialValue = mRingerMode.getValue(); + if (initialValue != -1) { + // If it's not -1, set it to the initial value, if it's -1, it means that the + // tracker is not listening already and will obtain the sticky value. + mState.ringerModeExternal = initialValue; + } + mRingerMode.observeForever(mRingerModeObserver); + initialValue = mRingerModeInternal.getValue(); + if (initialValue != -1) { + // If it's not -1, set it to the initial value, if it's -1, it means that the + // tracker is not listening already and will obtain the sticky value. + mState.ringerModeInternal = initialValue; + } + mRingerModeInternal.observeForever(mRingerModeInternalObserver); + } + + public void destroy() { + mRingerMode.removeObserver(mRingerModeObserver); + mRingerModeInternal.removeObserver(mRingerModeInternalObserver); + } + } private final class SettingObserver extends ContentObserver { private final Uri ZEN_MODE_URI = @@ -1006,8 +1091,6 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa final IntentFilter filter = new IntentFilter(); filter.addAction(AudioManager.VOLUME_CHANGED_ACTION); filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION); - filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); - filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION); filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION); filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); @@ -1042,18 +1125,6 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa + stream + " devices=" + devices + " oldDevices=" + oldDevices); changed = checkRoutedToBluetoothW(stream); changed |= onVolumeChangedW(stream, 0); - } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { - final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1); - if (isInitialStickyBroadcast()) mState.ringerModeExternal = rm; - if (D.BUG) Log.d(TAG, "onReceive RINGER_MODE_CHANGED_ACTION rm=" - + Util.ringerModeToString(rm)); - changed = updateRingerModeExternalW(rm); - } else if (action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) { - final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1); - if (isInitialStickyBroadcast()) mState.ringerModeInternal = rm; - if (D.BUG) Log.d(TAG, "onReceive INTERNAL_RINGER_MODE_CHANGED_ACTION rm=" - + Util.ringerModeToString(rm)); - changed = updateRingerModeInternalW(rm); } else if (action.equals(AudioManager.STREAM_MUTE_CHANGED_ACTION)) { final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); final boolean muted = intent diff --git a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java index a94af24fc843..1c7a9b5e8681 100644 --- a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java +++ b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java @@ -175,6 +175,9 @@ public class WifiDebuggingActivity extends AlertActivity IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); registerReceiver(mWifiChangeReceiver, filter); + // Close quick shade + sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + } @Override diff --git a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java index 0266a84503a1..7a31fa54b1cd 100644 --- a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java +++ b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java @@ -96,6 +96,8 @@ public class WifiDebuggingSecondaryUserActivity extends AlertActivity IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); registerReceiver(mWifiChangeReceiver, filter); + // Close quick shade + sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java index bae5bb41aa5a..c22b718fa50f 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java +++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java @@ -272,13 +272,18 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged } mAnimation.cancel(); } - mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE; final float defaultY = mImeSourceControl.getSurfacePosition().y; final float x = mImeSourceControl.getSurfacePosition().x; final float hiddenY = defaultY + imeSource.getFrame().height(); final float shownY = defaultY; final float startY = show ? hiddenY : shownY; final float endY = show ? shownY : hiddenY; + if (mAnimationDirection == DIRECTION_NONE && mImeShowing && show) { + // IME is already showing, so set seek to end + seekValue = shownY; + seek = true; + } + mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE; mImeShowing = show; mAnimation = ValueAnimator.ofFloat(startY, endY); mAnimation.setDuration( diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java index 4652abfa0721..cfec1c07ff1d 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java +++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java @@ -27,6 +27,7 @@ import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; +import android.annotation.IntDef; import android.annotation.NonNull; import android.content.ContentResolver; import android.content.Context; @@ -46,16 +47,27 @@ import android.view.Surface; import com.android.internal.R; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Contains information about the layout-properties of a display. This refers to internal layout * like insets/cutout/rotation. In general, this can be thought of as the System-UI analog to * DisplayPolicy. */ public class DisplayLayout { + @IntDef(prefix = { "NAV_BAR_" }, value = { + NAV_BAR_LEFT, + NAV_BAR_RIGHT, + NAV_BAR_BOTTOM, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface NavBarPosition {} + // Navigation bar position values - private static final int NAV_BAR_LEFT = 1 << 0; - private static final int NAV_BAR_RIGHT = 1 << 1; - private static final int NAV_BAR_BOTTOM = 1 << 2; + public static final int NAV_BAR_LEFT = 1 << 0; + public static final int NAV_BAR_RIGHT = 1 << 1; + public static final int NAV_BAR_BOTTOM = 1 << 2; private int mUiMode; private int mWidth; @@ -214,6 +226,14 @@ public class DisplayLayout { } /** + * Gets navigation bar position for this layout + * @return Navigation bar position for this layout. + */ + public @NavBarPosition int getNavigationBarPosition(Resources res) { + return navigationBarPosition(res, mWidth, mHeight, mRotation); + } + + /** * Rotates bounds as if parentBounds and bounds are a group. The group is rotated by `delta` * 90-degree counter-clockwise increments. This assumes that parentBounds is at 0,0 and * remains at 0,0 after rotation. @@ -437,8 +457,8 @@ public class DisplayLayout { } /** Retrieve navigation bar position from resources based on rotation and size. */ - public static int navigationBarPosition(Resources res, int displayWidth, int displayHeight, - int rotation) { + public static @NavBarPosition int navigationBarPosition(Resources res, int displayWidth, + int displayHeight, int rotation) { boolean navBarCanMove = displayWidth != displayHeight && res.getBoolean( com.android.internal.R.bool.config_navBarCanMove); if (navBarCanMove && displayWidth > displayHeight) { diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java index 1140b9aa3abb..e5da603321cd 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java +++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java @@ -258,12 +258,13 @@ public class SystemWindows { Rect outVisibleInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl, InsetsState outInsetsState, - Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) { + InsetsSourceControl[] outActiveControls, Point outSurfaceSize, + SurfaceControl outBLASTSurfaceControl) { int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight, viewVisibility, flags, frameNumber, outFrame, outOverscanInsets, outContentInsets, outVisibleInsets, outStableInsets, cutout, mergedConfiguration, outSurfaceControl, outInsetsState, - outSurfaceSize, outBLASTSurfaceControl); + outActiveControls, outSurfaceSize, outBLASTSurfaceControl); if (res != 0) { return res; } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java index cf1299fc66e0..9be2d124026c 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java @@ -48,6 +48,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -99,6 +100,11 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase { mContext, mParent, mUpdateMonitor, mKeyguardCallback, mHandler); } + @After + public void tearDown() { + ViewUtils.detachView(mParent); + } + @Test public void testShow() throws Exception { doAnswer(invocation -> { @@ -115,6 +121,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase { @Test public void testShow_dismissedByCallback() throws Exception { + doAnswer(answerVoid(Runnable::run)).when(mHandler).post(any(Runnable.class)); doAnswer(invocation -> { IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1]; callback.onDismiss(); @@ -184,7 +191,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase { private void verifyViewDismissed(SurfaceView v) throws Exception { verify(mParent).removeView(v); - verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID); + verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true); assertThat(mContext.isBound(mComponentName)).isFalse(); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index de7664c769e6..97714c194c56 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -27,12 +27,14 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.Context; import android.graphics.Color; import android.graphics.Paint.Style; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.text.TextPaint; +import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; @@ -68,15 +70,37 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { @Mock TextClock mClockView; + View mMockKeyguardSliceView; @InjectMocks KeyguardClockSwitch mKeyguardClockSwitch; @Before public void setUp() { + mMockKeyguardSliceView = mock(KeyguardSliceView.class); + when(mMockKeyguardSliceView.getContext()).thenReturn(mContext); + when(mMockKeyguardSliceView.findViewById(R.id.keyguard_status_area)) + .thenReturn(mMockKeyguardSliceView); + InjectionInflationController inflationController = new InjectionInflationController( SystemUIFactory.getInstance().getRootComponent()); LayoutInflater layoutInflater = inflationController .injectable(LayoutInflater.from(getContext())); + layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() { + + @Override + public View onCreateView(View parent, String name, Context context, + AttributeSet attrs) { + return onCreateView(name, context, attrs); + } + + @Override + public View onCreateView(String name, Context context, AttributeSet attrs) { + if ("com.android.keyguard.KeyguardSliceView".equals(name)) { + return mMockKeyguardSliceView; + } + return null; + } + }); mKeyguardClockSwitch = (KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null); mClockContainer = mKeyguardClockSwitch.findViewById(R.id.clock_view); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt index 072bc446fd21..4bcf917fa95d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt @@ -16,8 +16,12 @@ package com.android.keyguard +import android.app.Notification import android.graphics.drawable.Icon import android.media.MediaMetadata +import android.media.session.MediaController +import android.media.session.MediaSession +import android.media.session.PlaybackState import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.View @@ -28,7 +32,9 @@ import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder +import com.android.systemui.media.MediaControllerFactory import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat @@ -38,6 +44,7 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.any import org.mockito.Mockito.mock import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever @@ -48,9 +55,12 @@ import org.mockito.Mockito.`when` as whenever public class KeyguardMediaPlayerTest : SysuiTestCase() { private lateinit var keyguardMediaPlayer: KeyguardMediaPlayer + @Mock private lateinit var mockMediaFactory: MediaControllerFactory + @Mock private lateinit var mockMediaController: MediaController + private lateinit var playbackState: PlaybackState private lateinit var fakeExecutor: FakeExecutor private lateinit var mediaMetadata: MediaMetadata.Builder - private lateinit var entry: NotificationEntryBuilder + private lateinit var entry: NotificationEntry @Mock private lateinit var mockView: View private lateinit var songView: TextView private lateinit var artistView: TextView @@ -70,8 +80,16 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() { @Before public fun setup() { + playbackState = PlaybackState.Builder().run { + build() + } + mockMediaController = mock(MediaController::class.java) + whenever(mockMediaController.getPlaybackState()).thenReturn(playbackState) + mockMediaFactory = mock(MediaControllerFactory::class.java) + whenever(mockMediaFactory.create(any())).thenReturn(mockMediaController) + fakeExecutor = FakeExecutor(FakeSystemClock()) - keyguardMediaPlayer = KeyguardMediaPlayer(context, fakeExecutor) + keyguardMediaPlayer = KeyguardMediaPlayer(context, mockMediaFactory, fakeExecutor) mockIcon = mock(Icon::class.java) mockView = mock(View::class.java) @@ -81,7 +99,9 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() { whenever<TextView>(mockView.findViewById(R.id.header_artist)).thenReturn(artistView) mediaMetadata = MediaMetadata.Builder() - entry = NotificationEntryBuilder() + entry = NotificationEntryBuilder().build() + entry.getSbn().getNotification().extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, + MediaSession.Token(1, null)) ArchTaskExecutor.getInstance().setDelegate(taskExecutor) @@ -109,7 +129,7 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() { @Test public fun testUpdateControls() { - keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build()) + keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build()) FakeExecutor.exhaustExecutors(fakeExecutor) verify(mockView).setVisibility(View.VISIBLE) } @@ -122,11 +142,22 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() { } @Test + public fun testUpdateControlsNullPlaybackState() { + // GIVEN that the playback state is null (ie. the media session was destroyed) + whenever(mockMediaController.getPlaybackState()).thenReturn(null) + // WHEN updated + keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build()) + FakeExecutor.exhaustExecutors(fakeExecutor) + // THEN the controls are cleared (ie. visibility is set to GONE) + verify(mockView).setVisibility(View.GONE) + } + + @Test public fun testSongName() { val song: String = "Song" mediaMetadata.putText(MediaMetadata.METADATA_KEY_TITLE, song) - keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build()) + keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build()) assertThat(fakeExecutor.runAllReady()).isEqualTo(1) assertThat(songView.getText()).isEqualTo(song) @@ -137,7 +168,7 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() { val artist: String = "Artist" mediaMetadata.putText(MediaMetadata.METADATA_KEY_ARTIST, artist) - keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build()) + keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build()) assertThat(fakeExecutor.runAllReady()).isEqualTo(1) assertThat(artistView.getText()).isEqualTo(artist) diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java index 7231b8a143d0..e6c2ddcf7e65 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java @@ -16,33 +16,88 @@ package com.android.keyguard; +import static org.mockito.Mockito.when; + import android.content.Context; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardDisplayManager.KeyguardPresentation; +import com.android.systemui.R; import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; import com.android.systemui.util.InjectionInflationController; +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; @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class KeyguardPresentationTest extends SysuiTestCase { - @Test - public void testInflation_doesntCrash() { + + @Mock + KeyguardClockSwitch mMockKeyguardClockSwitch; + @Mock + KeyguardSliceView mMockKeyguardSliceView; + @Mock + KeyguardStatusView mMockKeyguardStatusView; + + LayoutInflater mLayoutInflater; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); mDependency.injectMockDependency(KeyguardUpdateMonitor.class); + when(mMockKeyguardClockSwitch.getContext()).thenReturn(mContext); + when(mMockKeyguardSliceView.getContext()).thenReturn(mContext); + when(mMockKeyguardStatusView.getContext()).thenReturn(mContext); + when(mMockKeyguardStatusView.findViewById(R.id.clock)).thenReturn(mMockKeyguardStatusView); allowTestableLooperAsMainThread(); + InjectionInflationController inflationController = new InjectionInflationController( SystemUIFactory.getInstance().getRootComponent()); - Context context = getContext(); - KeyguardPresentation keyguardPresentation = new KeyguardPresentation(context, - context.getDisplayNoVerify(), inflationController); + mLayoutInflater = inflationController.injectable(LayoutInflater.from(mContext)); + mLayoutInflater.setPrivateFactory(new LayoutInflater.Factory2() { + + @Override + public View onCreateView(View parent, String name, Context context, + AttributeSet attrs) { + return onCreateView(name, context, attrs); + } + + @Override + public View onCreateView(String name, Context context, AttributeSet attrs) { + if ("com.android.keyguard.KeyguardStatusView".equals(name)) { + return mMockKeyguardStatusView; + } else if ("com.android.keyguard.KeyguardClockSwitch".equals(name)) { + return mMockKeyguardClockSwitch; + } else if ("com.android.keyguard.KeyguardSliceView".equals(name)) { + return mMockKeyguardStatusView; + } + return null; + } + }); + } + + @After + public void tearDown() { + disallowTestableLooperAsMainThread(); + } + + @Test + public void testInflation_doesntCrash() { + KeyguardPresentation keyguardPresentation = new KeyguardPresentation(mContext, + mContext.getDisplayNoVerify(), mLayoutInflater); keyguardPresentation.onCreate(null /*savedInstanceState */); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java index d47fceea9724..64590fd3a36b 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -25,6 +25,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,6 +37,7 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase { @UiThreadTest @Test public void showSecurityScreen_canInflateAllModes() { + mDependency.injectMockDependency(KeyguardStateController.class); KeyguardSecurityContainer keyguardSecurityContainer = new KeyguardSecurityContainer(getContext()); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 73f9d8ad6953..7403a11fecbf 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -29,6 +29,8 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -50,6 +52,7 @@ import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; +import android.media.AudioManager; import android.os.Bundle; import android.os.Handler; import android.os.IRemoteCallback; @@ -63,18 +66,24 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.Observer; + import com.android.internal.telephony.TelephonyIntents; import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.util.RingerModeTracker; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -125,6 +134,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { private BroadcastDispatcher mBroadcastDispatcher; @Mock private Executor mBackgroundExecutor; + @Mock + private RingerModeTracker mRingerModeTracker; + @Mock + private LiveData<Integer> mRingerModeLiveData; private TestableLooper mTestableLooper; private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor; @@ -156,6 +169,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { context.addMockSystemService(DevicePolicyManager.class, mDevicePolicyManager); context.addMockSystemService(SubscriptionManager.class, mSubscriptionManager); + when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData); + mTestableLooper = TestableLooper.get(this); allowTestableLooperAsMainThread(); mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(context); @@ -613,6 +628,29 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(mKeyguardUpdateMonitor.getSecondaryLockscreenRequirement(user)).isNull(); } + @Test + public void testRingerModeChange() { + ArgumentCaptor<Observer<Integer>> captor = ArgumentCaptor.forClass(Observer.class); + verify(mRingerModeLiveData).observeForever(captor.capture()); + Observer<Integer> observer = captor.getValue(); + + KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class); + + mKeyguardUpdateMonitor.registerCallback(callback); + + observer.onChanged(AudioManager.RINGER_MODE_NORMAL); + observer.onChanged(AudioManager.RINGER_MODE_SILENT); + observer.onChanged(AudioManager.RINGER_MODE_VIBRATE); + + mTestableLooper.processAllMessages(); + + InOrder orderVerify = inOrder(callback); + orderVerify.verify(callback).onRingerModeChanged(anyInt()); // Initial update on register + orderVerify.verify(callback).onRingerModeChanged(AudioManager.RINGER_MODE_NORMAL); + orderVerify.verify(callback).onRingerModeChanged(AudioManager.RINGER_MODE_SILENT); + orderVerify.verify(callback).onRingerModeChanged(AudioManager.RINGER_MODE_VIBRATE); + } + private void setBroadcastReceiverPendingResult(BroadcastReceiver receiver) { BroadcastReceiver.PendingResult pendingResult = new BroadcastReceiver.PendingResult(Activity.RESULT_OK, @@ -643,7 +681,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { protected TestableKeyguardUpdateMonitor(Context context) { super(context, TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper(), - mBroadcastDispatcher, mDumpManager, mBackgroundExecutor); + mBroadcastDispatcher, mDumpManager, + mRingerModeTracker, mBackgroundExecutor); mStrongAuthTracker = KeyguardUpdateMonitorTest.this.mStrongAuthTracker; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java index 69e933e95562..45f9437efc15 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java @@ -52,6 +52,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.util.time.FakeSystemClock; import junit.framework.Assert; @@ -69,6 +70,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { private ForegroundServiceController mFsc; private ForegroundServiceNotificationListener mListener; private NotificationEntryListener mEntryListener; + private final FakeSystemClock mClock = new FakeSystemClock(); @Mock private NotificationEntryManager mEntryManager; @Mock private AppOpsController mAppOpsController; @Mock private Handler mMainHandler; @@ -80,9 +82,10 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { allowTestableLooperAsMainThread(); MockitoAnnotations.initMocks(this); - mFsc = new ForegroundServiceController(mEntryManager, mAppOpsController, mMainHandler); + mFsc = new ForegroundServiceController( + mEntryManager, mAppOpsController, mMainHandler); mListener = new ForegroundServiceNotificationListener( - mContext, mFsc, mEntryManager, mNotifPipeline); + mContext, mFsc, mEntryManager, mNotifPipeline, mClock); ArgumentCaptor<NotificationEntryListener> entryListenerCaptor = ArgumentCaptor.forClass(NotificationEntryListener.class); verify(mEntryManager).addNotificationEntryListener( diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java index 46a473bd6543..bca8deeafd34 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java @@ -17,7 +17,6 @@ package com.android.systemui; import static com.android.systemui.ForegroundServiceLifetimeExtender.MIN_FGS_TIME_MS; -import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -29,6 +28,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -37,12 +37,15 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest public class ForegroundServiceNotificationListenerTest extends SysuiTestCase { - private ForegroundServiceLifetimeExtender mExtender = new ForegroundServiceLifetimeExtender(); + private ForegroundServiceLifetimeExtender mExtender; private NotificationEntry mEntry; private Notification mNotif; + private final FakeSystemClock mClock = new FakeSystemClock(); @Before public void setup() { + mExtender = new ForegroundServiceLifetimeExtender(mClock); + mNotif = new Notification.Builder(mContext, "") .setSmallIcon(R.drawable.ic_person) .setContentTitle("Title") @@ -50,6 +53,7 @@ public class ForegroundServiceNotificationListenerTest extends SysuiTestCase { .build(); mEntry = new NotificationEntryBuilder() + .setCreationTime(mClock.uptimeMillis()) .setNotification(mNotif) .build(); } @@ -62,27 +66,26 @@ public class ForegroundServiceNotificationListenerTest extends SysuiTestCase { // Extend the lifetime of a FGS notification iff it has not been visible // for the minimum time mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE; - modifySbn(mEntry) - .setPostTime(System.currentTimeMillis()) - .build(); + + // No time has elapsed, keep showing assertTrue(mExtender.shouldExtendLifetime(mEntry)); } @Test public void testShouldExtendLifetime_shouldNot_foreground() { mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE; - modifySbn(mEntry) - .setPostTime(System.currentTimeMillis() - MIN_FGS_TIME_MS - 1) - .build(); + + // Entry was created at mClock.uptimeMillis(), advance it MIN_FGS_TIME_MS + 1 + mClock.advanceTime(MIN_FGS_TIME_MS + 1); assertFalse(mExtender.shouldExtendLifetime(mEntry)); } @Test public void testShouldExtendLifetime_shouldNot_notForeground() { mNotif.flags = 0; - modifySbn(mEntry) - .setPostTime(System.currentTimeMillis() - MIN_FGS_TIME_MS - 1) - .build(); + + // Entry was created at mClock.uptimeMillis(), advance it MIN_FGS_TIME_MS + 1 + mClock.advanceTime(MIN_FGS_TIME_MS + 1); assertFalse(mExtender.shouldExtendLifetime(mEntry)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java index 475023e2506d..5227aaf01249 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java @@ -160,7 +160,7 @@ public class ImageWallpaperTest extends SysuiTestCase { LOW_BMP_HEIGHT /* bmpHeight */, LOW_BMP_WIDTH /* surfaceWidth */, LOW_BMP_HEIGHT /* surfaceHeight */, - true /* assertion */); + false /* assertion */); } @Test @@ -172,7 +172,7 @@ public class ImageWallpaperTest extends SysuiTestCase { INVALID_BMP_HEIGHT /* bmpHeight */, ImageWallpaper.GLEngine.MIN_SURFACE_WIDTH /* surfaceWidth */, ImageWallpaper.GLEngine.MIN_SURFACE_HEIGHT /* surfaceHeight */, - true /* assertion */); + false /* assertion */); } private void verifySurfaceSizeAndAssertTransition(int bmpWidth, int bmpHeight, diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index 32604f8609fa..b2c35867e789 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -38,6 +38,8 @@ import com.android.systemui.broadcast.FakeBroadcastDispatcher; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.statusbar.SmartReplyController; +import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; import org.junit.After; import org.junit.Before; @@ -97,6 +99,12 @@ public abstract class SysuiTestCase { // A lot of tests get the LocalBluetoothManager, often via several layers of indirection. // None of them actually need it. mDependency.injectMockDependency(LocalBluetoothManager.class); + + // Notifications tests are injecting one of these, causing many classes (including + // KeyguardUpdateMonitor to be created (injected). + // TODO(b/1531701009) Clean up NotificationContentView creation to prevent this + mDependency.injectMockDependency(SmartReplyController.class); + mDependency.injectMockDependency(NotificationBlockingHelperManager.class); } @After diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 037f04ec1d7c..2f5ef00056fb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -42,6 +42,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.IActivityManager; +import android.app.INotificationManager; import android.app.Notification; import android.app.PendingIntent; import android.content.res.Resources; @@ -273,7 +274,8 @@ public class BubbleControllerTest extends SysuiTestCase { mFeatureFlagsOldPipeline, mDumpManager, mFloatingContentCoordinator, - mSysUiState); + mSysUiState, + mock(INotificationManager.class)); mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener); mBubbleController.setExpandListener(mBubbleExpandListener); @@ -374,7 +376,7 @@ public class BubbleControllerTest extends SysuiTestCase { assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey())); assertTrue(mBubbleController.hasBubbles()); - mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE); + mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE); assertFalse(mNotificationShadeWindowController.getBubblesShowing()); verify(mNotificationEntryManager, times(3)).updateNotifications(any()); assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey())); @@ -399,7 +401,7 @@ public class BubbleControllerTest extends SysuiTestCase { // Expand the stack BubbleStackView stackView = mBubbleController.getStackView(); - mBubbleController.expandStack(); + mBubbleData.setExpanded(true); assertTrue(mBubbleController.isStackExpanded()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey()); assertTrue(mNotificationShadeWindowController.getBubbleExpanded()); @@ -436,7 +438,7 @@ public class BubbleControllerTest extends SysuiTestCase { // Expand BubbleStackView stackView = mBubbleController.getStackView(); - mBubbleController.expandStack(); + mBubbleData.setExpanded(true); assertTrue(mBubbleController.isStackExpanded()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey()); @@ -448,7 +450,7 @@ public class BubbleControllerTest extends SysuiTestCase { mRow2.getEntry())); // Switch which bubble is expanded - mBubbleController.selectBubble(mRow.getEntry().getKey()); + mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey())); mBubbleData.setExpanded(true); assertEquals(mRow.getEntry(), mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry()); @@ -482,7 +484,7 @@ public class BubbleControllerTest extends SysuiTestCase { assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot()); // Expand - mBubbleController.expandStack(); + mBubbleData.setExpanded(true); assertTrue(mBubbleController.isStackExpanded()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey()); @@ -510,7 +512,7 @@ public class BubbleControllerTest extends SysuiTestCase { assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot()); // Expand - mBubbleController.expandStack(); + mBubbleData.setExpanded(true); assertTrue(mBubbleController.isStackExpanded()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey()); @@ -544,7 +546,7 @@ public class BubbleControllerTest extends SysuiTestCase { // Expand BubbleStackView stackView = mBubbleController.getStackView(); - mBubbleController.expandStack(); + mBubbleData.setExpanded(true); assertTrue(mSysUiStateBubblesExpanded); @@ -726,7 +728,7 @@ public class BubbleControllerTest extends SysuiTestCase { public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry()); mBubbleController.updateBubble(mRow2.getEntry()); - mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE); + mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE); verify(mDeleteIntent, times(2)).send(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java index 545de210d5b5..9da160c3820c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -38,6 +38,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.IActivityManager; +import android.app.INotificationManager; import android.app.Notification; import android.app.PendingIntent; import android.content.res.Resources; @@ -250,7 +251,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { mFeatureFlagsNewPipeline, mDumpManager, mFloatingContentCoordinator, - mSysUiState); + mSysUiState, + mock(INotificationManager.class)); mBubbleController.addNotifCallback(mNotifCallback); mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener); mBubbleController.setExpandListener(mBubbleExpandListener); @@ -321,7 +323,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey())); assertTrue(mBubbleController.hasBubbles()); - mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE); + mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE); assertFalse(mNotificationShadeWindowController.getBubblesShowing()); verify(mNotifCallback, times(3)).invalidateNotifications(anyString()); assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey())); @@ -344,7 +346,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { // Expand the stack BubbleStackView stackView = mBubbleController.getStackView(); - mBubbleController.expandStack(); + mBubbleData.setExpanded(true); assertTrue(mBubbleController.isStackExpanded()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey()); assertTrue(mNotificationShadeWindowController.getBubbleExpanded()); @@ -376,7 +378,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { // Expand BubbleStackView stackView = mBubbleController.getStackView(); - mBubbleController.expandStack(); + mBubbleData.setExpanded(true); assertTrue(mBubbleController.isStackExpanded()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey()); @@ -385,7 +387,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(mRow2.getEntry())); // Switch which bubble is expanded - mBubbleController.selectBubble(mRow.getEntry().getKey()); + mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey())); mBubbleData.setExpanded(true); assertEquals(mRow.getEntry(), mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry()); @@ -416,7 +418,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot()); // Expand - mBubbleController.expandStack(); + mBubbleData.setExpanded(true); assertTrue(mBubbleController.isStackExpanded()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey()); @@ -442,7 +444,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { assertTrue(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()).showDot()); // Expand - mBubbleController.expandStack(); + mBubbleData.setExpanded(true); assertTrue(mBubbleController.isStackExpanded()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey()); @@ -474,7 +476,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { // Expand BubbleStackView stackView = mBubbleController.getStackView(); - mBubbleController.expandStack(); + mBubbleData.setExpanded(true); assertTrue(mBubbleController.isStackExpanded()); verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey()); @@ -628,7 +630,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { public void testDeleteIntent_dismissStack() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry()); mBubbleController.updateBubble(mRow2.getEntry()); - mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE); + mBubbleData.dismissAll(BubbleController.DISMISS_USER_GESTURE); verify(mDeleteIntent, times(2)).send(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java index f4861028e81a..7815ae78823a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java @@ -16,6 +16,7 @@ package com.android.systemui.bubbles; +import android.app.INotificationManager; import android.content.Context; import com.android.systemui.dump.DumpManager; @@ -54,12 +55,14 @@ public class TestableBubbleController extends BubbleController { FeatureFlags featureFlags, DumpManager dumpManager, FloatingContentCoordinator floatingContentCoordinator, - SysUiState sysUiState) { + SysUiState sysUiState, + INotificationManager notificationManager) { super(context, notificationShadeWindowController, statusBarStateController, shadeController, data, Runnable::run, configurationController, interruptionStateProvider, zenModeController, lockscreenUserManager, groupManager, entryManager, - notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState); + notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState, + notificationManager); setInflateSynchronously(true); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt index 88316f2d4323..bb003ee59978 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt @@ -125,7 +125,7 @@ class ControlsBindingControllerImplTest : SysuiTestCase() { loadSubscriberCaptor.value.onSubscribe(Binder(), subscription) canceller.run() - verify(subscription).cancel() + verify(providers[0]).cancelSubscription(subscription) } @Test @@ -145,7 +145,7 @@ class ControlsBindingControllerImplTest : SysuiTestCase() { loadSubscriberCaptor.value.onComplete(b) canceller.run() - verify(subscription, never()).cancel() + verify(providers[0], never()).cancelSubscription(subscription) } @Test @@ -203,7 +203,7 @@ class ControlsBindingControllerImplTest : SysuiTestCase() { loadSubscriberCaptor.value.onError(b, "") canceller.run() - verify(subscription, never()).cancel() + verify(providers[0], never()).cancelSubscription(subscription) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt index 8630570c4e70..f6ee46b0303a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt @@ -87,9 +87,6 @@ class ControlsControllerImplTest : SysuiTestCase() { private lateinit var structureInfoCaptor: ArgumentCaptor<StructureInfo> @Captor - private lateinit var booleanConsumer: ArgumentCaptor<Consumer<Boolean>> - - @Captor private lateinit var controlLoadCallbackCaptor: ArgumentCaptor<ControlsBindingController.LoadCallback> @Captor @@ -936,4 +933,33 @@ class ControlsControllerImplTest : SysuiTestCase() { verifyNoMoreInteractions(persistenceWrapper) verifyNoMoreInteractions(auxiliaryPersistenceWrapper) } + + @Test + fun testGetFavoritesForStructure() { + controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO) + controller.replaceFavoritesForStructure( + TEST_STRUCTURE_INFO_2.copy(componentName = TEST_COMPONENT)) + delayableExecutor.runAllReady() + + assertEquals(TEST_STRUCTURE_INFO.controls, + controller.getFavoritesForStructure(TEST_COMPONENT, TEST_STRUCTURE)) + assertEquals(TEST_STRUCTURE_INFO_2.controls, + controller.getFavoritesForStructure(TEST_COMPONENT, TEST_STRUCTURE_2)) + } + + @Test + fun testGetFavoritesForStructure_wrongStructure() { + controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO) + delayableExecutor.runAllReady() + + assertTrue(controller.getFavoritesForStructure(TEST_COMPONENT, TEST_STRUCTURE_2).isEmpty()) + } + + @Test + fun testGetFavoritesForStructure_wrongComponent() { + controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO) + delayableExecutor.runAllReady() + + assertTrue(controller.getFavoritesForStructure(TEST_COMPONENT_2, TEST_STRUCTURE).isEmpty()) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt index 5e0d28f6f795..236384b09514 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt @@ -31,6 +31,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest @@ -43,6 +45,8 @@ class AllModelTest : SysuiTestCase() { @Mock lateinit var pendingIntent: PendingIntent + @Mock + lateinit var controlsModelCallback: ControlsModel.ControlsModelCallback val idPrefix = "controlId" val favoritesIndices = listOf(7, 3, 1, 9) @@ -84,7 +88,7 @@ class AllModelTest : SysuiTestCase() { it in favoritesIndices ) } - model = AllModel(controls, favoritesList, EMPTY_STRING) + model = AllModel(controls, favoritesList, EMPTY_STRING, controlsModelCallback) } @Test @@ -93,28 +97,28 @@ class AllModelTest : SysuiTestCase() { // Zones are sorted by order of appearance, with empty at the end with special header. val expected = listOf( ZoneNameWrapper("1"), - ControlWrapper(controls[0]), - ControlWrapper(controls[3]), - ControlWrapper(controls[6]), - ControlWrapper(controls[9]), + ControlStatusWrapper(controls[0]), + ControlStatusWrapper(controls[3]), + ControlStatusWrapper(controls[6]), + ControlStatusWrapper(controls[9]), ZoneNameWrapper("2"), - ControlWrapper(controls[1]), - ControlWrapper(controls[4]), - ControlWrapper(controls[7]), + ControlStatusWrapper(controls[1]), + ControlStatusWrapper(controls[4]), + ControlStatusWrapper(controls[7]), ZoneNameWrapper("0"), - ControlWrapper(controls[2]), - ControlWrapper(controls[5]), - ControlWrapper(controls[8]), + ControlStatusWrapper(controls[2]), + ControlStatusWrapper(controls[5]), + ControlStatusWrapper(controls[8]), ZoneNameWrapper(EMPTY_STRING), - ControlWrapper(controls[10]), - ControlWrapper(controls[11]) + ControlStatusWrapper(controls[10]), + ControlStatusWrapper(controls[11]) ) expected.zip(model.elements).forEachIndexed { index, it -> assertEquals("Error in item at index $index", it.first, it.second) } } - private fun sameControl(controlInfo: ControlInfo.Builder, control: Control): Boolean { + private fun sameControl(controlInfo: ControlInfo, control: Control): Boolean { return controlInfo.controlId == control.controlId && controlInfo.controlTitle == control.title && controlInfo.controlSubtitle == control.subtitle && @@ -124,10 +128,11 @@ class AllModelTest : SysuiTestCase() { @Test fun testAllEmpty_noHeader() { val selected_controls = listOf(controls[10], controls[11]) - val new_model = AllModel(selected_controls, emptyList(), EMPTY_STRING) + val new_model = AllModel(selected_controls, emptyList(), EMPTY_STRING, + controlsModelCallback) val expected = listOf( - ControlWrapper(controls[10]), - ControlWrapper(controls[11]) + ControlStatusWrapper(controls[10]), + ControlStatusWrapper(controls[11]) ) expected.zip(new_model.elements).forEachIndexed { index, it -> @@ -154,6 +159,8 @@ class AllModelTest : SysuiTestCase() { model.favorites.zip(expectedFavorites).forEach { assertTrue(sameControl(it.first, it.second)) } + + verify(controlsModelCallback).onFirstChange() } @Test @@ -163,10 +170,12 @@ class AllModelTest : SysuiTestCase() { model.changeFavoriteStatus(id, true) assertTrue( (model.elements.first { - it is ControlWrapper && it.controlStatus.control.controlId == id - } as ControlWrapper) + it is ControlStatusWrapper && it.controlStatus.control.controlId == id + } as ControlStatusWrapper) .controlStatus.favorite ) + + verify(controlsModelCallback).onFirstChange() } @Test @@ -180,6 +189,8 @@ class AllModelTest : SysuiTestCase() { model.favorites.zip(expectedFavorites).forEach { assertTrue(sameControl(it.first, it.second)) } + + verify(controlsModelCallback, never()).onFirstChange() } @Test @@ -194,6 +205,8 @@ class AllModelTest : SysuiTestCase() { model.favorites.zip(expectedFavorites).forEach { assertTrue(sameControl(it.first, it.second)) } + + verify(controlsModelCallback).onFirstChange() } @Test @@ -203,10 +216,12 @@ class AllModelTest : SysuiTestCase() { model.changeFavoriteStatus(id, false) assertFalse( (model.elements.first { - it is ControlWrapper && it.controlStatus.control.controlId == id - } as ControlWrapper) + it is ControlStatusWrapper && it.controlStatus.control.controlId == id + } as ControlStatusWrapper) .controlStatus.favorite ) + + verify(controlsModelCallback).onFirstChange() } @Test @@ -219,5 +234,7 @@ class AllModelTest : SysuiTestCase() { model.favorites.zip(expectedFavorites).forEach { assertTrue(sameControl(it.first, it.second)) } + + verify(controlsModelCallback, never()).onFirstChange() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt deleted file mode 100644 index c330b38fed42..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.controls.management - -import android.app.PendingIntent -import android.content.ComponentName -import android.service.controls.Control -import android.testing.AndroidTestingRunner -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.controls.ControlStatus -import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Assert.fail -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.Parameterized -import org.mockito.Mock -import org.mockito.Mockito.verify -import org.mockito.Mockito.verifyNoMoreInteractions -import org.mockito.MockitoAnnotations - -open class FavoriteModelTest : SysuiTestCase() { - - @Mock - lateinit var pendingIntent: PendingIntent - @Mock - lateinit var allAdapter: ControlAdapter - @Mock - lateinit var favoritesAdapter: ControlAdapter - - val idPrefix = "controlId" - val favoritesIndices = listOf(7, 3, 1, 9) - val favoritesList = favoritesIndices.map { "controlId$it" } - lateinit var controls: List<ControlStatus> - - lateinit var model: FavoriteModel - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - - // controlId0 --> zone = 0 - // controlId1 --> zone = 1, favorite - // controlId2 --> zone = 2 - // controlId3 --> zone = 0, favorite - // controlId4 --> zone = 1 - // controlId5 --> zone = 2 - // controlId6 --> zone = 0 - // controlId7 --> zone = 1, favorite - // controlId8 --> zone = 2 - // controlId9 --> zone = 0, favorite - controls = (0..9).map { - ControlStatus( - Control.StatelessBuilder("$idPrefix$it", pendingIntent) - .setZone((it % 3).toString()) - .build(), - ComponentName("", ""), - it in favoritesIndices - ) - } - - model = FavoriteModel(controls, favoritesList, favoritesAdapter, allAdapter) - } -} - -@SmallTest -@RunWith(AndroidTestingRunner::class) -class FavoriteModelNonParametrizedTests : FavoriteModelTest() { - @Test - fun testAll() { - // Zones are sorted alphabetically - val expected = listOf( - ZoneNameWrapper("0"), - ControlWrapper(controls[0]), - ControlWrapper(controls[3]), - ControlWrapper(controls[6]), - ControlWrapper(controls[9]), - ZoneNameWrapper("1"), - ControlWrapper(controls[1]), - ControlWrapper(controls[4]), - ControlWrapper(controls[7]), - ZoneNameWrapper("2"), - ControlWrapper(controls[2]), - ControlWrapper(controls[5]), - ControlWrapper(controls[8]) - ) - assertEquals(expected, model.all) - } - - @Test - fun testFavoritesInOrder() { - val expected = favoritesIndices.map { ControlWrapper(controls[it]) } - assertEquals(expected, model.favorites) - } - - @Test - fun testChangeFavoriteStatus_addFavorite() { - val controlToAdd = 6 - model.changeFavoriteStatus("$idPrefix$controlToAdd", true) - - val pair = model.all.findControl(controlToAdd) - pair?.let { - assertTrue(it.second.favorite) - assertEquals(it.second, model.favorites.last().controlStatus) - verify(favoritesAdapter).notifyItemInserted(model.favorites.size - 1) - verify(allAdapter).notifyItemChanged(it.first) - verifyNoMoreInteractions(favoritesAdapter, allAdapter) - } ?: run { - fail("control not found") - } - } - - @Test - fun testChangeFavoriteStatus_removeFavorite() { - val controlToRemove = 3 - model.changeFavoriteStatus("$idPrefix$controlToRemove", false) - - val pair = model.all.findControl(controlToRemove) - pair?.let { - assertFalse(it.second.favorite) - assertTrue(model.favorites.none { - it.controlStatus.control.controlId == "$idPrefix$controlToRemove" - }) - verify(favoritesAdapter).notifyItemRemoved(favoritesIndices.indexOf(controlToRemove)) - verify(allAdapter).notifyItemChanged(it.first) - verifyNoMoreInteractions(favoritesAdapter, allAdapter) - } ?: run { - fail("control not found") - } - } - - @Test - fun testChangeFavoriteStatus_sameStatus() { - model.changeFavoriteStatus("${idPrefix}7", true) - model.changeFavoriteStatus("${idPrefix}6", false) - - val expected = favoritesIndices.map { ControlWrapper(controls[it]) } - assertEquals(expected, model.favorites) - - verifyNoMoreInteractions(favoritesAdapter, allAdapter) - } - - private fun List<ElementWrapper>.findControl(controlIndex: Int): Pair<Int, ControlStatus>? { - val index = indexOfFirst { - it is ControlWrapper && - it.controlStatus.control.controlId == "$idPrefix$controlIndex" - } - return if (index == -1) null else index to (get(index) as ControlWrapper).controlStatus - } -} - -@SmallTest -@RunWith(Parameterized::class) -class FavoriteModelParameterizedTest(val from: Int, val to: Int) : FavoriteModelTest() { - - companion object { - @JvmStatic - @Parameterized.Parameters(name = "{0} -> {1}") - fun data(): Collection<Array<Int>> { - return (0..3).flatMap { from -> - (0..3).map { to -> - arrayOf(from, to) - } - }.filterNot { it[0] == it[1] } - } - } - - @Test - fun testMoveItem() { - val originalFavorites = model.favorites.toList() - val originalFavoritesIds = - model.favorites.map { it.controlStatus.control.controlId }.toSet() - model.onMoveItem(from, to) - assertEquals(originalFavorites[from], model.favorites[to]) - // Check that we still have the same favorites - assertEquals(originalFavoritesIds, - model.favorites.map { it.controlStatus.control.controlId }.toSet()) - - verify(favoritesAdapter).notifyItemMoved(from, to) - - verifyNoMoreInteractions(allAdapter, favoritesAdapter) - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt new file mode 100644 index 000000000000..ce33a8d49fac --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt @@ -0,0 +1,291 @@ +/* + * 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.controls.management + +import android.content.ComponentName +import android.testing.AndroidTestingRunner +import androidx.recyclerview.widget.RecyclerView +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.controls.ControlInterface +import com.android.systemui.controls.controller.ControlInfo +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Mock +import org.mockito.Mockito.inOrder +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class FavoritesModelTest : SysuiTestCase() { + + companion object { + private val TEST_COMPONENT = ComponentName.unflattenFromString("test_pkg/.test_cls")!! + private val ID_PREFIX = "control" + private val INITIAL_FAVORITES = (0..5).map { + ControlInfo("$ID_PREFIX$it", "title$it", "subtitle$it", it) + } + } + + @Mock + private lateinit var callback: FavoritesModel.FavoritesModelCallback + @Mock + private lateinit var adapter: RecyclerView.Adapter<*> + private lateinit var model: FavoritesModel + private lateinit var dividerWrapper: DividerWrapper + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + model = FavoritesModel(TEST_COMPONENT, INITIAL_FAVORITES, callback) + model.attachAdapter(adapter) + dividerWrapper = model.elements.first { it is DividerWrapper } as DividerWrapper + } + + @After + fun testListConsistency() { + assertEquals(INITIAL_FAVORITES.size + 1, model.elements.toSet().size) + val dividerIndex = getDividerPosition() + model.elements.forEachIndexed { index, element -> + if (index == dividerIndex) { + assertEquals(dividerWrapper, element) + } else { + element as ControlInterface + assertEquals(index < dividerIndex, element.favorite) + } + } + assertEquals(model.favorites, model.elements.take(dividerIndex).map { + (it as ControlInfoWrapper).controlInfo + }) + } + + @Test + fun testInitialElements() { + val expected = INITIAL_FAVORITES.map { + ControlInfoWrapper(TEST_COMPONENT, it, true) + } + DividerWrapper() + assertEquals(expected, model.elements) + } + + @Test + fun testFavorites() { + assertEquals(INITIAL_FAVORITES, model.favorites) + } + + @Test + fun testRemoveFavorite_notInFavorites() { + val removed = 4 + val id = "$ID_PREFIX$removed" + + model.changeFavoriteStatus(id, false) + + assertTrue(model.favorites.none { it.controlId == id }) + + verify(callback).onFirstChange() + } + + @Test + fun testRemoveFavorite_endOfElements() { + val removed = 4 + val id = "$ID_PREFIX$removed" + model.changeFavoriteStatus(id, false) + + assertEquals(ControlInfoWrapper( + TEST_COMPONENT, INITIAL_FAVORITES[4], false), model.elements.last()) + verify(callback).onFirstChange() + } + + @Test + fun testRemoveFavorite_adapterNotified() { + val removed = 4 + val id = "$ID_PREFIX$removed" + model.changeFavoriteStatus(id, false) + + val lastPos = model.elements.size - 1 + verify(adapter).notifyItemChanged(eq(lastPos), any(Any::class.java)) + verify(adapter).notifyItemMoved(removed, lastPos) + + verify(callback).onFirstChange() + } + + @Test + fun testRemoveFavorite_dividerMovedBack() { + val oldDividerPosition = getDividerPosition() + val removed = 4 + val id = "$ID_PREFIX$removed" + model.changeFavoriteStatus(id, false) + + assertEquals(oldDividerPosition - 1, getDividerPosition()) + + verify(callback).onFirstChange() + } + + @Test + fun testRemoveFavorite_ShowDivider() { + val oldDividerPosition = getDividerPosition() + val removed = 4 + val id = "$ID_PREFIX$removed" + model.changeFavoriteStatus(id, false) + + assertTrue(dividerWrapper.showDivider) + verify(adapter).notifyItemChanged(oldDividerPosition) + + verify(callback).onFirstChange() + } + + @Test + fun testDoubleRemove_onlyOnce() { + val removed = 4 + val id = "$ID_PREFIX$removed" + model.changeFavoriteStatus(id, false) + model.changeFavoriteStatus(id, false) + + verify(adapter /* only once */).notifyItemChanged(anyInt(), any(Any::class.java)) + verify(adapter /* only once */).notifyItemMoved(anyInt(), anyInt()) + verify(adapter /* only once (divider) */).notifyItemChanged(anyInt()) + + verify(callback).onFirstChange() + } + + @Test + fun testRemoveTwo_InSameOrder() { + val removedFirst = 3 + val removedSecond = 0 + model.changeFavoriteStatus("$ID_PREFIX$removedFirst", false) + model.changeFavoriteStatus("$ID_PREFIX$removedSecond", false) + + assertEquals(listOf( + ControlInfoWrapper(TEST_COMPONENT, INITIAL_FAVORITES[removedFirst], false), + ControlInfoWrapper(TEST_COMPONENT, INITIAL_FAVORITES[removedSecond], false) + ), model.elements.takeLast(2)) + + verify(callback).onFirstChange() + } + + @Test + fun testRemoveAll_showNone() { + INITIAL_FAVORITES.forEach { + model.changeFavoriteStatus(it.controlId, false) + } + assertEquals(dividerWrapper, model.elements.first()) + assertTrue(dividerWrapper.showNone) + verify(adapter, times(2)).notifyItemChanged(anyInt()) // divider + verify(callback).onNoneChanged(true) + + verify(callback).onFirstChange() + } + + @Test + fun testAddFavorite_movedToEnd() { + val added = 2 + val id = "$ID_PREFIX$added" + model.changeFavoriteStatus(id, false) + model.changeFavoriteStatus(id, true) + + assertEquals(id, model.favorites.last().controlId) + + verify(callback).onFirstChange() + } + + @Test + fun testAddFavorite_onlyOnce() { + val added = 2 + val id = "$ID_PREFIX$added" + model.changeFavoriteStatus(id, false) + model.changeFavoriteStatus(id, true) + model.changeFavoriteStatus(id, true) + + // Once for remove and once for add + verify(adapter, times(2)).notifyItemChanged(anyInt(), any(Any::class.java)) + verify(adapter, times(2)).notifyItemMoved(anyInt(), anyInt()) + + verify(callback).onFirstChange() + } + + @Test + fun testAddFavorite_notRemoved() { + val added = 2 + val id = "$ID_PREFIX$added" + model.changeFavoriteStatus(id, true) + + verifyNoMoreInteractions(adapter) + + verify(callback, never()).onFirstChange() + } + + @Test + fun testAddOnlyRemovedFavorite_dividerStopsShowing() { + val added = 2 + val id = "$ID_PREFIX$added" + model.changeFavoriteStatus(id, false) + model.changeFavoriteStatus(id, true) + + assertFalse(dividerWrapper.showDivider) + val inOrder = inOrder(adapter) + inOrder.verify(adapter).notifyItemChanged(model.elements.size - 1) + inOrder.verify(adapter).notifyItemChanged(model.elements.size - 2) + + verify(callback).onFirstChange() + } + + @Test + fun testAddFirstFavorite_dividerNotShowsNone() { + INITIAL_FAVORITES.forEach { + model.changeFavoriteStatus(it.controlId, false) + } + + verify(callback).onNoneChanged(true) + + model.changeFavoriteStatus("${ID_PREFIX}3", true) + assertEquals(1, getDividerPosition()) + + verify(callback).onNoneChanged(false) + + verify(callback).onFirstChange() + } + + @Test + fun testMoveBetweenFavorites() { + val from = 2 + val to = 4 + + model.onMoveItem(from, to) + assertEquals( + listOf(0, 1, 3, 4, 2, 5).map { "$ID_PREFIX$it" }, + model.favorites.map(ControlInfo::controlId) + ) + verify(adapter).notifyItemMoved(from, to) + verify(adapter, never()).notifyItemChanged(anyInt(), any(Any::class.java)) + + verify(callback).onFirstChange() + } + + private fun getDividerPosition(): Int = model.elements.indexOf(dividerWrapper) +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java index c9bb4016c7bf..9985d21e8515 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java @@ -20,8 +20,10 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.hardware.display.AmbientDisplayConfiguration; import android.testing.AndroidTestingRunner; @@ -56,6 +58,7 @@ public class DozeDockHandlerTest extends SysuiTestCase { mDockManagerFake = spy(new DockManagerFake()); mDockHandler = new DozeDockHandler(mConfig, mMachine, mDockManagerFake); + when(mMachine.getState()).thenReturn(State.DOZE_AOD); doReturn(true).when(mConfig).alwaysOnEnabled(anyInt()); mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED); } @@ -101,4 +104,31 @@ public class DozeDockHandlerTest extends SysuiTestCase { verify(mMachine).requestState(eq(State.DOZE)); } + + @Test + public void onEvent_dockedWhilePulsing_wontRequestStateChange() { + when(mMachine.getState()).thenReturn(State.DOZE_PULSING); + + mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED); + + verify(mMachine, never()).requestState(any(State.class)); + } + + @Test + public void onEvent_noneWhilePulsing_wontRequestStateChange() { + when(mMachine.getState()).thenReturn(State.DOZE_PULSING); + + mDockManagerFake.setDockEvent(DockManager.STATE_NONE); + + verify(mMachine, never()).requestState(any(State.class)); + } + + @Test + public void onEvent_hideWhilePulsing_wontRequestStateChange() { + when(mMachine.getState()).thenReturn(State.DOZE_PULSING); + + mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE); + + verify(mMachine, never()).requestState(any(State.class)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java index c483314918fc..1f07f46bf764 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java @@ -254,6 +254,17 @@ public class DozeMachineTest extends SysuiTestCase { } @Test + public void testPulseDone_whileDockedAoD_staysDockedAod() { + when(mDockManager.isDocked()).thenReturn(true); + mMachine.requestState(INITIALIZED); + mMachine.requestState(DOZE_AOD_DOCKED); + + mMachine.requestState(DOZE_PULSE_DONE); + + verify(mPartMock, never()).transitionTo(DOZE_AOD_DOCKED, DOZE_PULSE_DONE); + } + + @Test public void testPulseDone_dozeSuppressed_afterDocked_goesToDoze() { when(mHost.isDozeSuppressed()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java index 137a126f539d..b44b23a9f51e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java @@ -16,8 +16,14 @@ package com.android.systemui.globalactions; +import static junit.framework.Assert.assertEquals; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.IActivityManager; import android.app.admin.DevicePolicyManager; @@ -31,6 +37,7 @@ import android.service.dreams.IDreamManager; import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.FeatureFlagUtils; import android.view.IWindowManager; import androidx.test.filters.SmallTest; @@ -52,6 +59,8 @@ import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.RingerModeLiveData; +import com.android.systemui.util.RingerModeTracker; import org.junit.Before; import org.junit.Test; @@ -63,7 +72,7 @@ import java.util.concurrent.Executor; @SmallTest @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper() public class GlobalActionsDialogTest extends SysuiTestCase { private GlobalActionsDialog mGlobalActionsDialog; @@ -95,6 +104,8 @@ public class GlobalActionsDialogTest extends SysuiTestCase { @Mock private ControlsListingController mControlsListingController; @Mock private ControlsController mControlsController; @Mock private UiEventLogger mUiEventLogger; + @Mock private RingerModeTracker mRingerModeTracker; + @Mock private RingerModeLiveData mRingerModeLiveData; private TestableLooper mTestableLooper; @@ -103,6 +114,8 @@ public class GlobalActionsDialogTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); allowTestableLooperAsMainThread(); + + when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData); mGlobalActionsDialog = new GlobalActionsDialog(mContext, mWindowManagerFuncs, mAudioManager, @@ -133,13 +146,122 @@ public class GlobalActionsDialogTest extends SysuiTestCase { mBackgroundExecutor, mControlsListingController, mControlsController, - mUiEventLogger + mUiEventLogger, + mRingerModeTracker ); + mGlobalActionsDialog.setZeroDialogPressDelayForTesting(); } + @Test public void testShouldLogVisibility() { mGlobalActionsDialog.onShow(null); + mTestableLooper.processAllMessages(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_OPEN); + } + + @Test + public void testShouldLogBugreportPress() throws InterruptedException { + GlobalActionsDialog.BugReportAction bugReportAction = + mGlobalActionsDialog.makeBugReportActionForTesting(); + bugReportAction.onPress(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_PRESS); + } + + @Test + public void testShouldLogBugreportLongPress() { + GlobalActionsDialog.BugReportAction bugReportAction = + mGlobalActionsDialog.makeBugReportActionForTesting(); + bugReportAction.onLongPress(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS); + } + + @Test + public void testShouldLogEmergencyDialerPress() { + GlobalActionsDialog.EmergencyDialerAction emergencyDialerAction = + mGlobalActionsDialog.makeEmergencyDialerActionForTesting(); + emergencyDialerAction.onPress(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS); + } + + @Test + public void testShouldLogScreenshotPress() { + GlobalActionsDialog.ScreenshotAction screenshotAction = + mGlobalActionsDialog.makeScreenshotActionForTesting(); + screenshotAction.onPress(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_PRESS); + } + + @Test + public void testShouldLogScreenshotLongPress() { + FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SCREENRECORD_LONG_PRESS, true); + GlobalActionsDialog.ScreenshotAction screenshotAction = + mGlobalActionsDialog.makeScreenshotActionForTesting(); + screenshotAction.onLongPress(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS); + } + + private void verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent event) { + mTestableLooper.processAllMessages(); verify(mUiEventLogger, times(1)) - .log(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_OPEN); + .log(event); + } + + @Test + public void testCreateActionItems_maxThree() { + mGlobalActionsDialog = spy(mGlobalActionsDialog); + // allow 3 items to be shown + doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems(); + // ensure items are not blocked by keyguard or device provisioning + doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any()); + String[] actions = { + GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, + GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, + GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, + GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT, + }; + doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); + mGlobalActionsDialog.createActionItems(); + + assertEquals(3, mGlobalActionsDialog.mItems.size()); + assertEquals(1, mGlobalActionsDialog.mOverflowItems.size()); + } + + @Test + public void testCreateActionItems_maxAny() { + mGlobalActionsDialog = spy(mGlobalActionsDialog); + // allow any number of power menu items to be shown + doReturn(Integer.MAX_VALUE).when(mGlobalActionsDialog).getMaxShownPowerItems(); + // ensure items are not blocked by keyguard or device provisioning + doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any()); + String[] actions = { + GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, + GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, + GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, + GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT, + }; + doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); + mGlobalActionsDialog.createActionItems(); + + assertEquals(4, mGlobalActionsDialog.mItems.size()); + assertEquals(0, mGlobalActionsDialog.mOverflowItems.size()); + } + + @Test + public void testCreateActionItems_maxThree_itemNotShown() { + mGlobalActionsDialog = spy(mGlobalActionsDialog); + // allow only 3 items to be shown + doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems(); + String[] actions = { + GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY, + // screenshot blocked because device not provisioned + GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT, + GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER, + GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART, + }; + doReturn(actions).when(mGlobalActionsDialog).getDefaultActions(); + mGlobalActionsDialog.createActionItems(); + + assertEquals(3, mGlobalActionsDialog.mItems.size()); + assertEquals(0, mGlobalActionsDialog.mOverflowItems.size()); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 6871aad0ea98..24b128af9fbd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -43,7 +43,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.statusbar.phone.NavigationModeController; -import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; @@ -66,7 +65,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock LockPatternUtils mLockPatternUtils; private @Mock KeyguardUpdateMonitor mUpdateMonitor; private @Mock StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; - private @Mock NotificationShadeWindowController mNotificationShadeWindowController; private @Mock BroadcastDispatcher mBroadcastDispatcher; private @Mock DismissCallbackRegistry mDismissCallbackRegistry; private @Mock DumpManager mDumpManager; @@ -88,7 +86,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mViewMediator = new KeyguardViewMediator( mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher, - mNotificationShadeWindowController, () -> mStatusBarKeyguardViewManager, + () -> mStatusBarKeyguardViewManager, mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor, mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController); mViewMediator.start(); @@ -98,18 +96,18 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { public void testOnGoingToSleep_UpdatesKeyguardGoingAway() { mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER); verify(mUpdateMonitor).setKeyguardGoingAway(false); - verify(mNotificationShadeWindowController, never()).setKeyguardGoingAway(anyBoolean()); + verify(mStatusBarKeyguardViewManager, never()).setKeyguardGoingAwayState(anyBoolean()); } @Test public void testRegisterDumpable() { verify(mDumpManager).registerDumpable(KeyguardViewMediator.class.getName(), mViewMediator); - verify(mNotificationShadeWindowController, never()).setKeyguardGoingAway(anyBoolean()); + verify(mStatusBarKeyguardViewManager, never()).setKeyguardGoingAwayState(anyBoolean()); } @Test public void testKeyguardGone_notGoingaway() { mViewMediator.mViewMediatorCallback.keyguardGone(); - verify(mNotificationShadeWindowController).setKeyguardGoingAway(eq(false)); + verify(mStatusBarKeyguardViewManager).setKeyguardGoingAwayState(eq(false)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt index 260f52070a70..d407b8a1e449 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt @@ -67,10 +67,11 @@ public class SeekBarObserverTest : SysuiTestCase() { val isEnabled = false val data = SeekBarViewModel.Progress(isEnabled, false, null, null, null) observer.onChanged(data) - // THEN seek bar visibility is set to GONE - assertThat(seekBarView.getVisibility()).isEqualTo(View.GONE) - assertThat(elapsedTimeView.getVisibility()).isEqualTo(View.GONE) - assertThat(totalTimeView.getVisibility()).isEqualTo(View.GONE) + // THEN seek bar shows just a line with no text + assertThat(seekBarView.isEnabled()).isFalse() + assertThat(seekBarView.getThumb().getAlpha()).isEqualTo(0) + assertThat(elapsedTimeView.getText()).isEqualTo("") + assertThat(totalTimeView.getText()).isEqualTo("") } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java index 0d66340a3917..56a748497d4e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java @@ -51,7 +51,6 @@ public class PipAnimationControllerTest extends SysuiTestCase { private PipAnimationController mPipAnimationController; - @Mock private SurfaceControl mLeash; @Mock @@ -61,6 +60,10 @@ public class PipAnimationControllerTest extends SysuiTestCase { public void setUp() throws Exception { mPipAnimationController = new PipAnimationController( mContext, new PipSurfaceTransactionHelper(mContext)); + mLeash = new SurfaceControl.Builder() + .setContainerLayer() + .setName("FakeLeash") + .build(); MockitoAnnotations.initMocks(this); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java index 0bf0f04d2d43..425bf88ebec0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java @@ -17,6 +17,7 @@ package com.android.systemui.pip; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.content.ComponentName; @@ -56,11 +57,15 @@ public class PipBoundsHandlerTest extends SysuiTestCase { private PipBoundsHandler mPipBoundsHandler; private DisplayInfo mDefaultDisplayInfo; + private ComponentName mTestComponentName1; + private ComponentName mTestComponentName2; @Before public void setUp() throws Exception { initializeMockResources(); mPipBoundsHandler = new PipBoundsHandler(mContext, new PipSnapAlgorithm(mContext)); + mTestComponentName1 = new ComponentName(mContext, "component1"); + mTestComponentName2 = new ComponentName(mContext, "component2"); mPipBoundsHandler.onDisplayInfoChanged(mDefaultDisplayInfo); } @@ -121,7 +126,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { }; for (float aspectRatio : aspectRatios) { final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - aspectRatio, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + mTestComponentName1, aspectRatio, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); assertEquals("Destination bounds matches the given aspect ratio", @@ -137,7 +142,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { }; for (float aspectRatio : invalidAspectRatios) { final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - aspectRatio, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + mTestComponentName1, aspectRatio, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); assertEquals("Destination bounds fallbacks to default aspect ratio", @@ -153,7 +158,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left; final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - aspectRatio, currentBounds, EMPTY_MINIMAL_SIZE); + mTestComponentName1, aspectRatio, currentBounds, EMPTY_MINIMAL_SIZE); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); @@ -177,7 +182,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { final float aspectRatio = aspectRatios[i]; final Size minimalSize = minimalSizes[i]; final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - aspectRatio, EMPTY_CURRENT_BOUNDS, minimalSize); + mTestComponentName1, aspectRatio, EMPTY_CURRENT_BOUNDS, minimalSize); assertTrue("Destination bounds is no smaller than minimal requirement", (destinationBounds.width() == minimalSize.getWidth() && destinationBounds.height() >= minimalSize.getHeight()) @@ -198,7 +203,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { final Size minSize = new Size(currentBounds.width() / 2, currentBounds.height() / 2); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( - aspectRatio, currentBounds, minSize); + mTestComponentName1, aspectRatio, currentBounds, minSize); assertTrue("Destination bounds ignores minimal size", destinationBounds.width() > minSize.getWidth() @@ -206,81 +211,92 @@ public class PipBoundsHandlerTest extends SysuiTestCase { } @Test + public void getDestinationBounds_withDifferentComponentName_ignoreLastPosition() { + final Rect oldPosition = mPipBoundsHandler.getDestinationBounds(mTestComponentName1, + DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + + oldPosition.offset(0, -100); + mPipBoundsHandler.onSaveReentryBounds(mTestComponentName1, oldPosition); + + final Rect newPosition = mPipBoundsHandler.getDestinationBounds(mTestComponentName2, + DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); + + assertNonBoundsInclusionWithMargin("ignore saved bounds", oldPosition, newPosition); + } + + @Test public void setShelfHeight_offsetBounds() { final int shelfHeight = 100; - final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( + final Rect oldPosition = mPipBoundsHandler.getDestinationBounds(mTestComponentName1, DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); mPipBoundsHandler.setShelfHeight(true, shelfHeight); - final Rect newPosition = mPipBoundsHandler.getDestinationBounds( + final Rect newPosition = mPipBoundsHandler.getDestinationBounds(mTestComponentName1, DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); oldPosition.offset(0, -shelfHeight); - assertBoundsWithMargin("offsetBounds by shelf", oldPosition, newPosition); + assertBoundsInclusionWithMargin("offsetBounds by shelf", oldPosition, newPosition); } @Test public void onImeVisibilityChanged_offsetBounds() { final int imeHeight = 100; - final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( + final Rect oldPosition = mPipBoundsHandler.getDestinationBounds(mTestComponentName1, DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); mPipBoundsHandler.onImeVisibilityChanged(true, imeHeight); - final Rect newPosition = mPipBoundsHandler.getDestinationBounds( + final Rect newPosition = mPipBoundsHandler.getDestinationBounds(mTestComponentName1, DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); oldPosition.offset(0, -imeHeight); - assertBoundsWithMargin("offsetBounds by IME", oldPosition, newPosition); + assertBoundsInclusionWithMargin("offsetBounds by IME", oldPosition, newPosition); } @Test public void onSaveReentryBounds_restoreLastPosition() { - final ComponentName componentName = new ComponentName(mContext, "component1"); - final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( + final Rect oldPosition = mPipBoundsHandler.getDestinationBounds(mTestComponentName1, DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); oldPosition.offset(0, -100); - mPipBoundsHandler.onSaveReentryBounds(componentName, oldPosition); + mPipBoundsHandler.onSaveReentryBounds(mTestComponentName1, oldPosition); - final Rect newPosition = mPipBoundsHandler.getDestinationBounds( + final Rect newPosition = mPipBoundsHandler.getDestinationBounds(mTestComponentName1, DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); - assertBoundsWithMargin("restoreLastPosition", oldPosition, newPosition); + assertBoundsInclusionWithMargin("restoreLastPosition", oldPosition, newPosition); } @Test public void onResetReentryBounds_useDefaultBounds() { - final ComponentName componentName = new ComponentName(mContext, "component1"); - final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds( + final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds(mTestComponentName1, DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final Rect newBounds = new Rect(defaultBounds); newBounds.offset(0, -100); - mPipBoundsHandler.onSaveReentryBounds(componentName, newBounds); + mPipBoundsHandler.onSaveReentryBounds(mTestComponentName1, newBounds); - mPipBoundsHandler.onResetReentryBounds(componentName); - final Rect actualBounds = mPipBoundsHandler.getDestinationBounds( + mPipBoundsHandler.onResetReentryBounds(mTestComponentName1); + final Rect actualBounds = mPipBoundsHandler.getDestinationBounds(mTestComponentName1, DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); - assertBoundsWithMargin("useDefaultBounds", defaultBounds, actualBounds); + assertBoundsInclusionWithMargin("useDefaultBounds", defaultBounds, actualBounds); } @Test public void onResetReentryBounds_componentMismatch_restoreLastPosition() { - final ComponentName componentName = new ComponentName(mContext, "component1"); - final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds( + final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds(mTestComponentName1, DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final Rect newBounds = new Rect(defaultBounds); newBounds.offset(0, -100); - mPipBoundsHandler.onSaveReentryBounds(componentName, newBounds); + mPipBoundsHandler.onSaveReentryBounds(mTestComponentName1, newBounds); - mPipBoundsHandler.onResetReentryBounds(new ComponentName(mContext, "component2")); - final Rect actualBounds = mPipBoundsHandler.getDestinationBounds( + mPipBoundsHandler.onResetReentryBounds(mTestComponentName2); + final Rect actualBounds = mPipBoundsHandler.getDestinationBounds(mTestComponentName1, DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); - assertBoundsWithMargin("restoreLastPosition", newBounds, actualBounds); + assertBoundsInclusionWithMargin("restoreLastPosition", newBounds, actualBounds); } - private void assertBoundsWithMargin(String from, Rect expected, Rect actual) { + private void assertBoundsInclusionWithMargin(String from, Rect expected, Rect actual) { final Rect expectedWithMargin = new Rect(expected); expectedWithMargin.inset(-ROUNDING_ERROR_MARGIN, -ROUNDING_ERROR_MARGIN); assertTrue(from + ": expect " + expected @@ -288,4 +304,13 @@ public class PipBoundsHandlerTest extends SysuiTestCase { + " with error margin " + ROUNDING_ERROR_MARGIN, expectedWithMargin.contains(actual)); } + + private void assertNonBoundsInclusionWithMargin(String from, Rect expected, Rect actual) { + final Rect expectedWithMargin = new Rect(expected); + expectedWithMargin.inset(-ROUNDING_ERROR_MARGIN, -ROUNDING_ERROR_MARGIN); + assertFalse(from + ": expect " + expected + + " not contains " + actual + + " with error margin " + ROUNDING_ERROR_MARGIN, + expectedWithMargin.contains(actual)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java index 4d7e6aec8aa9..721125409c5a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java @@ -29,7 +29,6 @@ import android.graphics.Rect; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.Size; -import android.view.DisplayInfo; import androidx.test.filters.SmallTest; @@ -59,12 +58,8 @@ import org.mockito.MockitoAnnotations; @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) public class PipTouchHandlerTest extends SysuiTestCase { - private static final int ROUNDING_ERROR_MARGIN = 10; - private static final float DEFAULT_ASPECT_RATIO = 1f; - private static final Rect EMPTY_CURRENT_BOUNDS = null; private PipTouchHandler mPipTouchHandler; - private DisplayInfo mDefaultDisplayInfo; @Mock private IActivityManager mActivityManager; @@ -90,18 +85,17 @@ public class PipTouchHandlerTest extends SysuiTestCase { @Mock private DeviceConfigProxy mDeviceConfigProxy; - private PipSnapAlgorithm mPipSnapAlgorithm; private PipMotionHelper mMotionHelper; private PipResizeGestureHandler mPipResizeGestureHandler; - Rect mInsetBounds; - Rect mMinBounds; - Rect mCurBounds; - boolean mFromImeAdjustment; - boolean mFromShelfAdjustment; - int mDisplayRotation; - + private Rect mInsetBounds; + private Rect mMinBounds; + private Rect mCurBounds; + private boolean mFromImeAdjustment; + private boolean mFromShelfAdjustment; + private int mDisplayRotation; + private int mImeHeight; @Before public void setUp() throws Exception { @@ -121,10 +115,11 @@ public class PipTouchHandlerTest extends SysuiTestCase { mInsetBounds = new Rect(10, 10, 990, 990); // minBounds of 100x100 bottom right corner mMinBounds = new Rect(890, 890, 990, 990); - mCurBounds = new Rect(); + mCurBounds = new Rect(mMinBounds); mFromImeAdjustment = false; mFromShelfAdjustment = false; mDisplayRotation = 0; + mImeHeight = 100; } @Test @@ -162,6 +157,8 @@ public class PipTouchHandlerTest extends SysuiTestCase { @Test public void updateMovementBounds_withImeAdjustment_movesPip() { mFromImeAdjustment = true; + mPipTouchHandler.onImeVisibilityChanged(true /* imeVisible */, mImeHeight); + mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds, mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt index 6b7a3bfce5ad..c874915e9124 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt @@ -117,12 +117,27 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() { } @Test - fun updateGlobalDialogVisibility_appliesBlur() { + fun updateGlobalDialogVisibility_animatesBlur() { notificationShadeDepthController.updateGlobalDialogVisibility(0.5f, root) verify(globalActionsSpring).animateTo(eq(maxBlur / 2), safeEq(root)) } @Test + fun updateGlobalDialogVisibility_appliesBlur_withoutHomeControls() { + `when`(globalActionsSpring.radius).thenReturn(maxBlur) + notificationShadeDepthController.updateBlurCallback.doFrame(0) + verify(blurUtils).applyBlur(any(), eq(maxBlur)) + } + + @Test + fun updateGlobalDialogVisibility_appliesBlur_unlessHomeControls() { + notificationShadeDepthController.showingHomeControls = true + `when`(globalActionsSpring.radius).thenReturn(maxBlur) + notificationShadeDepthController.updateBlurCallback.doFrame(0) + verify(blurUtils).applyBlur(any(), eq(0)) + } + + @Test fun updateBlurCallback_setsBlurAndZoom() { notificationShadeDepthController.updateBlurCallback.doFrame(0) verify(wallpaperManager).setWallpaperZoomOut(any(), anyFloat()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt deleted file mode 100644 index d522f903c83a..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.systemui.statusbar.notification - -import com.android.systemui.statusbar.FeatureFlags -import com.android.systemui.statusbar.NotificationPresenter -import com.android.systemui.statusbar.NotificationRemoteInputManager -import com.android.systemui.statusbar.notification.collection.NotificationEntry -import com.android.systemui.statusbar.notification.collection.NotificationRankingManager -import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder -import com.android.systemui.statusbar.phone.NotificationGroupManager -import com.android.systemui.util.leak.LeakDetector -import java.util.concurrent.CountDownLatch - -/** - * Enable some test capabilities for NEM without making everything public on the base class - */ -class TestableNotificationEntryManager( - logger: NotificationEntryManagerLogger, - gm: NotificationGroupManager, - rm: NotificationRankingManager, - ke: KeyguardEnvironment, - ff: FeatureFlags, - rb: dagger.Lazy<NotificationRowBinder>, - notificationRemoteInputManagerLazy: dagger.Lazy<NotificationRemoteInputManager>, - leakDetector: LeakDetector, - fgsFeatureController: ForegroundServiceDismissalFeatureController -) : NotificationEntryManager(logger, gm, rm, ke, ff, rb, - notificationRemoteInputManagerLazy, leakDetector, fgsFeatureController) { - - public var countDownLatch: CountDownLatch = CountDownLatch(1) - - override fun onAsyncInflationFinished(entry: NotificationEntry) { - super.onAsyncInflationFinished(entry) - countDownLatch.countDown() - } - - fun setUpForTest( - presenter: NotificationPresenter? - ) { - super.setUpWithPresenter(presenter) - } - - fun setActiveNotificationList(activeList: List<NotificationEntry>) { - mSortedAndFiltered.clear() - mSortedAndFiltered.addAll(activeList) - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java index 43cf83f380f1..81f9546ba885 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java @@ -29,6 +29,7 @@ import android.service.notification.StatusBarNotification; import com.android.internal.logging.InstanceId; import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.SbnBuilder; +import com.android.systemui.util.time.FakeSystemClock; import java.util.ArrayList; @@ -44,16 +45,22 @@ import java.util.ArrayList; public class NotificationEntryBuilder { private final SbnBuilder mSbnBuilder = new SbnBuilder(); private final RankingBuilder mRankingBuilder = new RankingBuilder(); + private final FakeSystemClock mClock = new FakeSystemClock(); private StatusBarNotification mSbn = null; /* ListEntry properties */ private GroupEntry mParent; private int mSection = -1; + /* If set, use this creation time instead of mClock.uptimeMillis */ + private long mCreationTime = -1; + public NotificationEntry build() { StatusBarNotification sbn = mSbn != null ? mSbn : mSbnBuilder.build(); mRankingBuilder.setKey(sbn.getKey()); - final NotificationEntry entry = new NotificationEntry(sbn, mRankingBuilder.build()); + long creationTime = mCreationTime != -1 ? mCreationTime : mClock.uptimeMillis(); + final NotificationEntry entry = new NotificationEntry( + sbn, mRankingBuilder.build(), mClock.uptimeMillis()); /* ListEntry properties */ entry.setParent(mParent); @@ -86,6 +93,14 @@ public class NotificationEntryBuilder { return this; } + /** + * Set the creation time + */ + public NotificationEntryBuilder setCreationTime(long creationTime) { + mCreationTime = creationTime; + return this; + } + /* Delegated to SbnBuilder */ public NotificationEntryBuilder setPkg(String pkg) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java index 5b0b66849027..1a022ec7c87d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java @@ -52,6 +52,7 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.SbnBuilder; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -71,6 +72,7 @@ public class NotificationEntryTest extends SysuiTestCase { private int mId; private NotificationEntry mEntry; + private final FakeSystemClock mClock = new FakeSystemClock(); @Before public void setup() { @@ -187,7 +189,7 @@ public class NotificationEntryTest extends SysuiTestCase { .build(); NotificationEntry entry = - new NotificationEntry(sbn, ranking); + new NotificationEntry(sbn, ranking, mClock.uptimeMillis()); assertEquals(systemGeneratedSmartActions, entry.getSmartActions()); assertEquals(NOTIFICATION_CHANNEL, entry.getChannel()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java index 6b9e43bcb290..35b31c01fd9c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -62,7 +63,6 @@ public class PreparationCoordinatorTest extends SysuiTestCase { private OnBeforeFinalizeFilterListener mBeforeFilterListener; private NotifFilter mUninflatedFilter; private NotifFilter mInflationErrorFilter; - private NotifInflaterImpl.InflationCallback mCallback; private NotifInflationErrorManager mErrorManager; private NotificationEntry mEntry; private Exception mInflationError; @@ -104,9 +104,6 @@ public class PreparationCoordinatorTest extends SysuiTestCase { mBeforeFilterListenerCaptor.capture()); mBeforeFilterListener = mBeforeFilterListenerCaptor.getValue(); - verify(mNotifInflater).setInflationCallback(mCallbackCaptor.capture()); - mCallback = mCallbackCaptor.getValue(); - mCollectionListener.onEntryInit(mEntry); } @@ -142,7 +139,7 @@ public class PreparationCoordinatorTest extends SysuiTestCase { mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); // THEN we inflate it - verify(mNotifInflater).inflateViews(mEntry); + verify(mNotifInflater).inflateViews(eq(mEntry), any()); // THEN we filter it out until it's done inflating. assertTrue(mUninflatedFilter.shouldFilterOut(mEntry, 0)); @@ -151,14 +148,17 @@ public class PreparationCoordinatorTest extends SysuiTestCase { @Test public void testRebindsInflatedNotificationsOnUpdate() { // GIVEN an inflated notification - mCallback.onInflationFinished(mEntry); + mCollectionListener.onEntryAdded(mEntry); + mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); + verify(mNotifInflater).inflateViews(eq(mEntry), mCallbackCaptor.capture()); + mCallbackCaptor.getValue().onInflationFinished(mEntry); // WHEN notification is updated mCollectionListener.onEntryUpdated(mEntry); mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); // THEN we rebind it - verify(mNotifInflater).rebindViews(mEntry); + verify(mNotifInflater).rebindViews(eq(mEntry), any()); // THEN we do not filter it because it's not the first inflation. assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0)); @@ -166,8 +166,11 @@ public class PreparationCoordinatorTest extends SysuiTestCase { @Test public void testDoesntFilterInflatedNotifs() { - // WHEN a notification is inflated - mCallback.onInflationFinished(mEntry); + // GIVEN an inflated notification + mCollectionListener.onEntryAdded(mEntry); + mBeforeFilterListener.onBeforeFinalizeFilter(List.of(mEntry)); + verify(mNotifInflater).inflateViews(eq(mEntry), mCallbackCaptor.capture()); + mCallbackCaptor.getValue().onInflationFinished(mEntry); // THEN it isn't filtered from shade list assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index be026f7884c3..855f524db3f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -18,10 +18,11 @@ package com.android.systemui.statusbar.notification.row; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; +import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; + import static junit.framework.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -139,6 +140,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { private NotificationRowBinderImpl mRowBinder; private Handler mHandler; private FakeExecutor mBgExecutor; + private RowContentBindStage mRowContentBindStage; @Before public void setUp() { @@ -147,10 +149,13 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { mHandler = Handler.createAsync(TestableLooper.get(this).getLooper()); + // Add an action so heads up content views are made + Notification.Action action = new Notification.Action.Builder(null, null, null).build(); Notification notification = new Notification.Builder(mContext) .setSmallIcon(R.drawable.ic_person) .setContentTitle(TEST_TITLE) .setContentText(TEST_TEXT) + .setActions(action) .build(); mSbn = new SbnBuilder() .setNotification(notification) @@ -192,11 +197,11 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { () -> mock(SmartReplyController.class), mock(ConversationNotificationProcessor.class), mBgExecutor); - RowContentBindStage stage = new RowContentBindStage( + mRowContentBindStage = new RowContentBindStage( binder, mock(NotifInflationErrorManager.class), mock(RowContentBindStageLogger.class)); - pipeline.setStage(stage); + pipeline.setStage(mRowContentBindStage); ArgumentCaptor<ExpandableNotificationRow> viewCaptor = ArgumentCaptor.forClass(ExpandableNotificationRow.class); @@ -210,9 +215,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { .onDismissRunnable(any())) .thenReturn(mExpandableNotificationRowComponentBuilder); when(mExpandableNotificationRowComponentBuilder - .inflationCallback(any())) - .thenReturn(mExpandableNotificationRowComponentBuilder); - when(mExpandableNotificationRowComponentBuilder .rowContentBindStage(any())) .thenReturn(mExpandableNotificationRowComponentBuilder); when(mExpandableNotificationRowComponentBuilder @@ -232,12 +234,11 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { "FOOBAR", "FOOBAR", mKeyguardBypassController, mGroupManager, - stage, + mRowContentBindStage, mock(NotificationLogger.class), mHeadsUpManager, mPresenter, mStatusBarStateController, - mEntryManager, mGutsManager, true, null, @@ -256,7 +257,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { mRemoteInputManager, mLockscreenUserManager, pipeline, - stage, + mRowContentBindStage, mNotificationInterruptionStateProvider, RowInflaterTask::new, mExpandableNotificationRowComponentBuilder, @@ -269,7 +270,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { mEntryManager.addNotificationEntryListener(mEntryListener); mRowBinder.setUpWithPresenter(mPresenter, mListContainer, mBindCallback); - mRowBinder.setInflationCallback(mEntryManager); mRowBinder.setNotificationClicker(mock(NotificationClicker.class)); Ranking ranking = new Ranking(); @@ -324,7 +324,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { assertNotNull(entry.getRow().getPrivateLayout().getContractedChild()); // THEN inflation callbacks are called - verify(mBindCallback).onBindRow(eq(entry), any(), eq(mSbn), any()); + verify(mBindCallback).onBindRow(entry.getRow()); verify(mEntryListener, never()).onInflationError(any(), any()); verify(mEntryListener).onEntryInflated(entry); verify(mEntryListener).onNotificationAdded(entry); @@ -365,6 +365,27 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { verify(mPresenter).updateNotificationViews(); } + @Test + public void testContentViewInflationDuringRowInflationInflatesCorrectViews() { + // GIVEN a notification is added and the row is inflating + mEntryManager.addNotification(mSbn, mRankingMap); + ArgumentCaptor<NotificationEntry> entryCaptor = ArgumentCaptor.forClass( + NotificationEntry.class); + verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture()); + NotificationEntry entry = entryCaptor.getValue(); + + // WHEN we try to bind a content view + mRowContentBindStage.getStageParams(entry).requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP); + mRowContentBindStage.requestRebind(entry, null); + + waitForInflation(); + + // THEN the notification has its row and all relevant content views inflated + assertNotNull(entry.getRow()); + assertNotNull(entry.getRow().getPrivateLayout().getContractedChild()); + assertNotNull(entry.getRow().getPrivateLayout().getHeadsUpChild()); + } + /** * Wait for inflation to finish. * diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index ef2071ef090e..657bc8d614cf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -69,7 +69,6 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; -import com.android.systemui.statusbar.notification.TestableNotificationEntryManager; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; @@ -138,7 +137,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private FeatureFlags mFeatureFlags; private UserChangedListener mUserChangedListener; - private TestableNotificationEntryManager mEntryManager; + private NotificationEntryManager mEntryManager; private int mOriginalInterruptionModelSetting; private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake(); @@ -167,7 +166,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { ArgumentCaptor<UserChangedListener> userChangedCaptor = ArgumentCaptor .forClass(UserChangedListener.class); - mEntryManager = new TestableNotificationEntryManager( + mEntryManager = new NotificationEntryManager( mock(NotificationEntryManagerLogger.class), mock(NotificationGroupManager.class), new NotificationRankingManager( @@ -187,7 +186,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mock(LeakDetector.class), mock(ForegroundServiceDismissalFeatureController.class) ); - mEntryManager.setUpForTest(mock(NotificationPresenter.class)); + mEntryManager.setUpWithPresenter(mock(NotificationPresenter.class)); when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false); NotificationShelf notificationShelf = mock(NotificationShelf.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index bfcf41db5287..a927c8011b8f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java @@ -109,7 +109,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mNotificationShadeWindowController, mKeyguardStateController, mHandler, mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters, mMetricsLogger, mDumpManager); - mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); + mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); } @Test @@ -202,7 +202,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { @Test public void onBiometricAuthenticated_whenFace_andBypass_dismissKeyguard() { when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true); - mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); + mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); // the value of isStrongBiometric doesn't matter here since we only care about the returned @@ -221,7 +221,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { public void onBiometricAuthenticated_whenFace_andBypass_encrypted_showBouncer() { reset(mUpdateMonitor); when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true); - mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); + mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); // the value of isStrongBiometric doesn't matter here since we only care about the returned @@ -241,7 +241,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { @Test public void onBiometricAuthenticated_whenFace_noBypass_encrypted_doNothing() { reset(mUpdateMonitor); - mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); + mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); // the value of isStrongBiometric doesn't matter here since we only care about the returned diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt new file mode 100644 index 000000000000..2489c301f6f5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt @@ -0,0 +1,112 @@ +/* + * 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.util + +import android.content.BroadcastReceiver +import android.content.IntentFilter +import android.os.UserHandle +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.lifecycle.Observer +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastDispatcher +import org.junit.After +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.MockitoAnnotations +import java.util.concurrent.Executor + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +class RingerModeLiveDataTest : SysuiTestCase() { + + companion object { + private fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() + private fun <T> any(): T = Mockito.any() + private fun <T> eq(value: T): T = Mockito.eq(value) ?: value + private val INTENT = "INTENT" + } + + @Mock + private lateinit var broadcastDispatcher: BroadcastDispatcher + @Mock + private lateinit var valueSupplier: () -> Int + @Mock + private lateinit var observer: Observer<Int> + @Captor + private lateinit var broadcastReceiverCaptor: ArgumentCaptor<BroadcastReceiver> + @Captor + private lateinit var intentFilterCaptor: ArgumentCaptor<IntentFilter> + + // Run everything immediately + private val executor = Executor { it.run() } + private lateinit var liveData: RingerModeLiveData + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + liveData = RingerModeLiveData(broadcastDispatcher, executor, INTENT, valueSupplier) + } + + @After + fun tearDown() { + liveData.removeObserver(observer) + } + + @Test + fun testInit_broadcastNotRegistered() { + verifyNoMoreInteractions(broadcastDispatcher) + } + + @Test + fun testOnActive_broadcastRegistered() { + liveData.observeForever(observer) + verify(broadcastDispatcher).registerReceiver(any(), any(), eq(executor), eq(UserHandle.ALL)) + } + + @Test + fun testOnActive_intentFilterHasIntent() { + liveData.observeForever(observer) + verify(broadcastDispatcher).registerReceiver(any(), capture(intentFilterCaptor), any(), + any()) + assertTrue(intentFilterCaptor.value.hasAction(INTENT)) + } + + @Test + fun testOnActive_valueObtained() { + liveData.observeForever(observer) + verify(valueSupplier).invoke() + } + + @Test + fun testOnInactive_broadcastUnregistered() { + liveData.observeForever(observer) + liveData.removeObserver(observer) + verify(broadcastDispatcher).unregisterReceiver(any()) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt index 950f70fcda46..eb435f9314e7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt @@ -134,6 +134,7 @@ class PhysicsAnimatorTest : SysuiTestCase() { @Test @Throws(InterruptedException::class) + @Ignore("Increasingly flaky") fun testEndListenersAndActions() { PhysicsAnimatorTestUtils.setAllAnimationsBlock(false) animator diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt index f1672b1c644d..f6b7b74d4bfc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt @@ -106,6 +106,10 @@ class MagnetizedObjectTest : SysuiTestCase() { location[1] = targetCenterY - targetSize / 2 // y = 800 } }.`when`(targetView).getLocationOnScreen(ArgumentMatchers.any()) + doAnswer { invocation -> + (invocation.arguments[0] as Runnable).run() + true + }.`when`(targetView).post(ArgumentMatchers.any()) `when`(targetView.context).thenReturn(context) magneticTarget = MagnetizedObject.MagneticTarget(targetView, magneticFieldRadius) @@ -408,6 +412,10 @@ class MagnetizedObjectTest : SysuiTestCase() { `when`(secondTargetView.width).thenReturn(targetSize) // width = 200 `when`(secondTargetView.height).thenReturn(targetSize) // height = 200 doAnswer { invocation -> + (invocation.arguments[0] as Runnable).run() + true + }.`when`(secondTargetView).post(ArgumentMatchers.any()) + doAnswer { invocation -> (invocation.arguments[0] as IntArray).also { location -> // Return the top left of the target. location[0] = secondTargetCenterX - targetSize / 2 // x = 0 diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java index 8cc83dd99b53..6166cd76e005 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java @@ -31,6 +31,7 @@ import android.media.session.MediaSession; import android.os.Handler; import android.os.Process; import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import androidx.test.filters.SmallTest; @@ -38,7 +39,10 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.util.RingerModeLiveData; +import com.android.systemui.util.RingerModeTracker; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,6 +53,7 @@ import java.util.Optional; @RunWith(AndroidTestingRunner.class) @SmallTest +@TestableLooper.RunWithLooper public class VolumeDialogControllerImplTest extends SysuiTestCase { TestableVolumeDialogControllerImpl mVolumeController; @@ -56,18 +61,35 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase { StatusBar mStatusBar; @Mock private BroadcastDispatcher mBroadcastDispatcher; + @Mock + private RingerModeTracker mRingerModeTracker; + @Mock + private RingerModeLiveData mRingerModeLiveData; + @Mock + private RingerModeLiveData mRingerModeInternalLiveData; @Before public void setup() throws Exception { MockitoAnnotations.initMocks(this); + when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData); + when(mRingerModeTracker.getRingerModeInternal()).thenReturn(mRingerModeInternalLiveData); + // Initial non-set value + when(mRingerModeLiveData.getValue()).thenReturn(-1); + when(mRingerModeInternalLiveData.getValue()).thenReturn(-1); + mCallback = mock(VolumeDialogControllerImpl.C.class); mStatusBar = mock(StatusBar.class); mVolumeController = new TestableVolumeDialogControllerImpl(mContext, mCallback, mStatusBar, - mBroadcastDispatcher); + mBroadcastDispatcher, mRingerModeTracker); mVolumeController.setEnableDialogs(true, true); } + @After + public void tearDown() { + mVolumeController.destroy(); + } + @Test public void testRegisteredWithDispatcher() { verify(mBroadcastDispatcher).registerReceiverWithHandler(any(BroadcastReceiver.class), @@ -109,7 +131,7 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase { TestableVolumeDialogControllerImpl nullStatusBarTestableDialog = new TestableVolumeDialogControllerImpl( - mContext, callback, null, mBroadcastDispatcher); + mContext, callback, null, mBroadcastDispatcher, mRingerModeTracker); nullStatusBarTestableDialog.setEnableDialogs(true, true); nullStatusBarTestableDialog.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI); verify(callback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED); @@ -127,12 +149,26 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase { mVolumeController.mMediaSessionsCallbacksW.onRemoteRemoved(token); } + @Test + public void testRingerModeLiveDataObserving() { + verify(mRingerModeLiveData).observeForever(any()); + verify(mRingerModeInternalLiveData).observeForever(any()); + } + + @Test + public void testRingerModeOnDestroy_observersRemoved() { + mVolumeController.destroy(); + + verify(mRingerModeLiveData).removeObserver(any()); + verify(mRingerModeInternalLiveData).removeObserver(any()); + } + static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl { TestableVolumeDialogControllerImpl(Context context, C callback, StatusBar s, - BroadcastDispatcher broadcastDispatcher) { + BroadcastDispatcher broadcastDispatcher, RingerModeTracker ringerModeTracker) { super( context, broadcastDispatcher, - s == null ? Optional.empty() : Optional.of(() -> s)); + s == null ? Optional.empty() : Optional.of(() -> s), ringerModeTracker); mCallbacks = callback; } } diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 190b443227ce..5b052df75ede 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -25,7 +25,7 @@ java_defaults { ], static_libs: [ "androidx.annotation_annotation", - "netd_aidl_interface-unstable-java", + "netd_aidl_interface-V3-java", "netlink-client", "networkstack-aidl-interfaces-unstable-java", "android.hardware.tetheroffload.config-V1.0-java", diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml index 9328611f5d3f..1dc8227e81f4 100644 --- a/packages/Tethering/AndroidManifest.xml +++ b/packages/Tethering/AndroidManifest.xml @@ -43,8 +43,9 @@ android:process="com.android.networkstack.process" android:extractNativeLibs="false" android:persistent="true"> - <service android:name="com.android.server.connectivity.tethering.TetheringService" - android:permission="android.permission.MAINLINE_NETWORK_STACK"> + <service android:name="com.android.networkstack.tethering.TetheringService" + android:permission="android.permission.MAINLINE_NETWORK_STACK" + android:exported="true"> <intent-filter> <action android:name="android.net.ITetheringConnector"/> </intent-filter> diff --git a/packages/Tethering/AndroidManifest_InProcess.xml b/packages/Tethering/AndroidManifest_InProcess.xml index 02ea551254b9..b1f124097c79 100644 --- a/packages/Tethering/AndroidManifest_InProcess.xml +++ b/packages/Tethering/AndroidManifest_InProcess.xml @@ -22,9 +22,10 @@ android:process="system"> <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" /> <application> - <service android:name="com.android.server.connectivity.tethering.TetheringService" + <service android:name="com.android.networkstack.tethering.TetheringService" android:process="system" - android:permission="android.permission.MAINLINE_NETWORK_STACK"> + android:permission="android.permission.MAINLINE_NETWORK_STACK" + android:exported="true"> <intent-filter> <action android:name="android.net.ITetheringConnector.InProcess"/> </intent-filter> diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 350980137f3e..cc095a0bb4a7 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -571,9 +571,8 @@ public class TetheringManager { /** * Configure tethering with static IPv4 assignment. * - * The clientAddress must be in the localIPv4Address prefix. A DHCP server will be - * started, but will only be able to offer the client address. The two addresses must - * be in the same prefix. + * A DHCP server will be started, but will only be able to offer the client address. + * The two addresses must be in the same prefix. * * @param localIPv4Address The preferred local IPv4 link address to use. * @param clientAddress The static client address. @@ -584,10 +583,7 @@ public class TetheringManager { @NonNull final LinkAddress clientAddress) { Objects.requireNonNull(localIPv4Address); Objects.requireNonNull(clientAddress); - if (localIPv4Address.getPrefixLength() != clientAddress.getPrefixLength() - || !localIPv4Address.isIpv4() || !clientAddress.isIpv4() - || !new IpPrefix(localIPv4Address.toString()).equals( - new IpPrefix(clientAddress.toString()))) { + if (!checkStaticAddressConfiguration(localIPv4Address, clientAddress)) { throw new IllegalArgumentException("Invalid server or client addresses"); } @@ -657,6 +653,19 @@ public class TetheringManager { } /** + * Check whether the two addresses are ipv4 and in the same prefix. + * @hide + */ + public static boolean checkStaticAddressConfiguration( + @NonNull final LinkAddress localIPv4Address, + @NonNull final LinkAddress clientAddress) { + return localIPv4Address.getPrefixLength() == clientAddress.getPrefixLength() + && localIPv4Address.isIpv4() && clientAddress.isIpv4() + && new IpPrefix(localIPv4Address.toString()).equals( + new IpPrefix(clientAddress.toString())); + } + + /** * Get a TetheringRequestParcel from the configuration * @hide */ diff --git a/packages/Tethering/proguard.flags b/packages/Tethering/proguard.flags index 1f83a663827c..051fbd19fc6c 100644 --- a/packages/Tethering/proguard.flags +++ b/packages/Tethering/proguard.flags @@ -1,5 +1,5 @@ # Keep class's integer static field for MessageUtils to parsing their name. --keep class com.android.server.connectivity.tethering.Tethering$TetherMasterSM { +-keep class com.android.networkstack.tethering.Tethering$TetherMasterSM { static final int CMD_*; static final int EVENT_*; } diff --git a/packages/Tethering/res/values-mcc204-mnc04/strings.xml b/packages/Tethering/res/values-mcc204-mnc04/strings.xml index a996b4247a0e..9dadd49cf8a4 100644 --- a/packages/Tethering/res/values-mcc204-mnc04/strings.xml +++ b/packages/Tethering/res/values-mcc204-mnc04/strings.xml @@ -15,16 +15,16 @@ --> <resources> <!-- String for no upstream notification title [CHAR LIMIT=200] --> - <string name="no_upstream_notification_title">Hotspot has no internet</string> + <string name="no_upstream_notification_title">Tethering has no internet</string> <!-- String for no upstream notification title [CHAR LIMIT=200] --> - <string name="no_upstream_notification_message">Devices can\u2019t connect to internet</string> - <!-- String for cellular roaming notification disable button [CHAR LIMIT=200] --> - <string name="no_upstream_notification_disable_button">Turn off hotspot</string> + <string name="no_upstream_notification_message">Devices can\u2019t connect</string> + <!-- String for no upstream notification disable button [CHAR LIMIT=200] --> + <string name="no_upstream_notification_disable_button">Turn off tethering</string> - <!-- String for cellular roaming notification title [CHAR LIMIT=200] --> - <string name="upstream_roaming_notification_title">Hotspot is on</string> - <!-- String for cellular roaming notification message [CHAR LIMIT=500] --> + <!-- String for cellular roaming notification title [CHAR LIMIT=200] --> + <string name="upstream_roaming_notification_title">Hotspot or tethering is on</string> + <!-- String for cellular roaming notification message [CHAR LIMIT=500] --> <string name="upstream_roaming_notification_message">Additional charges may apply while roaming</string> - <!-- String for cellular roaming notification continue button [CHAR LIMIT=200] --> + <!-- String for cellular roaming notification continue button [CHAR LIMIT=200] --> <string name="upstream_roaming_notification_continue_button">Continue</string> </resources> diff --git a/packages/Tethering/res/values-mcc310-mnc004/strings.xml b/packages/Tethering/res/values-mcc310-mnc004/strings.xml index a996b4247a0e..9dadd49cf8a4 100644 --- a/packages/Tethering/res/values-mcc310-mnc004/strings.xml +++ b/packages/Tethering/res/values-mcc310-mnc004/strings.xml @@ -15,16 +15,16 @@ --> <resources> <!-- String for no upstream notification title [CHAR LIMIT=200] --> - <string name="no_upstream_notification_title">Hotspot has no internet</string> + <string name="no_upstream_notification_title">Tethering has no internet</string> <!-- String for no upstream notification title [CHAR LIMIT=200] --> - <string name="no_upstream_notification_message">Devices can\u2019t connect to internet</string> - <!-- String for cellular roaming notification disable button [CHAR LIMIT=200] --> - <string name="no_upstream_notification_disable_button">Turn off hotspot</string> + <string name="no_upstream_notification_message">Devices can\u2019t connect</string> + <!-- String for no upstream notification disable button [CHAR LIMIT=200] --> + <string name="no_upstream_notification_disable_button">Turn off tethering</string> - <!-- String for cellular roaming notification title [CHAR LIMIT=200] --> - <string name="upstream_roaming_notification_title">Hotspot is on</string> - <!-- String for cellular roaming notification message [CHAR LIMIT=500] --> + <!-- String for cellular roaming notification title [CHAR LIMIT=200] --> + <string name="upstream_roaming_notification_title">Hotspot or tethering is on</string> + <!-- String for cellular roaming notification message [CHAR LIMIT=500] --> <string name="upstream_roaming_notification_message">Additional charges may apply while roaming</string> - <!-- String for cellular roaming notification continue button [CHAR LIMIT=200] --> + <!-- String for cellular roaming notification continue button [CHAR LIMIT=200] --> <string name="upstream_roaming_notification_continue_button">Continue</string> </resources> diff --git a/packages/Tethering/res/values-mcc311-mnc480/strings.xml b/packages/Tethering/res/values-mcc311-mnc480/strings.xml index a996b4247a0e..9dadd49cf8a4 100644 --- a/packages/Tethering/res/values-mcc311-mnc480/strings.xml +++ b/packages/Tethering/res/values-mcc311-mnc480/strings.xml @@ -15,16 +15,16 @@ --> <resources> <!-- String for no upstream notification title [CHAR LIMIT=200] --> - <string name="no_upstream_notification_title">Hotspot has no internet</string> + <string name="no_upstream_notification_title">Tethering has no internet</string> <!-- String for no upstream notification title [CHAR LIMIT=200] --> - <string name="no_upstream_notification_message">Devices can\u2019t connect to internet</string> - <!-- String for cellular roaming notification disable button [CHAR LIMIT=200] --> - <string name="no_upstream_notification_disable_button">Turn off hotspot</string> + <string name="no_upstream_notification_message">Devices can\u2019t connect</string> + <!-- String for no upstream notification disable button [CHAR LIMIT=200] --> + <string name="no_upstream_notification_disable_button">Turn off tethering</string> - <!-- String for cellular roaming notification title [CHAR LIMIT=200] --> - <string name="upstream_roaming_notification_title">Hotspot is on</string> - <!-- String for cellular roaming notification message [CHAR LIMIT=500] --> + <!-- String for cellular roaming notification title [CHAR LIMIT=200] --> + <string name="upstream_roaming_notification_title">Hotspot or tethering is on</string> + <!-- String for cellular roaming notification message [CHAR LIMIT=500] --> <string name="upstream_roaming_notification_message">Additional charges may apply while roaming</string> - <!-- String for cellular roaming notification continue button [CHAR LIMIT=200] --> + <!-- String for cellular roaming notification continue button [CHAR LIMIT=200] --> <string name="upstream_roaming_notification_continue_button">Continue</string> </resources> diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml index 04d6215dce96..430fdc42284d 100644 --- a/packages/Tethering/res/values/config.xml +++ b/packages/Tethering/res/values/config.xml @@ -89,7 +89,7 @@ TYPE_MOBILE_HIPRI is appended. For other changes applied to this list, now and in the future, see - com.android.server.connectivity.tethering.TetheringConfiguration. + com.android.networkstack.tethering.TetheringConfiguration. Note also: the order of this is important. The first upstream type for which a satisfying network exists is used. diff --git a/packages/Tethering/res/values/strings.xml b/packages/Tethering/res/values/strings.xml index 52a16545c22f..4fa60d412566 100644 --- a/packages/Tethering/res/values/strings.xml +++ b/packages/Tethering/res/values/strings.xml @@ -40,13 +40,13 @@ <string name="no_upstream_notification_title"></string> <!-- String for no upstream notification message [CHAR LIMIT=200] --> <string name="no_upstream_notification_message"></string> - <!-- String for cellular roaming notification disable button [CHAR LIMIT=200] --> + <!-- String for no upstream notification disable button [CHAR LIMIT=200] --> <string name="no_upstream_notification_disable_button"></string> - <!-- String for cellular roaming notification title [CHAR LIMIT=200] --> + <!-- String for cellular roaming notification title [CHAR LIMIT=200] --> <string name="upstream_roaming_notification_title"></string> - <!-- String for cellular roaming notification message [CHAR LIMIT=500] --> + <!-- String for cellular roaming notification message [CHAR LIMIT=500] --> <string name="upstream_roaming_notification_message"></string> - <!-- String for cellular roaming notification continue button [CHAR LIMIT=200] --> + <!-- String for cellular roaming notification continue button [CHAR LIMIT=200] --> <string name="upstream_roaming_notification_continue_button"></string> </resources> diff --git a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java index d6bc063210b3..82a26beadacf 100644 --- a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java +++ b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java @@ -18,10 +18,12 @@ package android.net.dhcp; import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; -import android.annotation.NonNull; import android.net.LinkAddress; import android.util.ArraySet; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.net.Inet4Address; import java.util.Collection; import java.util.Collections; @@ -160,6 +162,17 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { return this; } + /** + * Set the client address to tell DHCP server only offer this address. + * The client's prefix length is the same as server's. + * + * <p>If not set, the default value is null. + */ + public DhcpServingParamsParcelExt setSingleClientAddr(@Nullable Inet4Address clientAddr) { + this.clientAddr = clientAddr == null ? 0 : inet4AddressToIntHTH(clientAddr); + return this; + } + private static int[] toIntArray(@NonNull Collection<Inet4Address> addrs) { int[] res = new int[addrs.size()]; int i = 0; diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 5b6fe91b9c1a..83727bcdc67e 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -18,6 +18,7 @@ package android.net.ip; import static android.net.InetAddresses.parseNumericAddress; import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static android.net.util.NetworkConstants.FF; @@ -121,6 +122,8 @@ public class IpServer extends StateMachine { // TODO: have this configurable private static final int DHCP_LEASE_TIME_SECS = 3600; + private static final MacAddress NULL_MAC_ADDRESS = MacAddress.fromString("00:00:00:00:00:00"); + private static final String TAG = "IpServer"; private static final boolean DBG = false; private static final boolean VDBG = false; @@ -511,17 +514,24 @@ public class IpServer extends StateMachine { } } - private boolean startDhcp(Inet4Address addr, int prefixLen) { + private boolean startDhcp(final LinkAddress serverLinkAddr, final LinkAddress clientLinkAddr) { if (mUsingLegacyDhcp) { return true; } + + final Inet4Address addr = (Inet4Address) serverLinkAddr.getAddress(); + final int prefixLen = serverLinkAddr.getPrefixLength(); + final Inet4Address clientAddr = clientLinkAddr == null ? null : + (Inet4Address) clientLinkAddr.getAddress(); + final DhcpServingParamsParcel params; params = new DhcpServingParamsParcelExt() .setDefaultRouters(addr) .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS) .setDnsServers(addr) - .setServerAddr(new LinkAddress(addr, prefixLen)) - .setMetered(true); + .setServerAddr(serverLinkAddr) + .setMetered(true) + .setSingleClientAddr(clientAddr); // TODO: also advertise link MTU mDhcpServerStartIndex++; @@ -556,9 +566,10 @@ public class IpServer extends StateMachine { } } - private boolean configureDhcp(boolean enable, Inet4Address addr, int prefixLen) { + private boolean configureDhcp(boolean enable, final LinkAddress serverAddr, + final LinkAddress clientAddr) { if (enable) { - return startDhcp(addr, prefixLen); + return startDhcp(serverAddr, clientAddr); } else { stopDhcp(); return true; @@ -606,7 +617,7 @@ public class IpServer extends StateMachine { // code that calls into NetworkManagementService directly. srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR); mIpv4Address = new LinkAddress(srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); - return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); + return configureDhcp(enabled, mIpv4Address, null /* clientAddress */); } mIpv4Address = new LinkAddress(srvAddr, prefixLen); } catch (IllegalArgumentException e) { @@ -643,7 +654,7 @@ public class IpServer extends StateMachine { mLinkProperties.removeRoute(route); } - return configureDhcp(enabled, srvAddr, prefixLen); + return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); } private String getRandomWifiIPv4Address() { @@ -893,9 +904,12 @@ public class IpServer extends StateMachine { return; } + // When deleting rules, we still need to pass a non-null MAC, even though it's ignored. + // Do this here instead of in the Ipv6ForwardingRule constructor to ensure that we never + // add rules with a null MAC, only delete them. + MacAddress dstMac = e.isValid() ? e.macAddr : NULL_MAC_ADDRESS; Ipv6ForwardingRule rule = new Ipv6ForwardingRule(upstreamIfindex, - mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr, - e.macAddr); + mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr, dstMac); if (e.isValid()) { addIpv6ForwardingRule(rule); } else { @@ -962,7 +976,14 @@ public class IpServer extends StateMachine { } private void maybeConfigureStaticIp(final TetheringRequestParcel request) { - if (request == null) return; + // Ignore static address configuration if they are invalid or null. In theory, static + // addresses should not be invalid here because TetheringManager do not allow caller to + // specify invalid static address configuration. + if (request == null || request.localIPv4Address == null + || request.staticClientAddress == null || !checkStaticAddressConfiguration( + request.localIPv4Address, request.staticClientAddress)) { + return; + } mStaticIpv4ServerAddr = request.localIPv4Address; mStaticIpv4ClientAddr = request.staticClientAddress; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/ConnectedClientsTracker.java b/packages/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java index cdd1a5d97823..8a96988ae1d1 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/ConnectedClientsTracker.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_WIFI; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java index 639cf65d7936..4c7b2d49ee9a 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; @@ -52,7 +52,6 @@ import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.StateMachine; -import com.android.networkstack.tethering.R; import java.io.PrintWriter; @@ -71,7 +70,7 @@ public class EntitlementManager { @VisibleForTesting protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning"; private static final String ACTION_PROVISIONING_ALARM = - "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM"; + "com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM"; private static final String EXTRA_SUBID = "subId"; private final ComponentName mSilentProvisioningService; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java index 66b9ade81019..d450c46de718 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.net.IpPrefix; import android.net.LinkAddress; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java index 15cdb6ad7a8e..c007c174fe4f 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.METERED_NO; @@ -50,7 +50,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; +import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; import java.net.Inet4Address; import java.net.Inet6Address; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java index b54571720857..85a23fb83fb2 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.util.TetheringUtils.uint16; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java index 4b2c9215f7b7..f3cead92be7e 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.NETWORK_STACK; @@ -60,7 +60,7 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; +import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; import android.app.usage.NetworkStatsManager; import android.bluetooth.BluetoothAdapter; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java index 7e9e26f5af40..aeac437e24e3 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.content.Context.TELEPHONY_SERVICE; import static android.net.ConnectivityManager.TYPE_ETHERNET; @@ -33,7 +33,6 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; -import com.android.networkstack.tethering.R; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index 0330dad6a1ae..893c5823dce1 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.bluetooth.BluetoothAdapter; import android.content.Context; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringInterfaceUtils.java index 4dd68301f9fa..ff38f717a121 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringInterfaceUtils.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.annotation.Nullable; import android.net.LinkProperties; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java index 992cdd8de6a7..42870560cb5e 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_USB; @@ -41,7 +41,6 @@ import androidx.annotation.IntRange; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; -import com.android.networkstack.tethering.R; /** * A class to display tethering-related notifications. diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java index c30be25dbd22..3ed211520db6 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java index 45bb4ab6e5f7..25ddce4404e4 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkState.java b/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java index 68bb83759368..bab9f84cf762 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkState.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import android.net.LinkProperties; import android.net.Network; diff --git a/packages/Tethering/tests/integration/Android.bp b/packages/Tethering/tests/integration/Android.bp index 1a1c30d1d5f9..620261b375d2 100644 --- a/packages/Tethering/tests/integration/Android.bp +++ b/packages/Tethering/tests/integration/Android.bp @@ -39,4 +39,9 @@ android_test { "android.test.base", "android.test.mock", ], + jni_libs: [ + // For mockito extended + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], } diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index dbd68ef77cb7..b02bb23f9807 100644 --- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -205,7 +205,7 @@ public class EthernetTetheringTest { requestWithStaticIpv4(localAddr, clientAddr)); mTetheringEventCallback.awaitInterfaceTethered(); - assertInterfaceHasIpAddress(iface, clientAddr); + assertInterfaceHasIpAddress(iface, localAddr); byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray(); byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray(); diff --git a/packages/Tethering/tests/unit/AndroidManifest.xml b/packages/Tethering/tests/unit/AndroidManifest.xml index 530bc0788a78..55640db69324 100644 --- a/packages/Tethering/tests/unit/AndroidManifest.xml +++ b/packages/Tethering/tests/unit/AndroidManifest.xml @@ -20,7 +20,16 @@ <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> + <service + android:name="com.android.networkstack.tethering.MockTetheringService" + android:permission="android.permission.TETHER_PRIVILEGED" + android:exported="true"> + <intent-filter> + <action android:name="com.android.networkstack.tethering.TetheringService"/> + </intent-filter> + </service> </application> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" android:targetPackage="com.android.networkstack.tethering.tests.unit" android:label="Tethering service tests"> diff --git a/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java b/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java index e8add9830b5f..f8eb1476bad0 100644 --- a/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java +++ b/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java @@ -42,7 +42,9 @@ import java.util.stream.IntStream; @SmallTest public class DhcpServingParamsParcelExtTest { private static final Inet4Address TEST_ADDRESS = inet4Addr("192.168.0.123"); + private static final Inet4Address TEST_CLIENT_ADDRESS = inet4Addr("192.168.0.42"); private static final int TEST_ADDRESS_PARCELED = 0xc0a8007b; + private static final int TEST_CLIENT_ADDRESS_PARCELED = 0xc0a8002a; private static final int TEST_PREFIX_LENGTH = 17; private static final int TEST_LEASE_TIME_SECS = 120; private static final int TEST_MTU = 1000; @@ -105,6 +107,12 @@ public class DhcpServingParamsParcelExtTest { assertFalse(mParcel.metered); } + @Test + public void testSetClientAddr() { + mParcel.setSingleClientAddr(TEST_CLIENT_ADDRESS); + assertEquals(TEST_CLIENT_ADDRESS_PARCELED, mParcel.clientAddr); + } + private static Inet4Address inet4Addr(String addr) { return (Inet4Address) parseNumericAddress(addr); } diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index fdfdae837d51..f9be7b9d3664 100644 --- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -587,6 +587,7 @@ public class IpServerTest { final InetAddress neighB = InetAddresses.parseNumericAddress("2001:db8::2"); final InetAddress neighLL = InetAddresses.parseNumericAddress("fe80::1"); final InetAddress neighMC = InetAddresses.parseNumericAddress("ff02::1234"); + final MacAddress macNull = MacAddress.fromString("00:00:00:00:00:00"); final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a"); final MacAddress macB = MacAddress.fromString("11:22:33:00:00:0b"); @@ -612,13 +613,14 @@ public class IpServerTest { verifyNoMoreInteractions(mNetd); // A neighbor that is no longer valid causes the rule to be removed. - recvNewNeigh(myIfindex, neighA, NUD_FAILED, macA); - verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA)); + // NUD_FAILED events do not have a MAC address. + recvNewNeigh(myIfindex, neighA, NUD_FAILED, null); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macNull)); reset(mNetd); // A neighbor that is deleted causes the rule to be removed. recvDelNeigh(myIfindex, neighB, NUD_STALE, macB); - verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macNull)); reset(mNetd); // Upstream changes result in deleting and re-adding the rules. diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt index 1cdc3bbb9933..d915354b0c37 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/ConnectedClientsTrackerTest.kt +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/ConnectedClientsTrackerTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering +package com.android.networkstack.tethering import android.net.LinkAddress import android.net.MacAddress @@ -159,4 +159,4 @@ class ConnectedClientsTrackerTest { return time } } -}
\ No newline at end of file +} diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java index b3a30abca6f1..8bd0edc2490d 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_ETHERNET; @@ -33,7 +33,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSess import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; @@ -60,7 +59,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; -import com.android.networkstack.tethering.R; import org.junit.After; import org.junit.Before; @@ -72,8 +70,6 @@ import org.mockito.MockitoSession; import org.mockito.quality.Strictness; import java.util.ArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @SmallTest @@ -255,19 +251,16 @@ public final class EntitlementManagerTest { @Test public void testRequestLastEntitlementCacheValue() throws Exception { - final CountDownLatch mCallbacklatch = new CountDownLatch(1); // 1. Entitlement check is not required. mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; ResultReceiver receiver = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_NO_ERROR, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); @@ -277,12 +270,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 3. No cache value and ui entitlement check is needed. @@ -291,12 +282,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_PROVISIONING_FAILED, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(1, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 4. Cache value is TETHER_ERROR_PROVISIONING_FAILED and don't need to run entitlement @@ -306,12 +295,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_PROVISIONING_FAILED, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 5. Cache value is TETHER_ERROR_PROVISIONING_FAILED and ui entitlement check is needed. @@ -320,12 +307,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_NO_ERROR, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(1, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 6. Cache value is TETHER_ERROR_NO_ERROR. @@ -334,12 +319,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_NO_ERROR, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 7. Test get value for other downstream type. @@ -347,12 +330,10 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_USB, receiver, false); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); // 8. Test get value for invalid downstream type. @@ -361,22 +342,14 @@ public final class EntitlementManagerTest { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode); - mCallbacklatch.countDown(); } }; mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI_P2P, receiver, true); mLooper.dispatchAll(); - callbackTimeoutHelper(mCallbacklatch); assertEquals(0, mEnMgr.uiProvisionCount); mEnMgr.reset(); } - void callbackTimeoutHelper(final CountDownLatch latch) throws Exception { - if (!latch.await(1, TimeUnit.SECONDS)) { - fail("Timout, fail to receive callback"); - } - } - @Test public void verifyPermissionResult() { setupForRequiredProvisioning(); diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java new file mode 100644 index 000000000000..820f25514532 --- /dev/null +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/IPv6TetheringCoordinatorTest.java @@ -0,0 +1,156 @@ +/* + * 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.networkstack.tethering; + +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.ip.IpServer.STATE_LOCAL_ONLY; +import static android.net.ip.IpServer.STATE_TETHERED; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.net.InetAddresses; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.RouteInfo; +import android.net.ip.IpServer; +import android.net.util.SharedLog; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IPv6TetheringCoordinatorTest { + private static final String TEST_DNS_SERVER = "2001:4860:4860::8888"; + private static final String TEST_INTERFACE = "test_rmnet0"; + private static final String TEST_IPV6_ADDRESS = "2001:db8::1/64"; + private static final String TEST_IPV4_ADDRESS = "192.168.100.1/24"; + + private IPv6TetheringCoordinator mIPv6TetheringCoordinator; + private ArrayList<IpServer> mNotifyList; + + @Mock private SharedLog mSharedLog; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); + mNotifyList = new ArrayList<IpServer>(); + mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mSharedLog); + } + + private UpstreamNetworkState createDualStackUpstream(final int transportType) { + final Network network = mock(Network.class); + final NetworkCapabilities netCap = + new NetworkCapabilities.Builder().addTransportType(transportType).build(); + final InetAddress dns = InetAddresses.parseNumericAddress(TEST_DNS_SERVER); + final LinkProperties linkProp = new LinkProperties(); + linkProp.setInterfaceName(TEST_INTERFACE); + linkProp.addLinkAddress(new LinkAddress(TEST_IPV6_ADDRESS)); + linkProp.addLinkAddress(new LinkAddress(TEST_IPV4_ADDRESS)); + linkProp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, TEST_INTERFACE, RTN_UNICAST)); + linkProp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, TEST_INTERFACE, + RTN_UNICAST)); + linkProp.addDnsServer(dns); + return new UpstreamNetworkState(linkProp, netCap, network); + } + + private void assertOnlyOneV6AddressAndNoV4(LinkProperties lp) { + assertEquals(lp.getInterfaceName(), TEST_INTERFACE); + assertFalse(lp.hasIpv4Address()); + final List<LinkAddress> addresses = lp.getLinkAddresses(); + assertEquals(addresses.size(), 1); + final LinkAddress v6Address = addresses.get(0); + assertEquals(v6Address, new LinkAddress(TEST_IPV6_ADDRESS)); + } + + @Test + public void testUpdateIpv6Upstream() throws Exception { + // 1. Add first IpServer. + final IpServer firstServer = mock(IpServer.class); + mNotifyList.add(firstServer); + mIPv6TetheringCoordinator.addActiveDownstream(firstServer, STATE_TETHERED); + verify(firstServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null); + verifyNoMoreInteractions(firstServer); + + // 2. Add second IpServer and it would not have ipv6 tethering. + final IpServer secondServer = mock(IpServer.class); + mNotifyList.add(secondServer); + mIPv6TetheringCoordinator.addActiveDownstream(secondServer, STATE_LOCAL_ONLY); + verifyNoMoreInteractions(secondServer); + reset(firstServer, secondServer); + + // 3. No upstream. + mIPv6TetheringCoordinator.updateUpstreamNetworkState(null); + verify(secondServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null); + reset(firstServer, secondServer); + + // 4. Update ipv6 mobile upstream. + final UpstreamNetworkState mobileUpstream = createDualStackUpstream(TRANSPORT_CELLULAR); + final ArgumentCaptor<LinkProperties> lp = ArgumentCaptor.forClass(LinkProperties.class); + mIPv6TetheringCoordinator.updateUpstreamNetworkState(mobileUpstream); + verify(firstServer).sendMessage(eq(IpServer.CMD_IPV6_TETHER_UPDATE), eq(0), eq(0), + lp.capture()); + final LinkProperties v6OnlyLink = lp.getValue(); + assertOnlyOneV6AddressAndNoV4(v6OnlyLink); + verifyNoMoreInteractions(firstServer); + verifyNoMoreInteractions(secondServer); + reset(firstServer, secondServer); + + // 5. Remove first IpServer. + mNotifyList.remove(firstServer); + mIPv6TetheringCoordinator.removeActiveDownstream(firstServer); + verify(firstServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null); + verify(secondServer).sendMessage(eq(IpServer.CMD_IPV6_TETHER_UPDATE), eq(0), eq(0), + lp.capture()); + final LinkProperties localOnlyLink = lp.getValue(); + assertNotNull(localOnlyLink); + assertNotEquals(localOnlyLink, v6OnlyLink); + reset(firstServer, secondServer); + + // 6. Remove second IpServer. + mNotifyList.remove(secondServer); + mIPv6TetheringCoordinator.removeActiveDownstream(secondServer); + verifyNoMoreInteractions(firstServer); + verify(secondServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null); + } +} diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java new file mode 100644 index 000000000000..1c81c1247ded --- /dev/null +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java @@ -0,0 +1,56 @@ +/* + * 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.networkstack.tethering; + +import static org.mockito.Mockito.mock; + +import android.content.Intent; +import android.net.ITetheringConnector; +import android.os.Binder; +import android.os.IBinder; + +public class MockTetheringService extends TetheringService { + private final Tethering mTethering = mock(Tethering.class); + + @Override + public IBinder onBind(Intent intent) { + return new MockTetheringConnector(super.onBind(intent)); + } + + @Override + public Tethering makeTethering(TetheringDependencies deps) { + return mTethering; + } + + public Tethering getTethering() { + return mTethering; + } + + public class MockTetheringConnector extends Binder { + final IBinder mBase; + MockTetheringConnector(IBinder base) { + mBase = base; + } + + public ITetheringConnector getTetheringConnector() { + return ITetheringConnector.Stub.asInterface(mBase); + } + + public MockTetheringService getService() { + return MockTetheringService.this; + } + } +} diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java index fe840864fb99..65797200fa92 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.METERED_NO; @@ -26,9 +26,9 @@ import static android.net.NetworkStats.UID_TETHERING; import static android.net.RouteInfo.RTN_UNICAST; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; -import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_IFACE; -import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_UID; -import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; +import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE; +import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID; +import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; import static com.android.testutils.MiscAssertsKt.assertContainsAll; import static com.android.testutils.MiscAssertsKt.assertThrows; import static com.android.testutils.NetworkStatsUtilsKt.orderInsensitiveEquals; diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java index 3635964dd6a6..07ddea43f4e8 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; @@ -44,7 +44,6 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.test.BroadcastInterceptingContext; -import com.android.networkstack.tethering.R; import org.junit.After; import org.junit.Before; diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index b86949185c69..7bff74b25d94 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering +package com.android.networkstack.tethering import android.app.Notification import android.app.NotificationManager @@ -29,8 +29,7 @@ import androidx.test.platform.app.InstrumentationRegistry import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.test.BroadcastInterceptingContext -import com.android.networkstack.tethering.R -import com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE +import com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test @@ -259,4 +258,4 @@ class TetheringNotificationUpdaterTest { notificationUpdater.notifyTetheringDisabledByRestriction() verifyNotification(R.drawable.stat_sys_tether_general, disallowTitle, disallowMessage) } -}
\ No newline at end of file +} diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java new file mode 100644 index 000000000000..51bad9af23ef --- /dev/null +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java @@ -0,0 +1,194 @@ +/* + * 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.networkstack.tethering; + +import static android.net.TetheringManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.content.Intent; +import android.net.IIntResultListener; +import android.net.ITetheringConnector; +import android.net.ITetheringEventCallback; +import android.net.TetheringRequestParcel; +import android.os.ResultReceiver; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.rule.ServiceTestRule; +import androidx.test.runner.AndroidJUnit4; + +import com.android.networkstack.tethering.MockTetheringService.MockTetheringConnector; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public final class TetheringServiceTest { + private static final String TEST_IFACE_NAME = "test_wlan0"; + private static final String TEST_CALLER_PKG = "test_pkg"; + @Mock private ITetheringEventCallback mITetheringEventCallback; + @Rule public ServiceTestRule mServiceTestRule; + private Tethering mTethering; + private Intent mMockServiceIntent; + private ITetheringConnector mTetheringConnector; + + private class TestTetheringResult extends IIntResultListener.Stub { + private int mResult = -1; // Default value that does not match any result code. + @Override + public void onResult(final int resultCode) { + mResult = resultCode; + } + + public void assertResult(final int expected) { + assertEquals(expected, mResult); + } + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mServiceTestRule = new ServiceTestRule(); + mMockServiceIntent = new Intent( + InstrumentationRegistry.getTargetContext(), + MockTetheringService.class); + final MockTetheringConnector mockConnector = + (MockTetheringConnector) mServiceTestRule.bindService(mMockServiceIntent); + mTetheringConnector = mockConnector.getTetheringConnector(); + final MockTetheringService service = mockConnector.getService(); + mTethering = service.getTethering(); + verify(mTethering).startStateMachineUpdaters(); + when(mTethering.hasTetherableConfiguration()).thenReturn(true); + } + + @After + public void tearDown() throws Exception { + mServiceTestRule.unbindService(); + } + + @Test + public void testTether() throws Exception { + when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).tether(TEST_IFACE_NAME); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } + + @Test + public void testUntether() throws Exception { + when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).untether(TEST_IFACE_NAME); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } + + @Test + public void testSetUsbTethering() throws Exception { + when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR); + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).setUsbTethering(true /* enable */); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } + + @Test + public void testStartTethering() throws Exception { + final TestTetheringResult result = new TestTetheringResult(); + final TetheringRequestParcel request = new TetheringRequestParcel(); + request.tetheringType = TETHERING_WIFI; + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).startTethering(eq(request), eq(result)); + verifyNoMoreInteractions(mTethering); + } + + @Test + public void testStopTethering() throws Exception { + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).stopTethering(TETHERING_WIFI); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } + + @Test + public void testRequestLatestTetheringEntitlementResult() throws Exception { + final ResultReceiver result = new ResultReceiver(null); + mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, + true /* showEntitlementUi */, TEST_CALLER_PKG); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI), + eq(result), eq(true) /* showEntitlementUi */); + verifyNoMoreInteractions(mTethering); + } + + @Test + public void testRegisterTetheringEventCallback() throws Exception { + mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback, + TEST_CALLER_PKG); + verify(mTethering).registerTetheringEventCallback(eq(mITetheringEventCallback)); + verifyNoMoreInteractions(mTethering); + } + + @Test + public void testUnregisterTetheringEventCallback() throws Exception { + mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback, + TEST_CALLER_PKG); + verify(mTethering).unregisterTetheringEventCallback( + eq(mITetheringEventCallback)); + verifyNoMoreInteractions(mTethering); + } + + @Test + public void testStopAllTethering() throws Exception { + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verify(mTethering).untetherAll(); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } + + @Test + public void testIsTetheringSupported() throws Exception { + final TestTetheringResult result = new TestTetheringResult(); + mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, result); + verify(mTethering).hasTetherableConfiguration(); + verifyNoMoreInteractions(mTethering); + result.assertResult(TETHER_ERROR_NO_ERROR); + } +} diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index a59c6fd9e193..d4be3a26d958 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; @@ -38,6 +38,7 @@ import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; @@ -46,7 +47,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; +import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -136,11 +137,12 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; -import com.android.networkstack.tethering.R; import com.android.testutils.MiscAssertsKt; 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.ArgumentCaptor; @@ -439,6 +441,18 @@ public class TetheringTest { return buildMobileUpstreamState(false, true, true); } + // See FakeSettingsProvider#clearSettingsProvider() that this needs to be called before and + // after use. + @BeforeClass + public static void setupOnce() { + FakeSettingsProvider.clearSettingsProvider(); + } + + @AfterClass + public static void tearDownOnce() { + FakeSettingsProvider.clearSettingsProvider(); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -1654,10 +1668,13 @@ public class TetheringTest { } @Test - public void testRequestStaticServerIp() throws Exception { - final LinkAddress serverLinkAddr = new LinkAddress("192.168.20.1/24"); - final LinkAddress clientLinkAddr = new LinkAddress("192.168.20.42/24"); - final String serverAddr = "192.168.20.1"; + public void testRequestStaticIp() throws Exception { + final LinkAddress serverLinkAddr = new LinkAddress("192.168.0.123/24"); + final LinkAddress clientLinkAddr = new LinkAddress("192.168.0.42/24"); + final String serverAddr = "192.168.0.123"; + final int clientAddrParceled = 0xc0a8002a; + final ArgumentCaptor<DhcpServingParamsParcel> dhcpParamsCaptor = + ArgumentCaptor.forClass(DhcpServingParamsParcel.class); mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB, serverLinkAddr, clientLinkAddr), null); mLooper.dispatchAll(); @@ -1666,8 +1683,12 @@ public class TetheringTest { sendUsbBroadcast(true, true, true, TETHERING_USB); mLooper.dispatchAll(); verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr))); - - // TODO: test static client address. + verify(mIpServerDependencies, times(1)).makeDhcpServer(any(), dhcpParamsCaptor.capture(), + any()); + final DhcpServingParamsParcel params = dhcpParamsCaptor.getValue(); + assertEquals(serverAddr, intToInet4AddressHTH(params.serverAddr).getHostAddress()); + assertEquals(24, params.serverAddrPrefixLength); + assertEquals(clientAddrParceled, params.clientAddr); } // TODO: Test that a request for hotspot mode doesn't interfere with an diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java index 7c98f626a4d2..232588c7eec0 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/UpstreamNetworkMonitorTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.tethering; +package com.android.networkstack.tethering; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; @@ -24,7 +24,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; -import static com.android.server.connectivity.tethering.UpstreamNetworkMonitor.TYPE_NONE; +import static com.android.networkstack.tethering.UpstreamNetworkMonitor.TYPE_NONE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/packages/VpnDialogs/res/values-my/strings.xml b/packages/VpnDialogs/res/values-my/strings.xml index 9d60ff42a7cd..a949fae1f74e 100644 --- a/packages/VpnDialogs/res/values-my/strings.xml +++ b/packages/VpnDialogs/res/values-my/strings.xml @@ -30,7 +30,7 @@ <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string> <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ဆက်တင်များ ပြောင်းရန်"</string> <string name="configure" msgid="4905518375574791375">"ပုံပေါ်စေသည်"</string> - <string name="disconnect" msgid="971412338304200056">"ချိတ်ဆက်ခြင်းရပ်ရန်"</string> + <string name="disconnect" msgid="971412338304200056">"ချိတ်ဆက်မှုဖြုတ်ရန်"</string> <string name="open_app" msgid="3717639178595958667">"အက်ပ်ကို ဖွင့်ရန်"</string> <string name="dismiss" msgid="6192859333764711227">"ပယ်ရန်"</string> </resources> diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java index 93bffe9f54e4..52a82dd2a156 100644 --- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java +++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java @@ -36,10 +36,12 @@ import android.os.FileUtils; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.UserHandle; +import android.provider.Settings; import android.util.Slog; import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.content.PackageMonitor; import libcore.io.IoUtils; @@ -261,22 +263,7 @@ public class WallpaperBackupAgent extends BackupAgent { // And reset to the wallpaper service we should be using ComponentName wpService = parseWallpaperComponent(infoStage, "wp"); - if (servicePackageExists(wpService)) { - Slog.i(TAG, "Using wallpaper service " + wpService); - mWm.setWallpaperComponent(wpService, UserHandle.USER_SYSTEM); - if (!lockImageStage.exists()) { - // We have a live wallpaper and no static lock image, - // allow live wallpaper to show "through" on lock screen. - mWm.clear(FLAG_LOCK); - } - } else { - // If we've restored a live wallpaper, but the component doesn't exist, - // we should log it as an error so we can easily identify the problem - // in reports from users - if (wpService != null) { - Slog.e(TAG, "Wallpaper service " + wpService + " isn't available."); - } - } + updateWallpaperComponent(wpService, !lockImageStage.exists()); } catch (Exception e) { Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage()); } finally { @@ -293,6 +280,28 @@ public class WallpaperBackupAgent extends BackupAgent { } } + @VisibleForTesting + void updateWallpaperComponent(ComponentName wpService, boolean applyToLock) throws IOException { + if (servicePackageExists(wpService)) { + Slog.i(TAG, "Using wallpaper service " + wpService); + mWm.setWallpaperComponent(wpService, UserHandle.USER_SYSTEM); + if (applyToLock) { + // We have a live wallpaper and no static lock image, + // allow live wallpaper to show "through" on lock screen. + mWm.clear(FLAG_LOCK); + } + } else { + // If we've restored a live wallpaper, but the component doesn't exist, + // we should log it as an error so we can easily identify the problem + // in reports from users + if (wpService != null) { + applyComponentAtInstall(wpService, applyToLock); + Slog.w(TAG, "Wallpaper service " + wpService + " isn't available. " + + " Will try to apply later"); + } + } + } + private void restoreFromStage(File stage, File info, String hintTag, int which) throws IOException { if (stage.exists()) { @@ -372,7 +381,8 @@ public class WallpaperBackupAgent extends BackupAgent { return (value == null) ? defValue : Integer.parseInt(value); } - private boolean servicePackageExists(ComponentName comp) { + @VisibleForTesting + boolean servicePackageExists(ComponentName comp) { try { if (comp != null) { final IPackageManager pm = AppGlobals.getPackageManager(); @@ -401,4 +411,53 @@ public class WallpaperBackupAgent extends BackupAgent { throws IOException { // Intentionally blank } + + private void applyComponentAtInstall(ComponentName componentName, boolean applyToLock) { + PackageMonitor packageMonitor = getWallpaperPackageMonitor(componentName, applyToLock); + packageMonitor.register(getBaseContext(), null, UserHandle.ALL, true); + } + + @VisibleForTesting + PackageMonitor getWallpaperPackageMonitor(ComponentName componentName, boolean applyToLock) { + return new PackageMonitor() { + @Override + public void onPackageAdded(String packageName, int uid) { + if (!isDeviceInRestore()) { + // We don't want to reapply the wallpaper outside a restore. + unregister(); + return; + } + + if (componentName.getPackageName().equals(packageName)) { + Slog.d(TAG, "Applying component " + componentName); + mWm.setWallpaperComponent(componentName); + if (applyToLock) { + try { + mWm.clear(FLAG_LOCK); + } catch (IOException e) { + Slog.w(TAG, "Failed to apply live wallpaper to lock screen: " + e); + } + } + // We're only expecting to restore the wallpaper component once. + unregister(); + } + } + }; + } + + @VisibleForTesting + boolean isDeviceInRestore() { + try { + boolean isInSetup = Settings.Secure.getInt(getBaseContext().getContentResolver(), + Settings.Secure.USER_SETUP_COMPLETE) == 0; + boolean isInDeferredSetup = Settings.Secure.getInt(getBaseContext() + .getContentResolver(), + Settings.Secure.USER_SETUP_PERSONALIZATION_STATE) == + Settings.Secure.USER_SETUP_PERSONALIZATION_STARTED; + return isInSetup || isInDeferredSetup; + } catch (Settings.SettingNotFoundException e) { + Slog.w(TAG, "Failed to check if the user is in restore: " + e); + return false; + } + } }
\ No newline at end of file diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java index 255fdef36cd7..4367075abc74 100644 --- a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java +++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wallpaperbackup.tests; +package com.android.wallpaperbackup; import static android.app.WallpaperManager.FLAG_LOCK; import static android.app.WallpaperManager.FLAG_SYSTEM; @@ -26,17 +26,22 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.inOrder; +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.WallpaperManager; import android.app.backup.FullBackupDataOutput; +import android.content.ComponentName; +import android.content.Context; import android.content.SharedPreferences; import android.os.UserHandle; import androidx.test.core.app.ApplicationProvider; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.content.PackageMonitor; import com.android.wallpaperbackup.WallpaperBackupAgent; import com.android.wallpaperbackup.utils.ContextWithServiceOverrides; @@ -58,6 +63,7 @@ import java.util.List; public class WallpaperBackupAgentTest { private static final String SYSTEM_GENERATION = "system_gen"; private static final String LOCK_GENERATION = "lock_gen"; + private static final String TEST_WALLPAPER_PACKAGE = "wallpaper_package"; private static final int TEST_SYSTEM_WALLPAPER_ID = 1; private static final int TEST_LOCK_WALLPAPER_ID = 2; @@ -66,11 +72,13 @@ public class WallpaperBackupAgentTest { @Mock private WallpaperManager mWallpaperManager; @Mock private SharedPreferences mSharedPreferences; @Mock private SharedPreferences.Editor mSharedPreferenceEditor; + @Mock private Context mMockContext; @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); private ContextWithServiceOverrides mContext; private IsolatedWallpaperBackupAgent mWallpaperBackupAgent; + private ComponentName mWallpaperComponent; @Before public void setUp() { @@ -88,6 +96,8 @@ public class WallpaperBackupAgentTest { mWallpaperBackupAgent = new IsolatedWallpaperBackupAgent(mTemporaryFolder.getRoot()); mWallpaperBackupAgent.attach(mContext); mWallpaperBackupAgent.onCreate(); + + mWallpaperComponent = new ComponentName(TEST_WALLPAPER_PACKAGE, ""); } @Test @@ -130,6 +140,69 @@ public class WallpaperBackupAgentTest { inOrder.verify(mSharedPreferenceEditor).apply(); } + @Test + public void updateWallpaperComponent_doesApplyLater() throws IOException { + mWallpaperBackupAgent.mIsDeviceInRestore = true; + + mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent, + /* applyToLock */ true); + + // Imitate wallpaper component installation. + mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE, + /* uid */0); + + verify(mWallpaperManager, times(1)).setWallpaperComponent(mWallpaperComponent); + verify(mWallpaperManager, times(1)).clear(eq(FLAG_LOCK)); + } + + @Test + public void updateWallpaperComponent_applyToLockFalse_doesApplyLaterOnlyToMainScreen() + throws IOException { + mWallpaperBackupAgent.mIsDeviceInRestore = true; + + mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent, + /* applyToLock */ false); + + // Imitate wallpaper component installation. + mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE, + /* uid */0); + + verify(mWallpaperManager, times(1)).setWallpaperComponent(mWallpaperComponent); + verify(mWallpaperManager, never()).clear(eq(FLAG_LOCK)); + } + + @Test + public void updateWallpaperComponent_deviceNotInRestore_doesNotApply() + throws IOException { + mWallpaperBackupAgent.mIsDeviceInRestore = false; + + mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent, + /* applyToLock */ true); + + // Imitate wallpaper component installation. + mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(TEST_WALLPAPER_PACKAGE, + /* uid */0); + + verify(mWallpaperManager, never()).setWallpaperComponent(mWallpaperComponent); + verify(mWallpaperManager, never()).clear(eq(FLAG_LOCK)); + } + + @Test + public void updateWallpaperComponent_differentPackageInstalled_doesNotApply() + throws IOException { + mWallpaperBackupAgent.mIsDeviceInRestore = false; + + mWallpaperBackupAgent.updateWallpaperComponent(mWallpaperComponent, + /* applyToLock */ true); + + // Imitate "wrong" wallpaper component installation. + mWallpaperBackupAgent.mWallpaperPackageMonitor.onPackageAdded(/* packageName */"", + /* uid */0); + + verify(mWallpaperManager, never()).setWallpaperComponent(mWallpaperComponent); + verify(mWallpaperManager, never()).clear(eq(FLAG_LOCK)); + } + private void mockUnbackedUpState() { mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID); when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(-1); @@ -162,6 +235,8 @@ public class WallpaperBackupAgentTest { private class IsolatedWallpaperBackupAgent extends WallpaperBackupAgent { File mWallpaperBaseDirectory; List<File> mBackedUpFiles = new ArrayList<>(); + PackageMonitor mWallpaperPackageMonitor; + boolean mIsDeviceInRestore = false; IsolatedWallpaperBackupAgent(File wallpaperBaseDirectory) { mWallpaperBaseDirectory = wallpaperBaseDirectory; @@ -181,5 +256,27 @@ public class WallpaperBackupAgentTest { public SharedPreferences getSharedPreferences(File file, int mode) { return mSharedPreferences; } + + @Override + boolean servicePackageExists(ComponentName comp) { + return false; + } + + @Override + boolean isDeviceInRestore() { + return mIsDeviceInRestore; + } + + @Override + PackageMonitor getWallpaperPackageMonitor(ComponentName componentName, + boolean applyToLock) { + mWallpaperPackageMonitor = super.getWallpaperPackageMonitor(componentName, applyToLock); + return mWallpaperPackageMonitor; + } + + @Override + public Context getBaseContext() { + return mMockContext; + } } } diff --git a/proto/src/typed_features.proto b/proto/src/typed_features.proto new file mode 100644 index 000000000000..c2b3b18ea7c8 --- /dev/null +++ b/proto/src/typed_features.proto @@ -0,0 +1,25 @@ +/* + * 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. + */ + +syntax = "proto2"; + +package com.android.service; +option java_multiple_files = true; + +// This message is to specify feature params that are a list of strings. +message StringListParamProto { + repeated string element = 1; +}
\ No newline at end of file diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 2100c1a8be44..7230b00f87ad 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -413,7 +413,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub && component.getPackageName().equals(packageName)) || userState.mCrashedServices.removeIf(component -> component != null && component.getPackageName().equals(packageName)); - if (reboundAService) { + // Reloads the installed services info to make sure the rebound service could + // get a new one. + userState.mInstalledServices.clear(); + final boolean configurationChanged = + readConfigurationForUserStateLocked(userState); + if (reboundAService || configurationChanged) { onUserStateChangedLocked(userState); } migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, packageName); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java index ff59c24a7ca2..20a11bd9acd3 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityShellCommand.java @@ -17,6 +17,7 @@ package com.android.server.accessibility; import android.annotation.NonNull; +import android.app.ActivityManager; import android.os.ShellCommand; import android.os.UserHandle; @@ -83,7 +84,7 @@ final class AccessibilityShellCommand extends ShellCommand { return null; } } - return UserHandle.USER_SYSTEM; + return ActivityManager.getCurrentUser(); } @Override diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 8c1360cca940..ca1b27bd261e 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -3669,6 +3669,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // Default launcher from package manager. final ComponentName defaultLauncher = mPackageManagerInternal .getDefaultHomeActivity(UserHandle.getUserId(callingUid)); + if (defaultLauncher == null) { + return; + } int defaultLauncherUid = 0; try { defaultLauncherUid = mPackageManager.getApplicationInfo( diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java new file mode 100644 index 000000000000..3612e093c8bd --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java @@ -0,0 +1,131 @@ +/* + * 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.server.autofill; + +import android.annotation.NonNull; +import android.content.ComponentName; +import android.os.Bundle; +import android.os.Handler; +import android.view.autofill.AutofillId; +import android.view.inputmethod.InlineSuggestionsRequest; +import android.view.inputmethod.InlineSuggestionsResponse; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.inputmethod.InputMethodManagerInternal; + +import java.util.Collections; +import java.util.Optional; +import java.util.function.Consumer; + + +/** + * Controls the interaction with the IME for the inline suggestion sessions. + */ +final class AutofillInlineSessionController { + @NonNull + private final InputMethodManagerInternal mInputMethodManagerInternal; + private final int mUserId; + @NonNull + private final ComponentName mComponentName; + @NonNull + private final Object mLock; + @NonNull + private final Handler mHandler; + + @GuardedBy("mLock") + private AutofillInlineSuggestionsRequestSession mSession; + + AutofillInlineSessionController(InputMethodManagerInternal inputMethodManagerInternal, + int userId, ComponentName componentName, Handler handler, Object lock) { + mInputMethodManagerInternal = inputMethodManagerInternal; + mUserId = userId; + mComponentName = componentName; + mHandler = handler; + mLock = lock; + } + + + /** + * Requests the IME to create an {@link InlineSuggestionsRequest} for {@code autofillId}. + * + * @param autofillId the Id of the field for which the request is for. + * @param requestConsumer the callback which will be invoked when IME responded or if it times + * out waiting for IME response. + */ + @GuardedBy("mLock") + void onCreateInlineSuggestionsRequestLocked(@NonNull AutofillId autofillId, + @NonNull Consumer<InlineSuggestionsRequest> requestConsumer, @NonNull Bundle uiExtras) { + // TODO(b/151123764): rename the method to better reflect what it does. + if (mSession != null) { + // Send an empty response to IME and destroy the existing session. + mSession.onInlineSuggestionsResponseLocked(mSession.getAutofillIdLocked(), + new InlineSuggestionsResponse(Collections.EMPTY_LIST)); + mSession.destroySessionLocked(); + } + // TODO(b/151123764): consider reusing the same AutofillInlineSession object for the + // same field. + mSession = new AutofillInlineSuggestionsRequestSession(mInputMethodManagerInternal, mUserId, + mComponentName, mHandler, mLock, autofillId, requestConsumer, uiExtras); + mSession.onCreateInlineSuggestionsRequestLocked(); + + } + + /** + * Returns the {@link InlineSuggestionsRequest} provided by IME for the last request. + * + * <p> The caller is responsible for making sure Autofill hears back from IME before calling + * this method, using the {@code requestConsumer} provided when calling {@link + * #onCreateInlineSuggestionsRequestLocked(AutofillId, Consumer, Bundle)}. + */ + @GuardedBy("mLock") + Optional<InlineSuggestionsRequest> getInlineSuggestionsRequestLocked() { + if (mSession != null) { + return mSession.getInlineSuggestionsRequestLocked(); + } + return Optional.empty(); + } + + /** + * Requests the IME to hide the current suggestions, if any. Returns true if the message is sent + * to the IME. + */ + @GuardedBy("mLock") + boolean hideInlineSuggestionsUiLocked(@NonNull AutofillId autofillId) { + if (mSession != null) { + return mSession.onInlineSuggestionsResponseLocked(autofillId, + new InlineSuggestionsResponse(Collections.EMPTY_LIST)); + } + return false; + } + + /** + * Requests showing the inline suggestion in the IME when the IME becomes visible and is focused + * on the {@code autofillId}. + * + * @return false if there is no session, or if the IME callback is not available in the session. + */ + @GuardedBy("mLock") + boolean onInlineSuggestionsResponseLocked(@NonNull AutofillId autofillId, + @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) { + // TODO(b/151123764): rename the method to better reflect what it does. + if (mSession != null) { + return mSession.onInlineSuggestionsResponseLocked(autofillId, + inlineSuggestionsResponse); + } + return false; + } +} diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java new file mode 100644 index 000000000000..ea4aaa43ea65 --- /dev/null +++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java @@ -0,0 +1,414 @@ +/* + * 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.server.autofill; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; +import static com.android.server.autofill.Helper.sDebug; + +import android.annotation.BinderThread; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.os.Bundle; +import android.os.Handler; +import android.os.RemoteException; +import android.util.Log; +import android.util.Slog; +import android.view.autofill.AutofillId; +import android.view.inputmethod.InlineSuggestionsRequest; +import android.view.inputmethod.InlineSuggestionsResponse; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.view.IInlineSuggestionsRequestCallback; +import com.android.internal.view.IInlineSuggestionsResponseCallback; +import com.android.internal.view.InlineSuggestionsRequestInfo; +import com.android.server.inputmethod.InputMethodManagerInternal; + +import java.lang.ref.WeakReference; +import java.util.Collections; +import java.util.Optional; +import java.util.function.Consumer; + +/** + * Maintains an inline suggestion session with the IME. + * + * <p> Each session corresponds to one request from the Autofill manager service to create an + * {@link InlineSuggestionsRequest}. It's responsible for receiving callbacks from the IME and + * sending {@link android.view.inputmethod.InlineSuggestionsResponse} to IME. + */ +final class AutofillInlineSuggestionsRequestSession { + + private static final String TAG = AutofillInlineSuggestionsRequestSession.class.getSimpleName(); + private static final int INLINE_REQUEST_TIMEOUT_MS = 200; + + @NonNull + private final InputMethodManagerInternal mInputMethodManagerInternal; + private final int mUserId; + @NonNull + private final ComponentName mComponentName; + @NonNull + private final Object mLock; + @NonNull + private final Handler mHandler; + @NonNull + private final Bundle mUiExtras; + + @GuardedBy("mLock") + @NonNull + private AutofillId mAutofillId; + @GuardedBy("mLock") + @Nullable + private Consumer<InlineSuggestionsRequest> mImeRequestConsumer; + + @GuardedBy("mLock") + private boolean mImeRequestReceived; + @GuardedBy("mLock") + @Nullable + private InlineSuggestionsRequest mImeRequest; + @GuardedBy("mLock") + @Nullable + private IInlineSuggestionsResponseCallback mResponseCallback; + @GuardedBy("mLock") + @Nullable + private Runnable mTimeoutCallback; + + @GuardedBy("mLock") + @Nullable + private AutofillId mImeCurrentFieldId; + @GuardedBy("mLock") + private boolean mImeInputStarted; + @GuardedBy("mLock") + private boolean mImeInputViewStarted; + @GuardedBy("mLock") + @Nullable + private InlineSuggestionsResponse mInlineSuggestionsResponse; + @GuardedBy("mLock") + private boolean mPreviousResponseIsNotEmpty; + + @GuardedBy("mLock") + private boolean mDestroyed = false; + + AutofillInlineSuggestionsRequestSession( + @NonNull InputMethodManagerInternal inputMethodManagerInternal, int userId, + @NonNull ComponentName componentName, @NonNull Handler handler, @NonNull Object lock, + @NonNull AutofillId autofillId, + @NonNull Consumer<InlineSuggestionsRequest> requestConsumer, @NonNull Bundle uiExtras) { + mInputMethodManagerInternal = inputMethodManagerInternal; + mUserId = userId; + mComponentName = componentName; + mHandler = handler; + mLock = lock; + mUiExtras = uiExtras; + + mAutofillId = autofillId; + mImeRequestConsumer = requestConsumer; + } + + @GuardedBy("mLock") + @NonNull + AutofillId getAutofillIdLocked() { + return mAutofillId; + } + + /** + * Returns the {@link InlineSuggestionsRequest} provided by IME. + * + * <p> The caller is responsible for making sure Autofill hears back from IME before calling + * this method, using the {@link #mImeRequestConsumer}. + */ + @GuardedBy("mLock") + Optional<InlineSuggestionsRequest> getInlineSuggestionsRequestLocked() { + if (mDestroyed) { + return Optional.empty(); + } + return Optional.ofNullable(mImeRequest); + } + + /** + * Requests showing the inline suggestion in the IME when the IME becomes visible and is focused + * on the {@code autofillId}. + * + * @return false if the IME callback is not available. + */ + @GuardedBy("mLock") + boolean onInlineSuggestionsResponseLocked(@NonNull AutofillId autofillId, + @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) { + if (mDestroyed) { + return false; + } + if (sDebug) Log.d(TAG, "onInlineSuggestionsResponseLocked called for:" + autofillId); + if (mImeRequest == null || mResponseCallback == null) { + return false; + } + // TODO(b/151123764): each session should only correspond to one field. + mAutofillId = autofillId; + mInlineSuggestionsResponse = inlineSuggestionsResponse; + maybeUpdateResponseToImeLocked(); + return true; + } + + /** + * This method must be called when the session is destroyed, to avoid further callbacks from/to + * the IME. + */ + @GuardedBy("mLock") + void destroySessionLocked() { + mDestroyed = true; + } + + /** + * Requests the IME to create an {@link InlineSuggestionsRequest}. + * + * <p> This method should only be called once per session. + */ + @GuardedBy("mLock") + void onCreateInlineSuggestionsRequestLocked() { + if (sDebug) Log.d(TAG, "onCreateInlineSuggestionsRequestLocked called: " + mAutofillId); + if (mDestroyed) { + return; + } + mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(mUserId, + new InlineSuggestionsRequestInfo(mComponentName, mAutofillId, mUiExtras), + new InlineSuggestionsRequestCallbackImpl(this)); + mTimeoutCallback = () -> { + Log.w(TAG, "Timed out waiting for IME callback InlineSuggestionsRequest."); + handleOnReceiveImeRequest(null, null); + }; + mHandler.postDelayed(mTimeoutCallback, INLINE_REQUEST_TIMEOUT_MS); + } + + /** + * Optionally sends inline response to the IME, depending on the current state. + */ + @GuardedBy("mLock") + private void maybeUpdateResponseToImeLocked() { + if (sDebug) Log.d(TAG, "maybeUpdateResponseToImeLocked called"); + if (mDestroyed || mResponseCallback == null) { + return; + } + if (!mImeInputViewStarted && mPreviousResponseIsNotEmpty) { + // 1. if previous response is not empty, and IME just become invisible, then send + // empty response to make sure existing responses don't stick around on the IME. + // Although the inline suggestions should disappear when IME hides which removes them + // from the view hierarchy, but we still send an empty response to be extra safe. + + if (sDebug) Log.d(TAG, "Send empty inline response"); + updateResponseToImeUncheckLocked(new InlineSuggestionsResponse(Collections.EMPTY_LIST)); + mPreviousResponseIsNotEmpty = false; + } else if (mImeInputViewStarted && mInlineSuggestionsResponse != null && match(mAutofillId, + mImeCurrentFieldId)) { + // 2. if IME is visible, and response is not null, send the response + boolean isEmptyResponse = mInlineSuggestionsResponse.getInlineSuggestions().isEmpty(); + if (isEmptyResponse && !mPreviousResponseIsNotEmpty) { + // No-op if both the previous response and current response are empty. + return; + } + if (sDebug) { + Log.d(TAG, "Send inline response: " + + mInlineSuggestionsResponse.getInlineSuggestions().size()); + } + updateResponseToImeUncheckLocked(mInlineSuggestionsResponse); + mPreviousResponseIsNotEmpty = !isEmptyResponse; + } + } + + /** + * Sends the {@code response} to the IME, assuming all the relevant checks are already done. + */ + @GuardedBy("mLock") + private void updateResponseToImeUncheckLocked(InlineSuggestionsResponse response) { + if (mDestroyed) { + return; + } + try { + mResponseCallback.onInlineSuggestionsResponse(mAutofillId, response); + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException sending InlineSuggestionsResponse to IME"); + } + } + + /** + * Handles the {@code request} and {@code callback} received from the IME. + * + * <p> Should only invoked in the {@link #mHandler} thread. + */ + private void handleOnReceiveImeRequest(@Nullable InlineSuggestionsRequest request, + @Nullable IInlineSuggestionsResponseCallback callback) { + synchronized (mLock) { + if (mDestroyed || mImeRequestReceived) { + return; + } + mImeRequestReceived = true; + + if (mTimeoutCallback != null) { + if (sDebug) Log.d(TAG, "removing timeout callback"); + mHandler.removeCallbacks(mTimeoutCallback); + mTimeoutCallback = null; + } + if (request != null && callback != null) { + mImeRequest = request; + mResponseCallback = callback; + handleOnReceiveImeStatusUpdated(mAutofillId, true, false); + } + if (mImeRequestConsumer != null) { + // Note that mImeRequest is only set if both request and callback are non-null. + mImeRequestConsumer.accept(mImeRequest); + mImeRequestConsumer = null; + } + } + } + + /** + * Handles the IME status updates received from the IME. + * + * <p> Should only be invoked in the {@link #mHandler} thread. + */ + private void handleOnReceiveImeStatusUpdated(boolean imeInputStarted, + boolean imeInputViewStarted) { + synchronized (mLock) { + if (mDestroyed) { + return; + } + if (mImeCurrentFieldId != null) { + boolean imeInputStartedChanged = (mImeInputStarted != imeInputStarted); + boolean imeInputViewStartedChanged = (mImeInputViewStarted != imeInputViewStarted); + mImeInputStarted = imeInputStarted; + mImeInputViewStarted = imeInputViewStarted; + if (imeInputStartedChanged || imeInputViewStartedChanged) { + maybeUpdateResponseToImeLocked(); + } + } + } + } + + /** + * Handles the IME status updates received from the IME. + * + * <p> Should only be invoked in the {@link #mHandler} thread. + */ + private void handleOnReceiveImeStatusUpdated(@Nullable AutofillId imeFieldId, + boolean imeInputStarted, boolean imeInputViewStarted) { + synchronized (mLock) { + if (mDestroyed) { + return; + } + if (imeFieldId != null) { + mImeCurrentFieldId = imeFieldId; + } + handleOnReceiveImeStatusUpdated(imeInputStarted, imeInputViewStarted); + } + } + + private static final class InlineSuggestionsRequestCallbackImpl extends + IInlineSuggestionsRequestCallback.Stub { + + private final WeakReference<AutofillInlineSuggestionsRequestSession> mSession; + + private InlineSuggestionsRequestCallbackImpl( + AutofillInlineSuggestionsRequestSession session) { + mSession = new WeakReference<>(session); + } + + @BinderThread + @Override + public void onInlineSuggestionsUnsupported() throws RemoteException { + if (sDebug) Log.d(TAG, "onInlineSuggestionsUnsupported() called."); + final AutofillInlineSuggestionsRequestSession session = mSession.get(); + if (session != null) { + session.mHandler.sendMessage(obtainMessage( + AutofillInlineSuggestionsRequestSession::handleOnReceiveImeRequest, session, + null, null)); + } + } + + @BinderThread + @Override + public void onInlineSuggestionsRequest(InlineSuggestionsRequest request, + IInlineSuggestionsResponseCallback callback) { + if (sDebug) Log.d(TAG, "onInlineSuggestionsRequest() received: " + request); + final AutofillInlineSuggestionsRequestSession session = mSession.get(); + if (session != null) { + session.mHandler.sendMessage(obtainMessage( + AutofillInlineSuggestionsRequestSession::handleOnReceiveImeRequest, session, + request, callback)); + } + } + + @Override + public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException { + if (sDebug) Log.d(TAG, "onInputMethodStartInput() received on " + imeFieldId); + final AutofillInlineSuggestionsRequestSession session = mSession.get(); + if (session != null) { + session.mHandler.sendMessage(obtainMessage( + AutofillInlineSuggestionsRequestSession::handleOnReceiveImeStatusUpdated, + session, imeFieldId, true, false)); + } + } + + @Override + public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException { + if (sDebug) { + Log.d(TAG, "onInputMethodShowInputRequested() received: " + requestResult); + } + } + + @BinderThread + @Override + public void onInputMethodStartInputView() { + if (sDebug) Log.d(TAG, "onInputMethodStartInputView() received"); + final AutofillInlineSuggestionsRequestSession session = mSession.get(); + if (session != null) { + session.mHandler.sendMessage(obtainMessage( + AutofillInlineSuggestionsRequestSession::handleOnReceiveImeStatusUpdated, + session, true, true)); + } + } + + @BinderThread + @Override + public void onInputMethodFinishInputView() { + if (sDebug) Log.d(TAG, "onInputMethodFinishInputView() received"); + final AutofillInlineSuggestionsRequestSession session = mSession.get(); + if (session != null) { + session.mHandler.sendMessage(obtainMessage( + AutofillInlineSuggestionsRequestSession::handleOnReceiveImeStatusUpdated, + session, true, false)); + } + } + + @Override + public void onInputMethodFinishInput() throws RemoteException { + if (sDebug) Log.d(TAG, "onInputMethodFinishInput() received"); + final AutofillInlineSuggestionsRequestSession session = mSession.get(); + if (session != null) { + session.mHandler.sendMessage(obtainMessage( + AutofillInlineSuggestionsRequestSession::handleOnReceiveImeStatusUpdated, + session, false, false)); + } + } + } + + private static boolean match(@Nullable AutofillId autofillId, + @Nullable AutofillId imeClientFieldId) { + // The IME doesn't have information about the virtual view id for the child views in the + // web view, so we are only comparing the parent view id here. This means that for cases + // where there are two input fields in the web view, they will have the same view id + // (although different virtual child id), and we will not be able to distinguish them. + return autofillId != null && imeClientFieldId != null + && autofillId.getViewId() == imeClientFieldId.getViewId(); + } +} diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index d1805d96cad8..1bc026cd3b19 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -815,26 +815,27 @@ final class AutofillManagerServiceImpl } } - void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId) { + void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId, + @Nullable Bundle clientState) { synchronized (mLock) { if (mAugmentedAutofillEventHistory == null || mAugmentedAutofillEventHistory.getSessionId() != sessionId) { return; } mAugmentedAutofillEventHistory.addEvent( - new Event(Event.TYPE_DATASET_SELECTED, suggestionId, null, null, null, + new Event(Event.TYPE_DATASET_SELECTED, suggestionId, clientState, null, null, null, null, null, null, null, null)); } } - void logAugmentedAutofillShown(int sessionId) { + void logAugmentedAutofillShown(int sessionId, @Nullable Bundle clientState) { synchronized (mLock) { if (mAugmentedAutofillEventHistory == null || mAugmentedAutofillEventHistory.getSessionId() != sessionId) { return; } mAugmentedAutofillEventHistory.addEvent( - new Event(Event.TYPE_DATASETS_SHOWN, null, null, null, null, null, + new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null, null, null, null, null, null)); } @@ -1185,15 +1186,16 @@ final class AutofillManagerServiceImpl } @Override - public void logAugmentedAutofillShown(int sessionId) { - AutofillManagerServiceImpl.this.logAugmentedAutofillShown(sessionId); + public void logAugmentedAutofillShown(int sessionId, Bundle clientState) { + AutofillManagerServiceImpl.this.logAugmentedAutofillShown(sessionId, + clientState); } @Override public void logAugmentedAutofillSelected(int sessionId, - String suggestionId) { + String suggestionId, Bundle clientState) { AutofillManagerServiceImpl.this.logAugmentedAutofillSelected(sessionId, - suggestionId); + suggestionId, clientState); } @Override diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java deleted file mode 100644 index e2d511212a71..000000000000 --- a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.autofill; - -import static com.android.server.autofill.Helper.sDebug; - -import android.annotation.BinderThread; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.ComponentName; -import android.os.Bundle; -import android.os.Handler; -import android.os.RemoteException; -import android.util.Log; -import android.util.Slog; -import android.view.autofill.AutofillId; -import android.view.inputmethod.InlineSuggestionsRequest; -import android.view.inputmethod.InlineSuggestionsResponse; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.view.IInlineSuggestionsRequestCallback; -import com.android.internal.view.IInlineSuggestionsResponseCallback; -import com.android.internal.view.InlineSuggestionsRequestInfo; -import com.android.server.inputmethod.InputMethodManagerInternal; - -import java.util.Collections; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; - -/** - * Maintains an autofill inline suggestion session that communicates with the IME. - * - * <p> - * The same session may be reused for multiple input fields involved in the same autofill - * {@link Session}. Therefore, one {@link InlineSuggestionsRequest} and one - * {@link IInlineSuggestionsResponseCallback} may be used to generate and callback with inline - * suggestions for different input fields. - * - * <p> - * This class is the sole place in Autofill responsible for directly communicating with the IME. It - * receives the IME input view start/finish events, with the associated IME field Id. It uses the - * information to decide when to send the {@link InlineSuggestionsResponse} to IME. As a result, - * some of the response will be cached locally and only be sent when the IME is ready to show them. - * - * <p> - * See {@link android.inputmethodservice.InlineSuggestionSession} comments for InputMethodService - * side flow. - * - * <p> - * This class should hold the same lock as {@link Session} as they call into each other. - */ -final class InlineSuggestionSession { - - private static final String TAG = "AfInlineSuggestionSession"; - private static final int INLINE_REQUEST_TIMEOUT_MS = 200; - - @NonNull - private final InputMethodManagerInternal mInputMethodManagerInternal; - private final int mUserId; - @NonNull - private final ComponentName mComponentName; - @NonNull - private final Object mLock; - @NonNull - private final ImeStatusListener mImeStatusListener; - @NonNull - private final Handler mHandler; - - /** - * To avoid the race condition, one should not access {@code mPendingImeResponse} without - * holding the {@code mLock}. For consuming the existing value, tt's recommended to use - * {@link #getPendingImeResponse()} to get a copy of the reference to avoid blocking call. - */ - @GuardedBy("mLock") - @Nullable - private CompletableFuture<ImeResponse> mPendingImeResponse; - - @GuardedBy("mLock") - @Nullable - private AutofillResponse mPendingAutofillResponse; - - @GuardedBy("mLock") - private boolean mIsLastResponseNonEmpty = false; - - @Nullable - @GuardedBy("mLock") - private AutofillId mImeFieldId = null; - - @GuardedBy("mLock") - private boolean mImeInputViewStarted = false; - - InlineSuggestionSession(InputMethodManagerInternal inputMethodManagerInternal, - int userId, ComponentName componentName, Handler handler, Object lock) { - mInputMethodManagerInternal = inputMethodManagerInternal; - mUserId = userId; - mComponentName = componentName; - mHandler = handler; - mLock = lock; - mImeStatusListener = new ImeStatusListener() { - @Override - public void onInputMethodStartInput(AutofillId imeFieldId) { - synchronized (mLock) { - mImeFieldId = imeFieldId; - mImeInputViewStarted = false; - } - } - - @Override - public void onInputMethodStartInputView() { - synchronized (mLock) { - mImeInputViewStarted = true; - AutofillResponse pendingAutofillResponse = mPendingAutofillResponse; - if (pendingAutofillResponse != null - && pendingAutofillResponse.mAutofillId.equalsIgnoreSession( - mImeFieldId)) { - mPendingAutofillResponse = null; - onInlineSuggestionsResponseLocked(pendingAutofillResponse.mAutofillId, - pendingAutofillResponse.mResponse); - } - } - } - - @Override - public void onInputMethodFinishInputView() { - synchronized (mLock) { - mImeInputViewStarted = false; - } - } - - @Override - public void onInputMethodFinishInput() { - synchronized (mLock) { - mImeFieldId = null; - } - } - }; - } - - public void onCreateInlineSuggestionsRequest(@NonNull AutofillId autofillId, - @NonNull Consumer<InlineSuggestionsRequest> requestConsumer) { - if (sDebug) Log.d(TAG, "onCreateInlineSuggestionsRequest called for " + autofillId); - - synchronized (mLock) { - // Clean up all the state about the previous request. - hideInlineSuggestionsUi(autofillId); - mImeFieldId = null; - mImeInputViewStarted = false; - if (mPendingImeResponse != null && !mPendingImeResponse.isDone()) { - mPendingImeResponse.complete(null); - } - mPendingImeResponse = new CompletableFuture<>(); - // TODO(b/146454892): pipe the uiExtras from the ExtServices. - mInputMethodManagerInternal.onCreateInlineSuggestionsRequest( - mUserId, - new InlineSuggestionsRequestInfo(mComponentName, autofillId, new Bundle()), - new InlineSuggestionsRequestCallbackImpl(autofillId, mPendingImeResponse, - mImeStatusListener, requestConsumer, mHandler, mLock)); - } - } - - public Optional<InlineSuggestionsRequest> getInlineSuggestionsRequest() { - final CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse(); - if (pendingImeResponse == null || !pendingImeResponse.isDone()) { - return Optional.empty(); - } - return Optional.ofNullable(pendingImeResponse.getNow(null)).map(ImeResponse::getRequest); - } - - public boolean hideInlineSuggestionsUi(@NonNull AutofillId autofillId) { - synchronized (mLock) { - if (mIsLastResponseNonEmpty) { - return onInlineSuggestionsResponseLocked(autofillId, - new InlineSuggestionsResponse(Collections.EMPTY_LIST)); - } - return false; - } - } - - public boolean onInlineSuggestionsResponse(@NonNull AutofillId autofillId, - @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) { - synchronized (mLock) { - return onInlineSuggestionsResponseLocked(autofillId, inlineSuggestionsResponse); - } - } - - private boolean onInlineSuggestionsResponseLocked(@NonNull AutofillId autofillId, - @NonNull InlineSuggestionsResponse inlineSuggestionsResponse) { - final CompletableFuture<ImeResponse> completedImsResponse = getPendingImeResponse(); - if (completedImsResponse == null || !completedImsResponse.isDone()) { - if (sDebug) Log.d(TAG, "onInlineSuggestionsResponseLocked without IMS request"); - return false; - } - // There is no need to wait on the CompletableFuture since it should have been completed. - ImeResponse imeResponse = completedImsResponse.getNow(null); - if (imeResponse == null) { - if (sDebug) Log.d(TAG, "onInlineSuggestionsResponseLocked with pending IMS response"); - return false; - } - - // TODO(b/151846600): IME doesn't have access to the virtual id of the webview, so we - // only compare the view id for now. - if (!mImeInputViewStarted || mImeFieldId == null - || autofillId.getViewId() != mImeFieldId.getViewId()) { - if (sDebug) { - Log.d(TAG, - "onInlineSuggestionsResponseLocked not sent because input view is not " - + "started for " + autofillId); - } - mPendingAutofillResponse = new AutofillResponse(autofillId, inlineSuggestionsResponse); - // TODO(b/149442582): Although we are not sending the response to IME right away, we - // still return true to indicate that the response may be sent eventually, such that - // the dropdown UI will not be shown. This may not be the desired behavior in the - // auto-focus case where IME isn't shown after switching back to an activity. We may - // revisit this. - return true; - } - - try { - imeResponse.mCallback.onInlineSuggestionsResponse(autofillId, - inlineSuggestionsResponse); - mIsLastResponseNonEmpty = !inlineSuggestionsResponse.getInlineSuggestions().isEmpty(); - if (sDebug) { - Log.d(TAG, "Autofill sends inline response to IME: " - + inlineSuggestionsResponse.getInlineSuggestions().size()); - } - return true; - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException sending InlineSuggestionsResponse to IME"); - return false; - } - } - - @Nullable - @GuardedBy("mLock") - private CompletableFuture<ImeResponse> getPendingImeResponse() { - synchronized (mLock) { - return mPendingImeResponse; - } - } - - private static final class InlineSuggestionsRequestCallbackImpl - extends IInlineSuggestionsRequestCallback.Stub { - - private final Object mLock; - private final AutofillId mAutofillId; - @GuardedBy("mLock") - private final CompletableFuture<ImeResponse> mResponse; - @GuardedBy("mLock") - private final Consumer<InlineSuggestionsRequest> mRequestConsumer; - private final ImeStatusListener mImeStatusListener; - private final Handler mHandler; - private final Runnable mTimeoutCallback; - - private InlineSuggestionsRequestCallbackImpl(AutofillId autofillId, - CompletableFuture<ImeResponse> response, - ImeStatusListener imeStatusListener, - Consumer<InlineSuggestionsRequest> requestConsumer, - Handler handler, Object lock) { - mAutofillId = autofillId; - mResponse = response; - mImeStatusListener = imeStatusListener; - mRequestConsumer = requestConsumer; - mLock = lock; - - mHandler = handler; - mTimeoutCallback = () -> { - Log.w(TAG, "Timed out waiting for IME callback InlineSuggestionsRequest."); - completeIfNot(null); - }; - mHandler.postDelayed(mTimeoutCallback, INLINE_REQUEST_TIMEOUT_MS); - } - - private void completeIfNot(@Nullable ImeResponse response) { - synchronized (mLock) { - if (mResponse.isDone()) { - return; - } - mResponse.complete(response); - mRequestConsumer.accept(response == null ? null : response.mRequest); - mHandler.removeCallbacks(mTimeoutCallback); - } - } - - @BinderThread - @Override - public void onInlineSuggestionsUnsupported() throws RemoteException { - if (sDebug) Log.d(TAG, "onInlineSuggestionsUnsupported() called."); - completeIfNot(null); - } - - @BinderThread - @Override - public void onInlineSuggestionsRequest(InlineSuggestionsRequest request, - IInlineSuggestionsResponseCallback callback) { - if (sDebug) Log.d(TAG, "onInlineSuggestionsRequest() received: " + request); - mImeStatusListener.onInputMethodStartInput(mAutofillId); - if (request != null && callback != null) { - completeIfNot(new ImeResponse(request, callback)); - } else { - completeIfNot(null); - } - } - - @Override - public void onInputMethodStartInput(AutofillId imeFieldId) throws RemoteException { - if (sDebug) Log.d(TAG, "onInputMethodStartInput() received on " + imeFieldId); - mImeStatusListener.onInputMethodStartInput(imeFieldId); - } - - @Override - public void onInputMethodShowInputRequested(boolean requestResult) throws RemoteException { - if (sDebug) { - Log.d(TAG, "onInputMethodShowInputRequested() received: " + requestResult); - } - // TODO(b/151123764): use this signal to adjust the timeout on Autofill side waiting for - // IME to show. - } - - @BinderThread - @Override - public void onInputMethodStartInputView() { - if (sDebug) Log.d(TAG, "onInputMethodStartInputView() received"); - mImeStatusListener.onInputMethodStartInputView(); - } - - @BinderThread - @Override - public void onInputMethodFinishInputView() { - if (sDebug) Log.d(TAG, "onInputMethodFinishInputView() received"); - mImeStatusListener.onInputMethodFinishInputView(); - } - - @Override - public void onInputMethodFinishInput() throws RemoteException { - if (sDebug) Log.d(TAG, "onInputMethodFinishInput() received"); - mImeStatusListener.onInputMethodFinishInput(); - } - } - - private interface ImeStatusListener { - void onInputMethodStartInput(AutofillId imeFieldId); - - void onInputMethodStartInputView(); - - void onInputMethodFinishInputView(); - - void onInputMethodFinishInput(); - } - - /** - * A data class wrapping Autofill responses for the inline suggestion request. - */ - private static class AutofillResponse { - @NonNull - final AutofillId mAutofillId; - - @NonNull - final InlineSuggestionsResponse mResponse; - - AutofillResponse(@NonNull AutofillId autofillId, - @NonNull InlineSuggestionsResponse response) { - mAutofillId = autofillId; - mResponse = response; - } - - } - - /** - * A data class wrapping IME responses for the create inline suggestions request. - */ - private static class ImeResponse { - @NonNull - final InlineSuggestionsRequest mRequest; - - @NonNull - final IInlineSuggestionsResponseCallback mCallback; - - ImeResponse(@NonNull InlineSuggestionsRequest request, - @NonNull IInlineSuggestionsResponseCallback callback) { - mRequest = request; - mCallback = callback; - } - - InlineSuggestionsRequest getRequest() { - return mRequest; - } - } -} diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java index 8b50b010a22c..6cec8d82f9d4 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java @@ -58,6 +58,7 @@ import com.android.internal.os.IResultReceiver; import com.android.server.autofill.ui.InlineSuggestionFactory; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.TimeUnit; @@ -167,12 +168,12 @@ final class RemoteAugmentedAutofillService focusedId, focusedValue, requestTime, inlineSuggestionsRequest, new IFillCallback.Stub() { @Override - public void onSuccess( - @Nullable List<Dataset> inlineSuggestionsData) { + public void onSuccess(@Nullable List<Dataset> inlineSuggestionsData, + @Nullable Bundle clientState) { mCallbacks.resetLastResponse(); maybeRequestShowInlineSuggestions(sessionId, inlineSuggestionsRequest, inlineSuggestionsData, - focusedId, inlineSuggestionsCallback, + clientState, focusedId, inlineSuggestionsCallback, client, onErrorCallback, remoteRenderService); requestAutofill.complete(null); } @@ -237,7 +238,8 @@ final class RemoteAugmentedAutofillService private void maybeRequestShowInlineSuggestions(int sessionId, @Nullable InlineSuggestionsRequest request, - @Nullable List<Dataset> inlineSuggestionsData, @NonNull AutofillId focusedId, + @Nullable List<Dataset> inlineSuggestionsData, @Nullable Bundle clientState, + @NonNull AutofillId focusedId, @Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback, @NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback, @Nullable RemoteInlineSuggestionRenderService remoteRenderService) { @@ -255,7 +257,7 @@ final class RemoteAugmentedAutofillService @Override public void autofill(Dataset dataset) { mCallbacks.logAugmentedAutofillSelected(sessionId, - dataset.getId()); + dataset.getId(), clientState); try { final ArrayList<AutofillId> fieldIds = dataset.getFieldIds(); final int size = fieldIds.size(); @@ -263,6 +265,8 @@ final class RemoteAugmentedAutofillService && fieldIds.get(0).equals(focusedId); client.autofill(sessionId, fieldIds, dataset.getFieldValues(), hideHighlight); + inlineSuggestionsCallback.apply(new InlineSuggestionsResponse( + Collections.EMPTY_LIST)); } catch (RemoteException e) { Slog.w(TAG, "Encounter exception autofilling the values"); } @@ -284,7 +288,7 @@ final class RemoteAugmentedAutofillService return; } if (inlineSuggestionsCallback.apply(inlineSuggestionsResponse)) { - mCallbacks.logAugmentedAutofillShown(sessionId); + mCallbacks.logAugmentedAutofillShown(sessionId, clientState); } } @@ -307,8 +311,9 @@ final class RemoteAugmentedAutofillService void setLastResponse(int sessionId); - void logAugmentedAutofillShown(int sessionId); + void logAugmentedAutofillShown(int sessionId, @Nullable Bundle clientState); - void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId); + void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId, + @Nullable Bundle clientState); } } diff --git a/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java b/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java index 7ad5632dd70e..347174c4c804 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java @@ -27,7 +27,9 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.os.Bundle; import android.os.IBinder; +import android.os.RemoteCallback; import android.service.autofill.IInlineSuggestionRenderService; import android.service.autofill.IInlineSuggestionUiCallback; import android.service.autofill.InlinePresentation; @@ -91,6 +93,15 @@ public final class RemoteInlineSuggestionRenderService extends hostInputToken, displayId)); } + /** + * Gets the inline suggestions renderer info as a {@link Bundle}. + */ + public void getInlineSuggestionsRendererInfo(@NonNull RemoteCallback callback) { + scheduleAsyncRequest((s) -> s.getInlineSuggestionsRendererInfo(new RemoteCallback( + (bundle) -> callback.sendResult(bundle) + ))); + } + @Nullable private static ServiceInfo getServiceInfo(Context context, int userId) { final String packageName = diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 12905696ff98..3d6861898aaf 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -304,7 +304,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private boolean mForAugmentedAutofillOnly; @Nullable - private final InlineSuggestionSession mInlineSuggestionSession; + private final AutofillInlineSessionController mInlineSessionController; /** * Receiver of assist data from the app's {@link Activity}. @@ -652,10 +652,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return mService.isInlineSuggestionsEnabled(); } - private boolean isInlineSuggestionRenderServiceAvailable() { - return mService.getRemoteInlineSuggestionRenderServiceLocked() != null; - } - /** * Clears the existing response for the partition, reads a new structure, and then requests a * new fill response from the fill service. @@ -715,13 +711,18 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // Only ask IME to create inline suggestions request if Autofill provider supports it and // the render service is available. - if (isInlineSuggestionsEnabledByAutofillProviderLocked() - && isInlineSuggestionRenderServiceAvailable()) { + final RemoteInlineSuggestionRenderService remoteRenderService = + mService.getRemoteInlineSuggestionRenderServiceLocked(); + if (isInlineSuggestionsEnabledByAutofillProviderLocked() && remoteRenderService != null) { Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer = mAssistReceiver.newAutofillRequestLocked(/*isInlineRequest=*/ true); if (inlineSuggestionsRequestConsumer != null) { - mInlineSuggestionSession.onCreateInlineSuggestionsRequest(mCurrentViewId, - inlineSuggestionsRequestConsumer); + remoteRenderService.getInlineSuggestionsRendererInfo( + new RemoteCallback((extras) -> { + mInlineSessionController.onCreateInlineSuggestionsRequestLocked( + mCurrentViewId, inlineSuggestionsRequestConsumer, extras); + } + )); } } else { mAssistReceiver.newAutofillRequestLocked(/*isInlineRequest=*/ false); @@ -777,8 +778,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mForAugmentedAutofillOnly = forAugmentedAutofillOnly; setClientLocked(client); - mInlineSuggestionSession = new InlineSuggestionSession(inputMethodManagerInternal, userId, - componentName, handler, mLock); + mInlineSessionController = new AutofillInlineSessionController(inputMethodManagerInternal, + userId, componentName, handler, mLock); mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED) .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags)); @@ -1227,6 +1228,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } catch (RemoteException e) { Slog.e(TAG, "Error requesting to hide fill UI", e); } + + mInlineSessionController.hideInlineSuggestionsUiLocked(id); } } @@ -2561,7 +2564,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (sVerbose) Slog.v(TAG, "Exiting view " + id); mUi.hideFillUi(this); hideAugmentedAutofillLocked(viewState); - mInlineSuggestionSession.hideInlineSuggestionsUi(mCurrentViewId); + mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId); mCurrentViewId = null; } break; @@ -2779,7 +2782,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private boolean requestShowInlineSuggestionsLocked(@NonNull FillResponse response, @Nullable String filterText) { final Optional<InlineSuggestionsRequest> inlineSuggestionsRequest = - mInlineSuggestionSession.getInlineSuggestionsRequest(); + mInlineSessionController.getInlineSuggestionsRequestLocked(); if (!inlineSuggestionsRequest.isPresent()) { Log.w(TAG, "InlineSuggestionsRequest unavailable"); return false; @@ -2801,7 +2804,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState inlineSuggestionsRequest.get(), response, filterText, mCurrentViewId, this, () -> { synchronized (mLock) { - mInlineSuggestionSession.hideInlineSuggestionsUi(mCurrentViewId); + mInlineSessionController.hideInlineSuggestionsUiLocked( + mCurrentViewId); } }, remoteRenderService); if (inlineSuggestionsResponse == null) { @@ -2809,7 +2813,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return false; } - return mInlineSuggestionSession.onInlineSuggestionsResponse(mCurrentViewId, + return mInlineSessionController.onInlineSuggestionsResponseLocked(mCurrentViewId, inlineSuggestionsResponse); } @@ -3106,8 +3110,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState focusedId, currentValue, inlineSuggestionsRequest, /*inlineSuggestionsCallback=*/ - response -> mInlineSuggestionSession.onInlineSuggestionsResponse( - mCurrentViewId, response), + response -> { + synchronized (mLock) { + return mInlineSessionController + .onInlineSuggestionsResponseLocked( + mCurrentViewId, response); + } + }, /*onErrorCallback=*/ () -> { synchronized (mLock) { cancelAugmentedAutofillLocked(); @@ -3121,15 +3130,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // 1. the field is augmented autofill only (when standard autofill provider is None or // when it returns null response) // 2. standard autofill provider doesn't support inline suggestion - if (isInlineSuggestionRenderServiceAvailable() + final RemoteInlineSuggestionRenderService remoteRenderService = + mService.getRemoteInlineSuggestionRenderServiceLocked(); + if (remoteRenderService != null && (mForAugmentedAutofillOnly || !isInlineSuggestionsEnabledByAutofillProviderLocked())) { if (sDebug) Slog.d(TAG, "Create inline request for augmented autofill"); - mInlineSuggestionSession.onCreateInlineSuggestionsRequest(mCurrentViewId, - /*requestConsumer=*/ requestAugmentedAutofill); + remoteRenderService.getInlineSuggestionsRendererInfo(new RemoteCallback( + (extras) -> { + mInlineSessionController.onCreateInlineSuggestionsRequestLocked( + mCurrentViewId, /*requestConsumer=*/ requestAugmentedAutofill, + extras); + }, mHandler)); } else { requestAugmentedAutofill.accept( - mInlineSuggestionSession.getInlineSuggestionsRequest().orElse(null)); + mInlineSessionController.getInlineSuggestionsRequestLocked().orElse(null)); } if (mAugmentedAutofillDestroyer == null) { mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest(); diff --git a/services/core/Android.bp b/services/core/Android.bp index a8bc2b4bc6ce..77773edc28ca 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -127,7 +127,7 @@ java_library_static { "android.hardware.soundtrigger-V2.3-java", "android.hidl.manager-V1.2-java", "capture_state_listener-aidl-java", - "dnsresolver_aidl_interface-V2-java", + "dnsresolver_aidl_interface-V4-java", "netd_event_listener_interface-java", "overlayable_policy_aidl-java", ], diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 192ea72224b1..3c0d880916ee 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -119,8 +119,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int MESSAGE_DISABLE = 2; private static final int MESSAGE_HANDLE_ENABLE_DELAYED = 3; private static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4; - private static final int MESSAGE_REGISTER_ADAPTER = 20; - private static final int MESSAGE_UNREGISTER_ADAPTER = 21; private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30; private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31; private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40; @@ -642,10 +640,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { Slog.w(TAG, "Callback is null in registerAdapter"); return null; } - Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER); - msg.obj = callback; - mHandler.sendMessage(msg); - + synchronized (mCallbacks) { + mCallbacks.register(callback); + } return mBluetooth; } @@ -655,9 +652,9 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return; } mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER); - msg.obj = callback; - mHandler.sendMessage(msg); + synchronized (mCallbacks) { + mCallbacks.unregister(callback); + } } public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) { @@ -1559,18 +1556,20 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * Inform BluetoothAdapter instances that Adapter service is up */ private void sendBluetoothServiceUpCallback() { - try { - int n = mCallbacks.beginBroadcast(); - Slog.d(TAG, "Broadcasting onBluetoothServiceUp() to " + n + " receivers."); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); + synchronized (mCallbacks) { + try { + int n = mCallbacks.beginBroadcast(); + Slog.d(TAG, "Broadcasting onBluetoothServiceUp() to " + n + " receivers."); + for (int i = 0; i < n; i++) { + try { + mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e); + } } + } finally { + mCallbacks.finishBroadcast(); } - } finally { - mCallbacks.finishBroadcast(); } } @@ -1578,18 +1577,20 @@ class BluetoothManagerService extends IBluetoothManager.Stub { * Inform BluetoothAdapter instances that Adapter service is down */ private void sendBluetoothServiceDownCallback() { - try { - int n = mCallbacks.beginBroadcast(); - Slog.d(TAG, "Broadcasting onBluetoothServiceDown() to " + n + " receivers."); - for (int i = 0; i < n; i++) { - try { - mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); + synchronized (mCallbacks) { + try { + int n = mCallbacks.beginBroadcast(); + Slog.d(TAG, "Broadcasting onBluetoothServiceDown() to " + n + " receivers."); + for (int i = 0; i < n; i++) { + try { + mCallbacks.getBroadcastItem(i).onBluetoothServiceDown(); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e); + } } + } finally { + mCallbacks.finishBroadcast(); } - } finally { - mCallbacks.finishBroadcast(); } } @@ -1917,17 +1918,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mContext.getPackageName()); } break; - - case MESSAGE_REGISTER_ADAPTER: { - IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; - mCallbacks.register(callback); - break; - } - case MESSAGE_UNREGISTER_ADAPTER: { - IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; - mCallbacks.unregister(callback); - break; - } case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: { IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 8a1de1f0763e..1a58d6047bd7 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2151,7 +2151,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private boolean checkNetworkSignalStrengthWakeupPermission(int pid, int uid) { return checkAnyPermissionOf(pid, uid, android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP, - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS); } private void enforceConnectivityRestrictedNetworksPermission() { @@ -3339,6 +3340,8 @@ public class ConnectivityService extends IConnectivityManager.Stub getNetworkPermission(networkAgent.networkCapabilities)); } mDnsResolver.createNetworkCache(networkAgent.network.netId); + mDnsManager.updateTransportsForNetwork(networkAgent.network.netId, + networkAgent.networkCapabilities.getTransportTypes()); return true; } catch (RemoteException | ServiceSpecificException e) { loge("Error creating network " + networkAgent.network.netId + ": " @@ -6088,7 +6091,13 @@ public class ConnectivityService extends IConnectivityManager.Stub log("Setting DNS servers for network " + netId + " to " + dnses); } try { - mDnsManager.setDnsConfigurationForNetwork(netId, newLp, isDefaultNetwork); + mDnsManager.noteDnsServersForNetwork(netId, newLp); + // TODO: netd should listen on [::1]:53 and proxy queries to the current + // default network, and we should just set net.dns1 to ::1, not least + // because applications attempting to use net.dns resolvers will bypass + // the privacy protections of things like DNS-over-TLS. + if (isDefaultNetwork) mDnsManager.setDefaultDnsSystemProperties(newLp.getDnsServers()); + mDnsManager.flushVmDnsCache(); } catch (Exception e) { loge("Exception in setDnsConfigurationForNetwork: " + e); } @@ -6286,6 +6295,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // bubble those changes through. updateAllVpnsCapabilities(); } + + if (!newNc.equalsTransportTypes(prevNc)) { + mDnsManager.updateTransportsForNetwork(nai.network.netId, newNc.getTransportTypes()); + } } /** diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index d9e7c3851906..e77458cc955a 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -315,28 +315,31 @@ public class PackageWatchdog { // causing any elapsed time to be deducted from all existing packages before we add new // packages. This maintains the invariant that the elapsed time for ALL (new and existing) // packages is the same. - syncState("observing new packages"); + mLongTaskHandler.post(() -> { + syncState("observing new packages"); - synchronized (mLock) { - ObserverInternal oldObserver = mAllObservers.get(observer.getName()); - if (oldObserver == null) { - Slog.d(TAG, observer.getName() + " started monitoring health " - + "of packages " + packageNames); - mAllObservers.put(observer.getName(), - new ObserverInternal(observer.getName(), packages)); - } else { - Slog.d(TAG, observer.getName() + " added the following " - + "packages to monitor " + packageNames); - oldObserver.updatePackagesLocked(packages); + synchronized (mLock) { + ObserverInternal oldObserver = mAllObservers.get(observer.getName()); + if (oldObserver == null) { + Slog.d(TAG, observer.getName() + " started monitoring health " + + "of packages " + packageNames); + mAllObservers.put(observer.getName(), + new ObserverInternal(observer.getName(), packages)); + } else { + Slog.d(TAG, observer.getName() + " added the following " + + "packages to monitor " + packageNames); + oldObserver.updatePackagesLocked(packages); + } } - } - // Register observer in case not already registered - registerHealthObserver(observer); + // Register observer in case not already registered + registerHealthObserver(observer); + + // Sync after we add the new packages to the observers. We may have received packges + // requiring an earlier schedule than we are currently scheduled for. + syncState("updated observers"); + }); - // Sync after we add the new packages to the observers. We may have received packges - // requiring an earlier schedule than we are currently scheduled for. - syncState("updated observers"); } /** diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 067147703b0c..14fe0c5e3c22 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -220,6 +220,10 @@ class StorageManagerService extends IStorageManager.Stub private static final boolean ENABLE_ISOLATED_STORAGE = StorageManager.hasIsolatedStorage(); + // A system property to control if obb app data isolation is enabled in vold. + private static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY = + "persist.sys.vold_app_data_isolation_enabled"; + /** * If {@code 1}, enables the isolated storage feature. If {@code -1}, * disables the isolated storage feature. If {@code 0}, uses the default @@ -596,6 +600,8 @@ class StorageManagerService extends IStorageManager.Stub private final boolean mIsFuseEnabled; + private final boolean mVoldAppDataIsolationEnabled; + @GuardedBy("mLock") private final Set<Integer> mUidsWithLegacyExternalStorage = new ArraySet<>(); // Not guarded by lock, always used on the ActivityManager thread @@ -1516,7 +1522,7 @@ class StorageManagerService extends IStorageManager.Stub if (vol.type == VolumeInfo.TYPE_EMULATED) { if (newState != VolumeInfo.STATE_MOUNTED) { mFuseMountedUser.remove(vol.getMountUserId()); - } else { + } else if (mVoldAppDataIsolationEnabled){ final int userId = vol.getMountUserId(); mFuseMountedUser.add(userId); // Async remount app storage so it won't block the main thread. @@ -1740,6 +1746,8 @@ class StorageManagerService extends IStorageManager.Stub // incorrect until #updateFusePropFromSettings where we set the correct value and reboot if // different mIsFuseEnabled = SystemProperties.getBoolean(PROP_FUSE, DEFAULT_FUSE_ENABLED); + mVoldAppDataIsolationEnabled = mIsFuseEnabled && SystemProperties.getBoolean( + ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false); mContext = context; mResolver = mContext.getContentResolver(); mCallbacks = new Callbacks(FgThread.get().getLooper()); @@ -3207,10 +3215,14 @@ class StorageManagerService extends IStorageManager.Stub @Override public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) { - Slog.d(TAG, "unlockUserKey: " + userId); + boolean isFsEncrypted = StorageManager.isFileEncryptedNativeOrEmulated(); + Slog.d(TAG, "unlockUserKey: " + userId + + " isFileEncryptedNativeOrEmulated: " + isFsEncrypted + + " hasToken: " + (token != null) + + " hasSecret: " + (secret != null)); enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); - if (StorageManager.isFileEncryptedNativeOrEmulated()) { + if (isFsEncrypted) { try { mVold.unlockUserKey(userId, serialNumber, encodeBytes(token), encodeBytes(secret)); @@ -4468,9 +4480,8 @@ class StorageManagerService extends IStorageManager.Stub String.format("/storage/emulated/%d/Android/data/%s/", userId, pkg); - int appUid = - UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid()); // Create package obb and data dir if it doesn't exist. + int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid()); File file = new File(packageObbDir); if (!file.exists()) { vold.setupAppDir(packageObbDir, appUid); diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 061ff42de60b..58972a5346c7 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -123,6 +123,8 @@ public class Watchdog extends Thread { "android.hardware.neuralnetworks@1.0::IDevice", "android.hardware.power.stats@1.0::IPowerStats", "android.hardware.sensors@1.0::ISensors", + "android.hardware.sensors@2.0::ISensors", + "android.hardware.sensors@2.1::ISensors", "android.hardware.vr@1.0::IVr", "android.system.suspend@1.0::ISystemSuspend" ); diff --git a/services/core/java/com/android/server/am/AnrHelper.java b/services/core/java/com/android/server/am/AnrHelper.java index bc455338fc52..8f8990fdaae7 100644 --- a/services/core/java/com/android/server/am/AnrHelper.java +++ b/services/core/java/com/android/server/am/AnrHelper.java @@ -98,7 +98,7 @@ class AnrHelper { final long endTime = SystemClock.uptimeMillis(); Slog.d(TAG, "Completed ANR of " + r.mApp.processName + " in " + (endTime - startTime) + "ms, latency " + reportLatency - + (onlyDumpSelf ? "ms" : "ms (expired, only dump ANR app)")); + + (onlyDumpSelf ? "ms (expired, only dump ANR app)" : "ms")); } mRunning.set(false); diff --git a/services/core/java/com/android/server/am/BugReportHandlerUtil.java b/services/core/java/com/android/server/am/BugReportHandlerUtil.java index ba89fce0b3f8..0a0d8d85f5c3 100644 --- a/services/core/java/com/android/server/am/BugReportHandlerUtil.java +++ b/services/core/java/com/android/server/am/BugReportHandlerUtil.java @@ -16,15 +16,20 @@ package com.android.server.am; +import static android.app.AppOpsManager.OP_NONE; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import android.app.Activity; import android.app.BroadcastOptions; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Binder; +import android.os.BugreportManager; +import android.os.BugreportParams; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; @@ -43,6 +48,8 @@ public final class BugReportHandlerUtil { private static final String SHELL_APP_PACKAGE = "com.android.shell"; private static final String INTENT_BUGREPORT_REQUESTED = "com.android.internal.intent.action.BUGREPORT_REQUESTED"; + private static final String INTENT_GET_BUGREPORT_HANDLER_RESPONSE = + "com.android.internal.intent.action.GET_BUGREPORT_HANDLER_RESPONSE"; /** * Check is BugReportHandler enabled on the device. @@ -100,6 +107,43 @@ public final class BugReportHandlerUtil { return false; } + if (getBugReportHandlerAppResponseReceivers(context, handlerApp, handlerUser).isEmpty()) { + // Just try to launch bugreport handler app to handle bugreport request + // because the bugreport handler app is old and not support to provide response to + // let BugReportHandlerUtil know it is available or not. + launchBugReportHandlerApp(context, handlerApp, handlerUser); + return true; + } + + Slog.i(TAG, "Getting response from bug report handler app: " + handlerApp); + Intent intent = new Intent(INTENT_GET_BUGREPORT_HANDLER_RESPONSE); + intent.setPackage(handlerApp); + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + final long identity = Binder.clearCallingIdentity(); + try { + // Handler app's BroadcastReceiver should call setResultCode(Activity.RESULT_OK) to + // let BugreportHandlerResponseBroadcastReceiver know the handler app is available. + context.sendOrderedBroadcastAsUser(intent, + UserHandle.of(handlerUser), + android.Manifest.permission.DUMP, + OP_NONE, /* options= */ null, + new BugreportHandlerResponseBroadcastReceiver(handlerApp, handlerUser), + /* scheduler= */ null, + Activity.RESULT_CANCELED, + /* initialData= */ null, + /* initialExtras= */ null); + } catch (RuntimeException e) { + Slog.e(TAG, "Error while trying to get response from bug report handler app.", e); + return false; + } finally { + Binder.restoreCallingIdentity(identity); + } + return true; + } + + private static void launchBugReportHandlerApp(Context context, String handlerApp, + int handlerUser) { Slog.i(TAG, "Launching bug report handler app: " + handlerApp); Intent intent = new Intent(INTENT_BUGREPORT_REQUESTED); intent.setPackage(handlerApp); @@ -115,11 +159,9 @@ public final class BugReportHandlerUtil { options.toBundle()); } catch (RuntimeException e) { Slog.e(TAG, "Error while trying to launch bugreport handler app.", e); - return false; } finally { Binder.restoreCallingIdentity(identity); } - return true; } private static String getCustomBugReportHandlerApp(Context context) { @@ -159,6 +201,16 @@ public final class BugReportHandlerUtil { handlerUser); } + private static List<ResolveInfo> getBugReportHandlerAppResponseReceivers(Context context, + String handlerApp, int handlerUser) { + // Use the app package and the user id to retrieve the receiver that can provide response + Intent intent = new Intent(INTENT_GET_BUGREPORT_HANDLER_RESPONSE); + intent.setPackage(handlerApp); + return context.getPackageManager() + .queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_SYSTEM_ONLY, + handlerUser); + } + private static String getDefaultBugReportHandlerApp(Context context) { return context.getResources().getString( com.android.internal.R.string.config_defaultBugReportHandlerApp); @@ -176,4 +228,30 @@ public final class BugReportHandlerUtil { Binder.restoreCallingIdentity(identity); } } + + private static class BugreportHandlerResponseBroadcastReceiver extends BroadcastReceiver { + private final String handlerApp; + private final int handlerUser; + + BugreportHandlerResponseBroadcastReceiver(String handlerApp, int handlerUser) { + this.handlerApp = handlerApp; + this.handlerUser = handlerUser; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (getResultCode() == Activity.RESULT_OK) { + // Try to launch bugreport handler app to handle bugreport request because the + // bugreport handler app is available. + launchBugReportHandlerApp(context, handlerApp, handlerUser); + return; + } + + Slog.w(TAG, "Request bug report because no response from handler app."); + BugreportManager bugreportManager = context.getSystemService(BugreportManager.class); + bugreportManager.requestBugreport( + new BugreportParams(BugreportParams.BUGREPORT_MODE_INTERACTIVE), + /* shareTitle= */null, /* shareDescription= */ null); + } + } } diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java index ea607cb750de..0e3480131952 100644 --- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java @@ -36,7 +36,6 @@ import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.view.WindowInsets; -import android.view.WindowManager; import android.widget.ImageView; import android.widget.TextView; @@ -59,12 +58,6 @@ final class CarUserSwitchingDialog extends UserSwitchingDialog { String switchingToSystemUserMessage) { super(service, context, oldUser, newUser, aboveSystem, switchingFromSystemUserMessage, switchingToSystemUserMessage); - - // {@link UserSwitchingDialog} uses {@link WindowManager.LayoutParams.TYPE_SYSTEM_ERROR} - // when trying to show dialog above system. That window type has been deprecated and since - // this is a system dialog, hence, it makes sense to put this in System Dialog Window. - // This window also automatically shows status bar. - getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); } @Override diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index dbcb3da3e2f4..2d6ef81faf1c 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -231,7 +231,8 @@ public final class OomAdjuster { final ServiceThread adjusterThread = new ServiceThread(TAG, TOP_APP_PRIORITY_BOOST, false /* allowIo */); adjusterThread.start(); - Process.setThreadGroupAndCpuset(adjusterThread.getThreadId(), THREAD_GROUP_TOP_APP); + adjusterThread.getThreadHandler().post(() -> Process.setThreadGroupAndCpuset( + adjusterThread.getThreadId(), THREAD_GROUP_TOP_APP)); return adjusterThread; } diff --git a/services/core/java/com/android/server/am/OomAdjuster.md b/services/core/java/com/android/server/am/OomAdjuster.md new file mode 100644 index 000000000000..eda511ab7369 --- /dev/null +++ b/services/core/java/com/android/server/am/OomAdjuster.md @@ -0,0 +1,129 @@ +<!-- 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. +--> + +# Oom Adjuster Designs + +## Purpose of Oom Adjuster + +The Android OS runs with limited hardware resources, i.e. CPU/RAM/Power. To strive for the better performance, Oom Ajuster is introduced to tweak the following 3 major factors: + + * Process State + * Wildly used by the System Server, i.e., determine if it's foreground or not, change the GC behavior, etc. + * Defined in `ActivityManager#PROCESS_STATE_*` + * Oom Adj score + * Used by the lmkd to determine which process should be expunged on memory pressure. + * Defined in `ProcessList#*_ADJ` + * Scheduler Group + * Used to tweak the process group, thread priorities. + * Top process is scheduled to be running on a dedicated big core, while foreground processes take the other big cores; background processes stay with LITTLE cores instead. + +## Process Capabilities + +Besides the above 3 major factors, Android R introduced the Process Capabilities `ActivityManager#PROCESS_CAPABILITY_*`. It's a new attribute to process record, mainly designed for supporting the "while-in-use" permission model - in additional to the traditional Android permissions, wheather or not a process has access to a given API, will be guarded by its current process state as well. The OomAdjuster will compute the process capabilities during updating the oom adj. Meanwhile, the flag `ActivityManager#BIND_INCLUDE_CAPABILITIES` enables to possiblity to "transfer" the capability from a client process to the service process it binds to. + +## Rationale of Oom Adjuster + +System server keeps a list of recent used app processes. Given the 4 types of entities that an Android processes could have: Activity, Service, Content Provider and Broadcast Receiver, the System Server has to adjust the above 3 factors to give the users the best performance according to the states of the entities. A typical case would be that: foreground app A binds into a background service B in order to serve the user, in the case of memory pressure, the background service B should be avoided from being expunged since it would result user-perceptible interruption of service. The Oom Adjuster is to tweak the aforementioned 3 factors for those app processes. + +The timing of updating the Oom Adj score is vital: assume a camera process in background gets launched into foreground, launching camera typically incurs high memory pressure, which could incur low memory kills - if the camera process isn't moved out of the background adj group, it could get killed by lmkd. Therefore the updates have to be called pretty frequently: in case there is an activity start, service binding, etc. + +The update procedure basically consists of 3 parts: + * Find out the process record to be updated + * There are two categories of updateOomAdjLocked: one with the target process record to be updated, while the other one is to update all process record. + * Besides that, while computing the Oom Aj score, the clients of service connections or content providers of the present process record, which forms a process dependency graph actually, will be evaluated as well. + * Starting from Android R, when updating for a specific process record, an optimization is made that, only the reachable process records starting from this process record in the process dependency graph, will be re-evaluated. + * The `cached` Oom Adj scores are grouped in `bucket`, which is used in the isolated processes: they could be correlated - assume one isolated Chrome process is at Oom Adj score 920 and another one is 980; the later one could get expunged much earlier than the former one, which doesn't make sense; grouping them would be a big relief for this case. + * Compute Oom Adj score + * This procedure returns true if there is a score change, false if there is no. + * The curAdj field in the process record is used as an intermediate value during the computation. + * Initialize the Process State to `PROCESS_STATE_CACHED_EMPTY`, which is the lowest importance. + * Calculate the scores based on various factors: + * If it's not allowed to be lower than `ProcessList#FOREGROUND_APP_ADJ`, meaning it's propbably a persistent process, there is no too much to do here. + * Exame if the process is the top app, running remote animation, running instrumentation, receiving broadcast, executing services, running on top but sleeping (screen off), update the intermediate values. + * Ask Window Manager (yes, ActivityTaskManager is with WindowManager now) to tell each activity's visibility information. + * Check if the process has recent tasks, check if it's hosting a foreground service, overlay UI, toast etc. Note for the foreground service, if it was in foreground status, allow it to stay in higher rank in memory for a while: Assuming a camera captureing case, where the camera app is still processing the picture while being switched out of foreground - keep it stay in higher rank in memory would ensure the pictures are persisted correctly. + * Check if the process is the heavy weight process, whose launching/exiting would be slow and it's better to keep it in the memory. Note there should be only one heavy weight process across the system. + * For sure the Home process shouldn't be expunged frequently as well. + * The next two factors are either it was the previous process with visible UI to the user, or it's a backup agent. + * And then it goes to the massive searches against the service connections and the content providers, each of the clients will be evaluated, and the Oom Adj score could get updated according to its clients' scores. However there are a bunch of service binding flags which could impact the result: + * Below table captures the results with given various service binding states: + | Conditon #1 | Condition #2 | Condition #3 | Condition #4 | Result | + |---------------------------------|------------------------------------------------------------|----------------------------------------------|---------------------------------------------------|--------------------------| + | `BIND_WAIVE_PRIORITY` not set | `BIND_ALLOW_OOM_MANAGEMENT` set | Shown UI && Not Home | | Use the app's own Adj | + | | | Inactive for a while | | Use the app's own Adj | + | | Client has a higher importance | Shown UI && Not Home && client is invisible | | Use the app's own Adj | + | | | `BIND_ABOVE_CLIENT` and `BIND_IMPORTANT` set | Client is not persistent | Try client's Adj | + | | | | Client is persistent | Try persistent Adj | + | | | `BIND_NOT_PERCEPTIBLE` set | client < perceptible && app > low perceptible | Try low perceptible Adj | + | | | `BIND_NOT_VISIBLE` set | client < perceptible && app > perceptible | Try perceptible Adj | + | | | Client >= perceptible | | Try client's Adj | + | | | Adj > visible | | Max of client/Own Adj | + | | | | | Use the app's own Adj | + | | `BIND_NOT_FOREGROUND`+`BIND_IMPORTANT_BACKGROUND` not set | Client's sched group > app's | `BIND_IMPORTANT` is set | Use client's sched group | + | | | | | Use default sched group | + | | | Client's process state < top | `BIND_FOREGROUND_SERVICE` is set | ProcState = bound fg | + | | | | `BIND_FOREGROUND_SERVICE_WHILE_AWAKE` + screen ON | ProcState = bound fg | + | | | | | ProcState = important fg | + | | | Client's process state = top | | ProcState = bound top | + | | `BIND_IMPORTANT_BACKGROUND` not set | Client's process state < transient bg | | ProcState = transient bg | + | | `BIND_NOT_FOREGROUND` or `BIND_IMPORTANT_BACKGROUND` set | Client's process state < important bg | | ProcState = important bg | + | `BIND_ADJUST_WITH_ACTIVITY` set | Adj > fg && App visible | | | Adj = foreground | + | | | `BIND_NOT_FOREGROUND` not set | `BIND_IMPORTANT` is set | Sched = top app bound | + | | | | `BIND_IMPORTANT` is NOT set | Sched = default | + * Below table captures the results with given various content provider binding states: + | Conditon #1 | Condition #2 | Condition #3 | Result | + |---------------------------------|------------------------------------------------------------|----------------------------------------------|--------------------------| + | Client's process state >= cached| | | Client ProcState = empty | + | Adj > Client Adj | Not shown UI or is Home, or Client's Adj <= perceptible | Client's Adj <= foreground Adj | Try foreground Adj | + | | | Client's Adj > foreground Adj | Try client's Adj | + | Client's process state <= fg svc| Client's process state is top | | ProcState = bound top | + | | Client's process state is NOT top | | ProcState = bound fg svc | + | Has external dependencies | Adj > fg app | | adj = fg app | + | | Process state > important foreground | | ProcState = important fg | + | Still within retain time | Adj > previous app Adj | | adj = previuos app adj | + | | Process state > last activity | | ProcState = last activity| + * Some additional tweaks after the above ones: + | Conditon #1 | Condition #2 | Condition #3 | Result | + |---------------------------------|------------------------------------------------------------|----------------------------------------------|------------------------------------| + | Process state >= cached empty | Has client activities | | ProcState = cached activity client | + | | treat like activity (IME) | | ProcState = cached activity | + | Adj is service adj | computing all process records | Num of new service A > 1/3 of services | Push it to service B | + | | | Low on RAM and app process's PSS is large | Push it to service B | + * Apply the scores, which consists of: write into kernel sysfs entries to update the Oom Adj scores; call kernel API to set the thread priorities, and then tell the world the new process state + +## Cycles, Cycles, Cycles + +Another interesting aspect of the Oom Adjuster is the cycles of the dependencies. A simple example would be like below illustration, process A is hosting a service which is bound by process B; meanwhile the process B is hosting a service which is bound by process A. +<pre> + +-------------+ +-------------+ + | Process A | <-------- | Process B | + | (service 1) | --------> | (service 2) | + +-------------+ +-------------+ +</pre> + +There could be very complicated cases, which could involve multiple cycles, and in the dependency graph, each of the process record node could have different importance. +<pre> + +-------------+ +-------------+ +-------------+ +-------------+ +-------------+ + | Process D | --------> | Process A | <-------- | Process B | <-------- | Process C | <-------- | Process A | + | | | (service 1) | | (service 2) | | (service 3) | | (service 1) | + +-------------+ +-------------+ +-------------+ +-------------+ +-------------+ +</pre> + +The Oom Adjuster maintains a global sequence ID `mAdjSeq` to track the current Oom Adjuster calling. And each of the process record has a field to track in which sequence the process record is evaluated. If during the Oom Adj computation, a process record with sequence ID as same as the current global sequence ID, this would mean that a cycle is detected; in this case: + * Decrement the sequence ID of each process if there is a cycle. + * Re-evaluate each of the process record within the cycle until nothing was promoted. + * Iterate the processes from least important to most important ones. + * A maximum retries of 10 is enforced, while in practice, the maximum retries could reach only 2 to 3. + diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 595275d20154..89fa02bbbd64 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -97,6 +97,7 @@ import android.os.storage.StorageManagerInternal; import android.system.Os; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.EventLog; import android.util.LongSparseArray; import android.util.Pair; @@ -137,6 +138,7 @@ import java.util.BitSet; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; /** * Activity manager code dealing with processes. @@ -152,6 +154,9 @@ public final class ProcessList { static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY = "persist.sys.vold_app_data_isolation_enabled"; + // A system property to control if fuse is enabled. + static final String ANDROID_FUSE_ENABLED = "persist.sys.fuse"; + // The minimum time we allow between crashes, for us to consider this // application to be bad and stop and its services and reject broadcasts. static final int MIN_CRASH_INTERVAL = 60 * 1000; @@ -705,8 +710,13 @@ public final class ProcessList { // want some apps enabled while some apps disabled mAppDataIsolationEnabled = SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true); - mVoldAppDataIsolationEnabled = SystemProperties.getBoolean( + boolean fuseEnabled = SystemProperties.getBoolean(ANDROID_FUSE_ENABLED, false); + boolean voldAppDataIsolationEnabled = SystemProperties.getBoolean( ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false); + if (!fuseEnabled && voldAppDataIsolationEnabled) { + Slog.e(TAG, "Fuse is not enabled while vold app data isolation is enabled"); + } + mVoldAppDataIsolationEnabled = fuseEnabled && voldAppDataIsolationEnabled; mAppDataIsolationWhitelistedApps = new ArrayList<>( SystemConfig.getInstance().getAppDataIsolationWhitelistedApps()); @@ -1846,11 +1856,13 @@ public final class ProcessList { runtimeFlags |= Zygote.USE_APP_IMAGE_STARTUP_CACHE; } - // Enable heap pointer tagging, unless disabled by the app manifest, target sdk level, - // or the compat feature. - if (app.info.allowsNativeHeapPointerTagging() - && mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) { - runtimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI; + if (Zygote.nativeSupportsTaggedPointers()) { + // Enable heap pointer tagging if supported by the kernel, unless disabled by the + // app manifest, target sdk level, or compat feature. + if (app.info.allowsNativeHeapPointerTagging() + && mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) { + runtimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI; + } } runtimeFlags |= decideGwpAsanLevel(app); @@ -2127,18 +2139,11 @@ public final class ProcessList { for (String packageName : packages) { String volumeUuid = pmInt.getPackage(packageName).getVolumeUuid(); long inode = pmInt.getCeDataInode(packageName, userId); - if (inode != 0) { - result.put(packageName, Pair.create(volumeUuid, inode)); - } - } - if (mAppDataIsolationWhitelistedApps != null) { - for (String packageName : mAppDataIsolationWhitelistedApps) { - String volumeUuid = pmInt.getPackage(packageName).getVolumeUuid(); - long inode = pmInt.getCeDataInode(packageName, userId); - if (inode != 0) { - result.put(packageName, Pair.create(volumeUuid, inode)); - } + if (inode == 0) { + Slog.w(TAG, packageName + " inode == 0 (b/152760674)"); + return null; } + result.put(packageName, Pair.create(volumeUuid, inode)); } return result; @@ -2160,35 +2165,56 @@ public final class ProcessList { app.setHasForegroundActivities(true); } - StorageManagerInternal storageManagerInternal = LocalServices.getService( - StorageManagerInternal.class); final Map<String, Pair<String, Long>> pkgDataInfoMap; + final Map<String, Pair<String, Long>> whitelistedAppDataInfoMap; boolean bindMountAppStorageDirs = false; + boolean bindMountAppsData = mAppDataIsolationEnabled + && UserHandle.isApp(app.uid) + && mPlatformCompat.isChangeEnabled(APP_DATA_DIRECTORY_ISOLATION, app.info); - if (mAppDataIsolationEnabled && UserHandle.isApp(app.uid) - && mPlatformCompat.isChangeEnabled(APP_DATA_DIRECTORY_ISOLATION, app.info)) { - // Get all packages belongs to the same shared uid. sharedPackages is empty array - // if it doesn't have shared uid. - final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked(); - final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage( - app.info.packageName, app.userId); - pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, sharedPackages.length == 0 - ? new String[]{app.info.packageName} : sharedPackages, uid); - - int userId = UserHandle.getUserId(uid); - if (mVoldAppDataIsolationEnabled - && !storageManagerInternal.isExternalStorageService(uid)) { - bindMountAppStorageDirs = true; - if (!storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(), - app.processName)) { - // Cannot prepare Android/app and Android/obb directory, - // so we won't mount it in zygote. - app.bindMountPending = true; - bindMountAppStorageDirs = false; - } + // Get all packages belongs to the same shared uid. sharedPackages is empty array + // if it doesn't have shared uid. + final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked(); + final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage( + app.info.packageName, app.userId); + final String[] targetPackagesList = sharedPackages.length == 0 + ? new String[]{app.info.packageName} : sharedPackages; + + pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, targetPackagesList, uid); + if (pkgDataInfoMap == null) { + // TODO(b/152760674): Handle inode == 0 case properly, now we just give it a + // tmp free pass. + bindMountAppsData = false; + } + + // Remove all packages in pkgDataInfoMap from mAppDataIsolationWhitelistedApps, so + // it won't be mounted twice. + final Set<String> whitelistedApps = new ArraySet<>(mAppDataIsolationWhitelistedApps); + for (String pkg : targetPackagesList) { + whitelistedApps.remove(pkg); + } + + whitelistedAppDataInfoMap = getPackageAppDataInfoMap(pmInt, + whitelistedApps.toArray(new String[0]), uid); + if (whitelistedAppDataInfoMap == null) { + // TODO(b/152760674): Handle inode == 0 case properly, now we just give it a + // tmp free pass. + bindMountAppsData = false; + } + + int userId = UserHandle.getUserId(uid); + StorageManagerInternal storageManagerInternal = LocalServices.getService( + StorageManagerInternal.class); + if (mVoldAppDataIsolationEnabled && UserHandle.isApp(app.uid) + && !storageManagerInternal.isExternalStorageService(uid)) { + bindMountAppStorageDirs = true; + if (!storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(), + app.processName)) { + // Cannot prepare Android/app and Android/obb directory, + // so we won't mount it in zygote. + app.bindMountPending = true; + bindMountAppStorageDirs = false; } - } else { - pkgDataInfoMap = null; } final Process.ProcessStartResult startResult; @@ -2206,7 +2232,8 @@ public final class ProcessList { app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, - app.mDisabledCompatChanges, pkgDataInfoMap, bindMountAppStorageDirs, + app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap, + bindMountAppsData, bindMountAppStorageDirs, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } else { startResult = Process.start(entryPoint, @@ -2214,7 +2241,7 @@ public final class ProcessList { app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags, isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap, - bindMountAppStorageDirs, + whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } checkSlow(startTime, "startProcess: returned from zygote!"); diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index 50ec0400a729..e8acbd493180 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -165,7 +165,7 @@ public class AttentionManagerService extends SystemService { * Returns {@code true} if attention service is supported on this device. */ private boolean isAttentionServiceSupported() { - return isServiceEnabled() && isServiceAvailable(); + return isServiceEnabled() && isServiceConfigured(mContext); } @VisibleForTesting @@ -210,6 +210,11 @@ public class AttentionManagerService extends SystemService { return false; } + if (!isServiceAvailable()) { + Slog.w(LOG_TAG, "Service is not available at this moment."); + return false; + } + // don't allow attention check in screen off state if (!mPowerManager.isInteractive()) { return false; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 30e765f3d602..387a2be41d3c 100644..100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -573,6 +573,8 @@ public class AudioService extends IAudioService.Stub private boolean mMicMuteFromSwitch; private boolean mMicMuteFromApi; private boolean mMicMuteFromRestrictions; + // caches the value returned by AudioSystem.isMicrophoneMuted() + private boolean mMicMuteFromSystemCached; @GuardedBy("mSettingsLock") private int mAssistantUid; @@ -933,6 +935,7 @@ public class AudioService extends IAudioService.Stub onIndicateSystemReady(); + mMicMuteFromSystemCached = AudioSystem.isMicrophoneMuted(); setMicMuteFromSwitchInput(); } @@ -1126,6 +1129,7 @@ public class AudioService extends IAudioService.Stub sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE, SENDMSG_QUEUE, 1, 0, null, 0); + setMicrophoneMuteNoCallerCheck(getCurrentUserId()); // will also update the mic mute cache setMicMuteFromSwitchInput(); } @@ -3151,12 +3155,20 @@ public class AudioService extends IAudioService.Stub } } + /** + * Returns the microphone mute state as seen from the native audio system + * @return true if microphone is reported as muted by primary HAL + */ public boolean isMicrophoneMuted() { + return mMicMuteFromSystemCached; + } + + private boolean isMicrophoneSupposedToBeMuted() { return mMicMuteFromSwitch || mMicMuteFromRestrictions || mMicMuteFromApi; } private void setMicrophoneMuteNoCallerCheck(int userId) { - final boolean muted = isMicrophoneMuted(); + final boolean muted = isMicrophoneSupposedToBeMuted(); if (DEBUG_VOL) { Log.d(TAG, String.format("Mic mute %b, user=%d", muted, userId)); } @@ -3164,8 +3176,20 @@ public class AudioService extends IAudioService.Stub if (getCurrentUserId() == userId || userId == android.os.Process.SYSTEM_UID) { final boolean currentMute = AudioSystem.isMicrophoneMuted(); final long identity = Binder.clearCallingIdentity(); - AudioSystem.muteMicrophone(muted); + final int ret = AudioSystem.muteMicrophone(muted); + + // update cache with the real state independently from what was set + mMicMuteFromSystemCached = AudioSystem.isMicrophoneMuted(); + if (ret != AudioSystem.AUDIO_STATUS_OK) { + Log.e(TAG, "Error changing mic mute state to " + muted + " current:" + + mMicMuteFromSystemCached); + } try { + // send the intent even if there was a failure to change the actual mute state: + // the AudioManager.setMicrophoneMute API doesn't have a return value to + // indicate if the call failed to successfully change the mute state, and receiving + // the intent may be the only time an application can resynchronize its mic mute + // state with the actual system mic mute state if (muted != currentMute) { sendMsg(mAudioHandler, MSG_BROADCAST_MICROPHONE_MUTE, SENDMSG_NOOP, 0, 0, null, 0); @@ -3622,7 +3646,15 @@ public class AudioService extends IAudioService.Stub hdlr = h; // Remove from client list so that it is re-inserted at top of list iter.remove(); - hdlr.getBinder().unlinkToDeath(hdlr, 0); + try { + hdlr.getBinder().unlinkToDeath(hdlr, 0); + if (cb != hdlr.getBinder()) { + hdlr = null; + } + } catch (NoSuchElementException e) { + hdlr = null; + Log.w(TAG, "link does not exist ..."); + } break; } } @@ -6968,6 +7000,10 @@ public class AudioService extends IAudioService.Stub pw.print(" mHdmiTvClient="); pw.println(mHdmiTvClient); pw.print(" mHdmiSystemAudioSupported="); pw.println(mHdmiSystemAudioSupported); pw.print(" mIsCallScreeningModeSupported="); pw.println(mIsCallScreeningModeSupported); + pw.print(" mic mute FromSwitch=" + mMicMuteFromSwitch + + " FromRestrictions=" + mMicMuteFromRestrictions + + " FromApi=" + mMicMuteFromApi + + " from system=" + mMicMuteFromSystemCached); dumpAudioPolicies(pw); mDynPolicyLogger.dump(pw); @@ -8411,6 +8447,23 @@ public class AudioService extends IAudioService.Stub } //====================== + // Multi Audio Focus + //====================== + public void setMultiAudioFocusEnabled(boolean enabled) { + enforceModifyAudioRoutingPermission(); + if (mMediaFocusControl != null) { + boolean mafEnabled = mMediaFocusControl.getMultiAudioFocusEnabled(); + if (mafEnabled != enabled) { + mMediaFocusControl.updateMultiAudioFocus(enabled); + if (!enabled) { + mDeviceBroker.postBroadcastBecomingNoisy(); + } + } + } + } + + + //====================== // misc //====================== private final HashMap<IBinder, AudioPolicyProxy> mAudioPolicies = diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index 7bf2bc842176..bfab9919258c 100644..100755 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -30,6 +30,7 @@ import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; +import android.provider.Settings; import android.util.Log; import com.android.internal.annotations.GuardedBy; @@ -80,6 +81,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer { private final Context mContext; private final AppOpsManager mAppOps; private PlayerFocusEnforcer mFocusEnforcer; // never null + private boolean mMultiAudioFocusEnabled = false; private boolean mRingOrCallActive = false; @@ -91,6 +93,8 @@ public class MediaFocusControl implements PlayerFocusEnforcer { mContext = cntxt; mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE); mFocusEnforcer = pfe; + mMultiAudioFocusEnabled = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.MULTI_AUDIO_FOCUS_ENABLED, 0) != 0; } protected void dump(PrintWriter pw) { @@ -100,6 +104,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer { pw.println("\n"); // log mEventLogger.dump(pw); + dumpMultiAudioFocus(pw); } //================================================================= @@ -194,6 +199,14 @@ public class MediaFocusControl implements PlayerFocusEnforcer { mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN); } } + + if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) { + for (FocusRequester multifr : mMultiAudioFocusList) { + if (isLockedFocusOwner(multifr)) { + multifr.handleFocusGain(AudioManager.AUDIOFOCUS_GAIN); + } + } + } } /** @@ -203,17 +216,30 @@ public class MediaFocusControl implements PlayerFocusEnforcer { */ @GuardedBy("mAudioFocusLock") private void propagateFocusLossFromGain_syncAf(int focusGain, final FocusRequester fr, - boolean forceDuck) { + boolean forceDuck) { final List<String> clientsToRemove = new LinkedList<String>(); // going through the audio focus stack to signal new focus, traversing order doesn't // matter as all entries respond to the same external focus gain - for (FocusRequester focusLoser : mFocusStack) { - final boolean isDefinitiveLoss = - focusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck); - if (isDefinitiveLoss) { - clientsToRemove.add(focusLoser.getClientId()); + if (!mFocusStack.empty()) { + for (FocusRequester focusLoser : mFocusStack) { + final boolean isDefinitiveLoss = + focusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck); + if (isDefinitiveLoss) { + clientsToRemove.add(focusLoser.getClientId()); + } } } + + if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) { + for (FocusRequester multifocusLoser : mMultiAudioFocusList) { + final boolean isDefinitiveLoss = + multifocusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck); + if (isDefinitiveLoss) { + clientsToRemove.add(multifocusLoser.getClientId()); + } + } + } + for (String clientToRemove : clientsToRemove) { removeFocusStackEntry(clientToRemove, false /*signal*/, true /*notifyFocusFollowers*/); @@ -222,6 +248,8 @@ public class MediaFocusControl implements PlayerFocusEnforcer { private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>(); + ArrayList<FocusRequester> mMultiAudioFocusList = new ArrayList<FocusRequester>(); + /** * Helper function: * Display in the log the current entries in the audio focus stack @@ -287,6 +315,22 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } } } + + if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) { + Iterator<FocusRequester> listIterator = mMultiAudioFocusList.iterator(); + while (listIterator.hasNext()) { + FocusRequester fr = listIterator.next(); + if (fr.hasSameClient(clientToRemove)) { + listIterator.remove(); + fr.release(); + } + } + + if (signal) { + // notify the new top of the stack it gained focus + notifyTopOfAudioFocusStack(); + } + } } /** @@ -410,6 +454,16 @@ public class MediaFocusControl implements PlayerFocusEnforcer { removeFocusEntryForExtPolicy(mCb); } else { removeFocusStackEntryOnDeath(mCb); + if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) { + Iterator<FocusRequester> listIterator = mMultiAudioFocusList.iterator(); + while (listIterator.hasNext()) { + FocusRequester fr = listIterator.next(); + if (fr.hasSameBinder(mCb)) { + listIterator.remove(); + fr.release(); + } + } + } } } } @@ -867,6 +921,35 @@ public class MediaFocusControl implements PlayerFocusEnforcer { final FocusRequester nfr = new FocusRequester(aa, focusChangeHint, flags, fd, cb, clientId, afdh, callingPackageName, Binder.getCallingUid(), this, sdk); + + if (mMultiAudioFocusEnabled + && (focusChangeHint == AudioManager.AUDIOFOCUS_GAIN)) { + if (enteringRingOrCall) { + if (!mMultiAudioFocusList.isEmpty()) { + for (FocusRequester multifr : mMultiAudioFocusList) { + multifr.handleFocusLossFromGain(focusChangeHint, nfr, forceDuck); + } + } + } else { + boolean needAdd = true; + if (!mMultiAudioFocusList.isEmpty()) { + for (FocusRequester multifr : mMultiAudioFocusList) { + if (multifr.getClientUid() == Binder.getCallingUid()) { + needAdd = false; + break; + } + } + } + if (needAdd) { + mMultiAudioFocusList.add(nfr); + } + nfr.handleFocusGainFromRequest(AudioManager.AUDIOFOCUS_REQUEST_GRANTED); + notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(), + AudioManager.AUDIOFOCUS_REQUEST_GRANTED); + return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; + } + } + if (focusGrantDelayed) { // focusGrantDelayed being true implies we can't reassign focus right now // which implies the focus stack is not empty. @@ -877,9 +960,7 @@ public class MediaFocusControl implements PlayerFocusEnforcer { return requestResult; } else { // propagate the focus change through the stack - if (!mFocusStack.empty()) { - propagateFocusLossFromGain_syncAf(focusChangeHint, nfr, forceDuck); - } + propagateFocusLossFromGain_syncAf(focusChangeHint, nfr, forceDuck); // push focus requester at the top of the audio focus stack mFocusStack.push(nfr); @@ -970,4 +1051,39 @@ public class MediaFocusControl implements PlayerFocusEnforcer { } }.start(); } + + public void updateMultiAudioFocus(boolean enabled) { + Log.d(TAG, "updateMultiAudioFocus( " + enabled + " )"); + mMultiAudioFocusEnabled = enabled; + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.MULTI_AUDIO_FOCUS_ENABLED, enabled ? 1 : 0); + if (!mFocusStack.isEmpty()) { + final FocusRequester fr = mFocusStack.peek(); + fr.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS, null, false); + } + if (!enabled) { + if (!mMultiAudioFocusList.isEmpty()) { + for (FocusRequester multifr : mMultiAudioFocusList) { + multifr.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS, null, false); + } + mMultiAudioFocusList.clear(); + } + } + } + + public boolean getMultiAudioFocusEnabled() { + return mMultiAudioFocusEnabled; + } + + private void dumpMultiAudioFocus(PrintWriter pw) { + pw.println("Multi Audio Focus enabled :" + mMultiAudioFocusEnabled); + if (!mMultiAudioFocusList.isEmpty()) { + pw.println("Multi Audio Focus List:"); + pw.println("------------------------------"); + for (FocusRequester multifr : mMultiAudioFocusList) { + multifr.dump(pw); + } + pw.println("------------------------------"); + } + } } diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java index 4431abe43136..808f8c21cc8d 100644 --- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java +++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java @@ -558,8 +558,10 @@ public abstract class BiometricServiceBase extends SystemService FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(), BiometricsProtoEnums.ISSUE_CANCEL_TIMED_OUT); + ClientMonitor newClient = mPendingClient; mCurrentClient = null; - startClient(mPendingClient, false); + mPendingClient = null; + startClient(newClient, false); } } diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index 5250a771d73c..506c8e39194b 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -27,6 +27,7 @@ import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; +import android.annotation.NonNull; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -34,6 +35,7 @@ import android.net.IDnsResolver; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkUtils; +import android.net.ResolverOptionsParcel; import android.net.ResolverParamsParcel; import android.net.Uri; import android.net.shared.PrivateDnsConfig; @@ -237,6 +239,8 @@ public class DnsManager { // TODO: Replace these Maps with SparseArrays. private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap; private final Map<Integer, PrivateDnsValidationStatuses> mPrivateDnsValidationMap; + private final Map<Integer, LinkProperties> mLinkPropertiesMap; + private final Map<Integer, int[]> mTransportsMap; private int mNumDnsEntries; private int mSampleValidity; @@ -253,6 +257,8 @@ public class DnsManager { mSystemProperties = sp; mPrivateDnsMap = new HashMap<>(); mPrivateDnsValidationMap = new HashMap<>(); + mLinkPropertiesMap = new HashMap<>(); + mTransportsMap = new HashMap<>(); // TODO: Create and register ContentObservers to track every setting // used herein, posting messages to respond to changes. @@ -265,6 +271,8 @@ public class DnsManager { public void removeNetwork(Network network) { mPrivateDnsMap.remove(network.netId); mPrivateDnsValidationMap.remove(network.netId); + mTransportsMap.remove(network.netId); + mLinkPropertiesMap.remove(network.netId); } public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) { @@ -304,9 +312,35 @@ public class DnsManager { statuses.updateStatus(update); } - public void setDnsConfigurationForNetwork( - int netId, LinkProperties lp, boolean isDefaultNetwork) { + /** + * When creating a new network or transport types are changed in a specific network, + * transport types are always saved to a hashMap before update dns config. + * When destroying network, the specific network will be removed from the hashMap. + * The hashMap is always accessed on the same thread. + */ + public void updateTransportsForNetwork(int netId, @NonNull int[] transportTypes) { + mTransportsMap.put(netId, transportTypes); + sendDnsConfigurationForNetwork(netId); + } + + /** + * When {@link LinkProperties} are changed in a specific network, they are + * always saved to a hashMap before update dns config. + * When destroying network, the specific network will be removed from the hashMap. + * The hashMap is always accessed on the same thread. + */ + public void noteDnsServersForNetwork(int netId, @NonNull LinkProperties lp) { + mLinkPropertiesMap.put(netId, lp); + sendDnsConfigurationForNetwork(netId); + } + /** + * Send dns configuration parameters to resolver for a given network. + */ + public void sendDnsConfigurationForNetwork(int netId) { + final LinkProperties lp = mLinkPropertiesMap.get(netId); + final int[] transportTypes = mTransportsMap.get(netId); + if (lp == null || transportTypes == null) return; updateParametersSettings(); final ResolverParamsParcel paramsParcel = new ResolverParamsParcel(); @@ -319,15 +353,16 @@ public class DnsManager { // networks like IMS. final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId, PRIVATE_DNS_OFF); - final boolean useTls = privateDnsCfg.useTls; final boolean strictMode = privateDnsCfg.inStrictMode(); + paramsParcel.netId = netId; paramsParcel.sampleValiditySeconds = mSampleValidity; paramsParcel.successThreshold = mSuccessThreshold; paramsParcel.minSamples = mMinSamples; paramsParcel.maxSamples = mMaxSamples; - paramsParcel.servers = NetworkUtils.makeStrings(lp.getDnsServers()); + paramsParcel.servers = + NetworkUtils.makeStrings(lp.getDnsServers()); paramsParcel.domains = getDomainStrings(lp.getDomains()); paramsParcel.tlsName = strictMode ? privateDnsCfg.hostname : ""; paramsParcel.tlsServers = @@ -337,6 +372,8 @@ public class DnsManager { .collect(Collectors.toList())) : useTls ? paramsParcel.servers // Opportunistic : new String[0]; // Off + paramsParcel.resolverOptions = new ResolverOptionsParcel(); + paramsParcel.transportTypes = transportTypes; // Prepare to track the validation status of the DNS servers in the // resolver config when private DNS is in opportunistic or strict mode. if (useTls) { @@ -349,7 +386,7 @@ public class DnsManager { mPrivateDnsValidationMap.remove(netId); } - Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, " + Slog.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, " + "%d, %d, %s, %s)", paramsParcel.netId, Arrays.toString(paramsParcel.servers), Arrays.toString(paramsParcel.domains), paramsParcel.sampleValiditySeconds, paramsParcel.successThreshold, paramsParcel.minSamples, @@ -363,13 +400,6 @@ public class DnsManager { Slog.e(TAG, "Error setting DNS configuration: " + e); return; } - - // TODO: netd should listen on [::1]:53 and proxy queries to the current - // default network, and we should just set net.dns1 to ::1, not least - // because applications attempting to use net.dns resolvers will bypass - // the privacy protections of things like DNS-over-TLS. - if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers()); - flushVmDnsCache(); } public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) { @@ -384,7 +414,10 @@ public class DnsManager { mNumDnsEntries = last; } - private void flushVmDnsCache() { + /** + * Flush DNS caches and events work before boot has completed. + */ + public void flushVmDnsCache() { /* * Tell the VMs to toss their DNS caches */ diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 962f337a8b3f..9a910bf5e859 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -569,9 +569,10 @@ public final class ContentService extends IContentService.Stub { // Immediately dispatch notifications to foreground apps that // are important to the user; all other background observers are // delayed to avoid stampeding + final boolean noDelay = (key.flags & ContentResolver.NOTIFY_NO_DELAY) != 0; final int procState = LocalServices.getService(ActivityManagerInternal.class) .getUidProcessState(key.uid); - if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { + if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND || noDelay) { task.run(); } else { BackgroundThread.getHandler().postDelayed(task, BACKGROUND_OBSERVER_DELAY); diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index f82ec82ce79b..4687a5117343 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -42,6 +42,7 @@ import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; @@ -1243,6 +1244,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (!reportOnly) { Trace.traceCounter(Trace.TRACE_TAG_POWER, "ScreenState", state); + // TODO(b/153319140) remove when we can get this from the above trace invocation + SystemProperties.set("debug.tracing.screen_state", String.valueOf(state)); mPowerState.setScreenState(state); // Tell battery stats about the transition. try { @@ -1319,6 +1322,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } if (mScreenBrightnessRampAnimator.animateTo(target, rate)) { Trace.traceCounter(Trace.TRACE_TAG_POWER, "TargetScreenBrightness", (int) target); + // TODO(b/153319140) remove when we can get this from the above trace invocation + SystemProperties.set("debug.tracing.screen_brightness", String.valueOf(target)); try { // TODO(brightnessfloat): change BatteryStats to use float mBatteryStats.noteScreenBrightness( diff --git a/services/core/java/com/android/server/display/color/AppSaturationController.java b/services/core/java/com/android/server/display/color/AppSaturationController.java index e42be02d4a9e..6a685bf187ad 100644 --- a/services/core/java/com/android/server/display/color/AppSaturationController.java +++ b/services/core/java/com/android/server/display/color/AppSaturationController.java @@ -17,6 +17,7 @@ package com.android.server.display.color; import android.annotation.UserIdInt; +import android.util.ArrayMap; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; @@ -61,11 +62,12 @@ class AppSaturationController { * Set the saturation level ({@code ColorDisplayManager#SaturationLevel} constant for a given * package name and userId. */ - public boolean setSaturationLevel(String packageName, @UserIdInt int userId, + public boolean setSaturationLevel(String callingPackageName, String affectedPackageName, + @UserIdInt int userId, int saturationLevel) { synchronized (mLock) { - return getSaturationControllerLocked(packageName, userId) - .setSaturationLevel(saturationLevel); + return getSaturationControllerLocked(affectedPackageName, userId) + .setSaturationLevel(callingPackageName, saturationLevel); } } @@ -148,13 +150,19 @@ class AppSaturationController { private static class SaturationController { + private static final int FULL_SATURATION = 100; + private final List<WeakReference<ColorTransformController>> mControllerRefs = new ArrayList<>(); - private int mSaturationLevel = 100; + private final ArrayMap<String, Integer> mSaturationLevels = new ArrayMap<>(); private float[] mTransformMatrix = new float[9]; - private boolean setSaturationLevel(int saturationLevel) { - mSaturationLevel = saturationLevel; + private boolean setSaturationLevel(String callingPackageName, int saturationLevel) { + if (saturationLevel == FULL_SATURATION) { + mSaturationLevels.remove(callingPackageName); + } else { + mSaturationLevels.put(callingPackageName, saturationLevel); + } if (!mControllerRefs.isEmpty()) { return updateState(); } @@ -163,17 +171,27 @@ class AppSaturationController { private boolean addColorTransformController( WeakReference<ColorTransformController> controller) { + clearExpiredReferences(); mControllerRefs.add(controller); - if (mSaturationLevel != 100) { + if (!mSaturationLevels.isEmpty()) { return updateState(); - } else { - clearExpiredReferences(); } return false; } + private int calculateSaturationLevel() { + int saturationLevel = FULL_SATURATION; + for (int i = 0; i < mSaturationLevels.size(); i++) { + final int level = mSaturationLevels.valueAt(i); + if (level < saturationLevel) { + saturationLevel = level; + } + } + return saturationLevel; + } + private boolean updateState() { - computeGrayscaleTransformMatrix(mSaturationLevel / 100f, mTransformMatrix); + computeGrayscaleTransformMatrix(calculateSaturationLevel() / 100f, mTransformMatrix); boolean updated = false; final Iterator<WeakReference<ColorTransformController>> iterator = mControllerRefs @@ -190,7 +208,6 @@ class AppSaturationController { } } return updated; - } private void clearExpiredReferences() { @@ -206,7 +223,7 @@ class AppSaturationController { } private void dump(PrintWriter pw) { - pw.println(" mSaturationLevel: " + mSaturationLevel); + pw.println(" mSaturationLevels: " + mSaturationLevels); pw.println(" mControllerRefs count: " + mControllerRefs.size()); } } 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 2dc2cf0d8e90..95a98f1e9494 100644 --- a/services/core/java/com/android/server/display/color/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java @@ -44,6 +44,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.display.ColorDisplayManager; @@ -73,6 +74,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.server.DisplayThread; +import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.twilight.TwilightListener; import com.android.server.twilight.TwilightManager; @@ -817,9 +819,11 @@ public final class ColorDisplayService extends SystemService { return LocalDateTime.MIN; } - private boolean setAppSaturationLevelInternal(String packageName, int saturationLevel) { + private boolean setAppSaturationLevelInternal(String callingPackageName, + String affectedPackageName, int saturationLevel) { return mAppSaturationController - .setSaturationLevel(packageName, mCurrentUser, saturationLevel); + .setSaturationLevel(callingPackageName, affectedPackageName, mCurrentUser, + saturationLevel); } private void setColorModeInternal(@ColorMode int colorMode) { @@ -1533,9 +1537,11 @@ public final class ColorDisplayService extends SystemService { getContext().enforceCallingPermission( Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, "Permission required to set display saturation level"); + final String callingPackageName = LocalServices.getService(PackageManagerInternal.class) + .getNameForUid(Binder.getCallingUid()); final long token = Binder.clearCallingIdentity(); try { - return setAppSaturationLevelInternal(packageName, level); + return setAppSaturationLevelInternal(callingPackageName, packageName, level); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java index f8b39627f236..ff7da11340eb 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java @@ -115,8 +115,12 @@ public final class HdmiCecMessage { s.append(String.format("<%s> %X%X:%02X", opcodeToString(mOpcode), mSource, mDestination, mOpcode)); if (mParams.length > 0) { - for (byte data : mParams) { - s.append(String.format(":%02X", data)); + if (filterMessageParameters(mOpcode)) { + s.append(String.format(" <Redacted len=%d>", mParams.length)); + } else { + for (byte data : mParams) { + s.append(String.format(":%02X", data)); + } } } return s.toString(); @@ -270,5 +274,21 @@ public final class HdmiCecMessage { return String.format("Opcode: %02X", opcode); } } + + private static boolean filterMessageParameters(int opcode) { + switch (opcode) { + case Constants.MESSAGE_USER_CONTROL_PRESSED: + case Constants.MESSAGE_USER_CONTROL_RELEASED: + case Constants.MESSAGE_SET_OSD_NAME: + case Constants.MESSAGE_SET_OSD_STRING: + case Constants.MESSAGE_VENDOR_COMMAND: + case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN: + case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP: + case Constants.MESSAGE_VENDOR_COMMAND_WITH_ID: + return true; + default: + return false; + } + } } diff --git a/services/core/java/com/android/server/location/AppOpsHelper.java b/services/core/java/com/android/server/location/AppOpsHelper.java index 9c279166ac8a..c598fb1dbe26 100644 --- a/services/core/java/com/android/server/location/AppOpsHelper.java +++ b/services/core/java/com/android/server/location/AppOpsHelper.java @@ -19,8 +19,8 @@ package com.android.server.location; import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION; import static android.app.AppOpsManager.OP_MONITOR_LOCATION; -import static com.android.server.LocationManagerService.D; -import static com.android.server.LocationManagerService.TAG; +import static com.android.server.location.LocationManagerService.D; +import static com.android.server.location.LocationManagerService.TAG; import android.annotation.Nullable; import android.app.AppOpsManager; @@ -191,7 +191,7 @@ public class AppOpsHelper { callerIdentity.uid, callerIdentity.packageName, callerIdentity.featureId, - null) == AppOpsManager.MODE_ALLOWED; + callerIdentity.listenerId) == AppOpsManager.MODE_ALLOWED; } finally { Binder.restoreCallingIdentity(identity); } @@ -210,7 +210,7 @@ public class AppOpsHelper { callerIdentity.packageName, false, callerIdentity.featureId, - null) == AppOpsManager.MODE_ALLOWED; + callerIdentity.listenerId) == AppOpsManager.MODE_ALLOWED; } finally { Binder.restoreCallingIdentity(identity); } @@ -245,7 +245,7 @@ public class AppOpsHelper { callerIdentity.uid, callerIdentity.packageName, callerIdentity.featureId, - null) == AppOpsManager.MODE_ALLOWED; + callerIdentity.listenerId) == AppOpsManager.MODE_ALLOWED; } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/location/CallerIdentity.java b/services/core/java/com/android/server/location/CallerIdentity.java index b84fd13415fc..8d508bb6256d 100644 --- a/services/core/java/com/android/server/location/CallerIdentity.java +++ b/services/core/java/com/android/server/location/CallerIdentity.java @@ -83,12 +83,22 @@ public final class CallerIdentity { */ public static CallerIdentity fromBinder(Context context, String packageName, @Nullable String featureId) { + return fromBinder(context, packageName, featureId, null); + } + + /** + * Creates a CallerIdentity from the current binder identity, using the given package, feature + * id, and listener id. The package will be checked to enforce it belongs to the calling uid, + * and a security exception will be thrown if it is invalid. + */ + public static CallerIdentity fromBinder(Context context, String packageName, + @Nullable String featureId, @Nullable String listenerId) { int uid = Binder.getCallingUid(); if (!ArrayUtils.contains(context.getPackageManager().getPackagesForUid(uid), packageName)) { throw new SecurityException("invalid package \"" + packageName + "\" for uid " + uid); } - return fromBinderUnsafe(context, packageName, featureId); + return fromBinderUnsafe(context, packageName, featureId, listenerId); } /** @@ -99,8 +109,19 @@ public final class CallerIdentity { */ public static CallerIdentity fromBinderUnsafe(Context context, String packageName, @Nullable String featureId) { + return fromBinderUnsafe(context, packageName, featureId, null); + } + + /** + * Creates a CallerIdentity from the current binder identity, using the given package, feature + * id, and listener id. The package will not be checked to enforce that it belongs to the + * calling uid - this method should only be used if the package will be validated by some other + * means, such as an appops call. + */ + public static CallerIdentity fromBinderUnsafe(Context context, String packageName, + @Nullable String featureId, @Nullable String listenerId) { return new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(), - UserHandle.getCallingUserId(), packageName, featureId, + UserHandle.getCallingUserId(), packageName, featureId, listenerId, getBinderPermissionLevel(context)); } @@ -157,6 +178,9 @@ public final class CallerIdentity { /** The calling feature id. */ public final @Nullable String featureId; + /** The calling listener id. */ + public final @Nullable String listenerId; + /** * The calling location permission level. This field should only be used for validating * permissions for API access. It should not be used for validating permissions for location @@ -167,11 +191,18 @@ public final class CallerIdentity { @VisibleForTesting public CallerIdentity(int uid, int pid, int userId, String packageName, @Nullable String featureId, @PermissionLevel int permissionLevel) { + this(uid, pid, userId, packageName, featureId, null, permissionLevel); + } + + private CallerIdentity(int uid, int pid, int userId, String packageName, + @Nullable String featureId, @Nullable String listenerId, + @PermissionLevel int permissionLevel) { this.uid = uid; this.pid = pid; this.userId = userId; this.packageName = Objects.requireNonNull(packageName); this.featureId = featureId; + this.listenerId = listenerId; this.permissionLevel = Preconditions.checkArgumentInRange(permissionLevel, PERMISSION_NONE, PERMISSION_FINE, "permissionLevel"); } @@ -216,7 +247,8 @@ public final class CallerIdentity { return uid == that.uid && pid == that.pid && packageName.equals(that.packageName) - && Objects.equals(featureId, that.featureId); + && Objects.equals(featureId, that.featureId) + && Objects.equals(listenerId, that.listenerId); } @Override diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index a9c3079adcc0..72cc13a2a419 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.location; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; @@ -91,27 +91,14 @@ import com.android.internal.location.ProviderRequest; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; -import com.android.server.location.AbstractLocationProvider; +import com.android.server.FgThread; +import com.android.server.LocalServices; +import com.android.server.PendingIntentUtils; +import com.android.server.SystemService; import com.android.server.location.AbstractLocationProvider.State; -import com.android.server.location.AppForegroundHelper; -import com.android.server.location.AppOpsHelper; -import com.android.server.location.CallerIdentity; import com.android.server.location.CallerIdentity.PermissionLevel; -import com.android.server.location.GeocoderProxy; -import com.android.server.location.GeofenceManager; -import com.android.server.location.GeofenceProxy; -import com.android.server.location.HardwareActivityRecognitionProxy; -import com.android.server.location.LocationFudger; -import com.android.server.location.LocationProviderProxy; -import com.android.server.location.LocationRequestStatistics; import com.android.server.location.LocationRequestStatistics.PackageProviderKey; import com.android.server.location.LocationRequestStatistics.PackageStatistics; -import com.android.server.location.LocationUsageLogger; -import com.android.server.location.MockProvider; -import com.android.server.location.MockableLocationProvider; -import com.android.server.location.PassiveProvider; -import com.android.server.location.SettingsHelper; -import com.android.server.location.UserInfoHelper; import com.android.server.location.UserInfoHelper.UserListener; import com.android.server.location.gnss.GnssManagerService; import com.android.server.pm.permission.PermissionManagerServiceInternal; @@ -1620,8 +1607,8 @@ public class LocationManagerService extends ILocationManager.Stub { // For now, make sure callers have supplied an attribution tag for use with // AppOpsManager. This might be relaxed in the future. final List<WorkChain> workChains = workSource.getWorkChains(); - return workChains != null && !workChains.isEmpty() && - workChains.get(0).getAttributionTag() != null; + return workChains != null && !workChains.isEmpty() + && workChains.get(0).getAttributionTag() != null; } } @@ -1836,12 +1823,13 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void requestLocationUpdates(LocationRequest request, ILocationListener listener, - PendingIntent intent, String packageName, String featureId) { + PendingIntent intent, String packageName, String featureId, String listenerId) { if (request == null) { request = DEFAULT_LOCATION_REQUEST; } - CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId); + CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId, + listenerId); identity.enforceLocationPermission(); WorkSource workSource = request.getWorkSource(); @@ -2027,7 +2015,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public boolean getCurrentLocation(LocationRequest locationRequest, ICancellationSignal remoteCancellationSignal, ILocationListener listener, - String packageName, String featureId) { + String packageName, String featureId, String listenerId) { // side effect of validating locationRequest and packageName Location lastLocation = getLastLocation(locationRequest, packageName, featureId); if (lastLocation != null) { @@ -2052,7 +2040,7 @@ public class LocationManagerService extends ILocationManager.Stub { } } - requestLocationUpdates(locationRequest, listener, null, packageName, featureId); + requestLocationUpdates(locationRequest, listener, null, packageName, featureId, listenerId); CancellationSignal cancellationSignal = CancellationSignal.fromTransport( remoteCancellationSignal); if (cancellationSignal != null) { diff --git a/services/core/java/com/android/server/LocationManagerServiceUtils.java b/services/core/java/com/android/server/location/LocationManagerServiceUtils.java index 9d0fe5e936bb..c33a70662cb5 100644 --- a/services/core/java/com/android/server/LocationManagerServiceUtils.java +++ b/services/core/java/com/android/server/location/LocationManagerServiceUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,15 +14,13 @@ * limitations under the License. */ -package com.android.server; +package com.android.server.location; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; import android.os.RemoteException; -import com.android.server.location.CallerIdentity; - import java.util.NoSuchElementException; import java.util.function.Consumer; diff --git a/services/core/java/com/android/server/location/LocationUsageLogger.java b/services/core/java/com/android/server/location/LocationUsageLogger.java index 93e19df01cf3..b325deb786d6 100644 --- a/services/core/java/com/android/server/location/LocationUsageLogger.java +++ b/services/core/java/com/android/server/location/LocationUsageLogger.java @@ -16,7 +16,7 @@ package com.android.server.location; -import static com.android.server.LocationManagerService.TAG; +import static com.android.server.location.LocationManagerService.TAG; import android.app.ActivityManager; import android.location.Geofence; diff --git a/services/core/java/com/android/server/location/SettingsHelper.java b/services/core/java/com/android/server/location/SettingsHelper.java index 7ab258c29b46..cbb06b86a291 100644 --- a/services/core/java/com/android/server/location/SettingsHelper.java +++ b/services/core/java/com/android/server/location/SettingsHelper.java @@ -26,8 +26,8 @@ import static android.provider.Settings.Secure.LOCATION_COARSE_ACCURACY_M; import static android.provider.Settings.Secure.LOCATION_MODE; import static android.provider.Settings.Secure.LOCATION_MODE_OFF; -import static com.android.server.LocationManagerService.D; -import static com.android.server.LocationManagerService.TAG; +import static com.android.server.location.LocationManagerService.D; +import static com.android.server.location.LocationManagerService.TAG; import android.app.ActivityManager; import android.content.Context; diff --git a/services/core/java/com/android/server/location/UserInfoHelper.java b/services/core/java/com/android/server/location/UserInfoHelper.java index 28f3f476847b..a3dcc40bdf2d 100644 --- a/services/core/java/com/android/server/location/UserInfoHelper.java +++ b/services/core/java/com/android/server/location/UserInfoHelper.java @@ -18,8 +18,8 @@ package com.android.server.location; import static android.os.UserManager.DISALLOW_SHARE_LOCATION; -import static com.android.server.LocationManagerService.D; -import static com.android.server.LocationManagerService.TAG; +import static com.android.server.location.LocationManagerService.D; +import static com.android.server.location.LocationManagerService.TAG; import android.annotation.IntDef; import android.annotation.Nullable; diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index ad3c8a61182f..d8acf0e331af 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -809,11 +809,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements locationRequest.setProvider(provider); // Ignore location settings if in emergency mode. This is only allowed for - // isUserEmergency request (introduced in HAL v2.0), or DBH request in HAL v1.1. + // isUserEmergency request (introduced in HAL v2.0), or HAL v1.1. if (mNIHandler.getInEmergency()) { GnssConfiguration.HalInterfaceVersion halVersion = mGnssConfiguration.getHalInterfaceVersion(); - if (isUserEmergency || (halVersion.mMajor < 2 && !independentFromGnss)) { + if (isUserEmergency || halVersion.mMajor < 2) { locationRequest.setLocationSettingsIgnored(true); durationMillis *= EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER; } diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java index 711f45cb7d28..3c509c380374 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -46,11 +46,11 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.LocalServices; -import com.android.server.LocationManagerServiceUtils.LinkedListener; -import com.android.server.LocationManagerServiceUtils.LinkedListenerBase; import com.android.server.location.AppForegroundHelper; import com.android.server.location.AppOpsHelper; import com.android.server.location.CallerIdentity; +import com.android.server.location.LocationManagerServiceUtils.LinkedListener; +import com.android.server.location.LocationManagerServiceUtils.LinkedListenerBase; import com.android.server.location.LocationUsageLogger; import com.android.server.location.RemoteListenerHelper; import com.android.server.location.SettingsHelper; diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java index 2aa53cc3882e..a5de90c93aab 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java @@ -169,6 +169,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider } public void rebindIfDisconnected() { + //TODO: When we are connecting to the service, calling this will unbind and bind again. + // We'd better not unbind if we are connecting. if (mActiveConnection == null && shouldBind()) { unbind(); bind(); diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java index fe118e51cdce..b688e0922d49 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java @@ -83,7 +83,7 @@ final class MediaRoute2ProviderWatcher { // Scan packages. // Also has the side-effect of restarting providers if needed. - mHandler.post(mScanPackagesRunnable); + postScanPackagesIfNeeded(); } } @@ -92,7 +92,7 @@ final class MediaRoute2ProviderWatcher { mRunning = false; mContext.unregisterReceiver(mScanPackagesReceiver); - mHandler.removeCallbacks(mScanPackagesRunnable); + mHandler.removeCallbacks(this::scanPackages); // Stop all providers. for (int i = mProxies.size() - 1; i >= 0; i--) { @@ -154,20 +154,19 @@ final class MediaRoute2ProviderWatcher { return -1; } + private void postScanPackagesIfNeeded() { + if (!mHandler.hasCallbacks(this::scanPackages)) { + mHandler.post(this::scanPackages); + } + } + private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) { Slog.d(TAG, "Received package manager broadcast: " + intent); } - scanPackages(); - } - }; - - private final Runnable mScanPackagesRunnable = new Runnable() { - @Override - public void run() { - scanPackages(); + postScanPackagesIfNeeded(); } }; diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 52e9d7c67605..0d899974cf93 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -98,18 +98,26 @@ class MediaRouter2ServiceImpl { public List<MediaRoute2Info> getSystemRoutes() { final int uid = Binder.getCallingUid(); final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier(); + final boolean hasModifyAudioRoutingPermission = mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_AUDIO_ROUTING) + == PackageManager.PERMISSION_GRANTED; final long token = Binder.clearCallingIdentity(); try { Collection<MediaRoute2Info> systemRoutes; synchronized (mLock) { UserRecord userRecord = getOrCreateUserRecordLocked(userId); - MediaRoute2ProviderInfo providerInfo = - userRecord.mHandler.mSystemProvider.getProviderInfo(); - if (providerInfo != null) { - systemRoutes = providerInfo.getRoutes(); + if (hasModifyAudioRoutingPermission) { + MediaRoute2ProviderInfo providerInfo = + userRecord.mHandler.mSystemProvider.getProviderInfo(); + if (providerInfo != null) { + systemRoutes = providerInfo.getRoutes(); + } else { + systemRoutes = Collections.emptyList(); + } } else { - systemRoutes = Collections.emptyList(); + systemRoutes = new ArrayList<>(); + systemRoutes.add(userRecord.mHandler.mSystemProvider.getDefaultRoute()); } } return new ArrayList<>(systemRoutes); @@ -122,18 +130,25 @@ class MediaRouter2ServiceImpl { public RoutingSessionInfo getSystemSessionInfo() { final int uid = Binder.getCallingUid(); final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier(); + final boolean hasModifyAudioRoutingPermission = mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_AUDIO_ROUTING) + == PackageManager.PERMISSION_GRANTED; final long token = Binder.clearCallingIdentity(); try { RoutingSessionInfo systemSessionInfo = null; synchronized (mLock) { UserRecord userRecord = getOrCreateUserRecordLocked(userId); - List<RoutingSessionInfo> sessionInfos = - userRecord.mHandler.mSystemProvider.getSessionInfos(); - if (sessionInfos != null && !sessionInfos.isEmpty()) { - systemSessionInfo = sessionInfos.get(0); + List<RoutingSessionInfo> sessionInfos; + if (hasModifyAudioRoutingPermission) { + sessionInfos = userRecord.mHandler.mSystemProvider.getSessionInfos(); + if (sessionInfos != null && !sessionInfos.isEmpty()) { + systemSessionInfo = sessionInfos.get(0); + } else { + Slog.w(TAG, "System provider does not have any session info."); + } } else { - Slog.w(TAG, "System provider does not have any session info."); + systemSessionInfo = userRecord.mHandler.mSystemProvider.getDefaultSessionInfo(); } } return systemSessionInfo; @@ -607,6 +622,16 @@ class MediaRouter2ServiceImpl { return; } + if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission + && !TextUtils.equals(route.getId(), + routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId())) { + Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to" + + route); + routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter( + routerRecord, requestId); + return; + } + long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId); routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::requestCreateSessionOnHandler, @@ -654,10 +679,20 @@ class MediaRouter2ServiceImpl { return; } - routerRecord.mUserRecord.mHandler.sendMessage( - obtainMessage(UserHandler::transferToRouteOnHandler, - routerRecord.mUserRecord.mHandler, - DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route)); + String defaultRouteId = + routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId(); + if (route.isSystemRoute() && !routerRecord.mHasModifyAudioRoutingPermission + && !TextUtils.equals(route.getId(), defaultRouteId)) { + routerRecord.mUserRecord.mHandler.sendMessage( + obtainMessage(UserHandler::notifySessionCreationFailedToRouter, + routerRecord.mUserRecord.mHandler, + routerRecord, toOriginalRequestId(DUMMY_REQUEST_ID))); + } else { + routerRecord.mUserRecord.mHandler.sendMessage( + obtainMessage(UserHandler::transferToRouteOnHandler, + routerRecord.mUserRecord.mHandler, + DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route)); + } } private void setSessionVolumeWithRouter2Locked(@NonNull IMediaRouter2 router, @@ -808,7 +843,7 @@ class MediaRouter2ServiceImpl { return; } - // Can be null if the session is system's. + // Can be null if the session is system's or RCN. RouterRecord routerRecord = managerRecord.mUserRecord.mHandler .findRouterforSessionLocked(uniqueSessionId); @@ -829,7 +864,7 @@ class MediaRouter2ServiceImpl { return; } - // Can be null if the session is system's. + // Can be null if the session is system's or RCN. RouterRecord routerRecord = managerRecord.mUserRecord.mHandler .findRouterforSessionLocked(uniqueSessionId); @@ -850,7 +885,7 @@ class MediaRouter2ServiceImpl { return; } - // Can be null if the session is system's. + // Can be null if the session is system's or RCN. RouterRecord routerRecord = managerRecord.mUserRecord.mHandler .findRouterforSessionLocked(uniqueSessionId); @@ -890,9 +925,6 @@ class MediaRouter2ServiceImpl { RouterRecord routerRecord = managerRecord.mUserRecord.mHandler .findRouterforSessionLocked(uniqueSessionId); - if (routerRecord == null) { - return; - } long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId); managerRecord.mUserRecord.mHandler.sendMessage( @@ -1185,18 +1217,42 @@ class MediaRouter2ServiceImpl { } } - List<IMediaRouter2> routers = getRouters(); + List<IMediaRouter2> routersWithModifyAudioRoutingPermission = getRouters(true); + List<IMediaRouter2> routersWithoutModifyAudioRoutingPermission = getRouters(false); List<IMediaRouter2Manager> managers = getManagers(); + List<MediaRoute2Info> defaultRoute = new ArrayList<>(); + defaultRoute.add(mSystemProvider.getDefaultRoute()); + if (addedRoutes.size() > 0) { - notifyRoutesAddedToRouters(routers, addedRoutes); + notifyRoutesAddedToRouters(routersWithModifyAudioRoutingPermission, addedRoutes); + if (!provider.mIsSystemRouteProvider) { + notifyRoutesAddedToRouters(routersWithoutModifyAudioRoutingPermission, + addedRoutes); + } else if (prevInfo == null) { + notifyRoutesAddedToRouters(routersWithoutModifyAudioRoutingPermission, + defaultRoute); + } // 'else' is handled as changed routes notifyRoutesAddedToManagers(managers, addedRoutes); } if (removedRoutes.size() > 0) { - notifyRoutesRemovedToRouters(routers, removedRoutes); + notifyRoutesRemovedToRouters(routersWithModifyAudioRoutingPermission, + removedRoutes); + if (!provider.mIsSystemRouteProvider) { + notifyRoutesRemovedToRouters(routersWithoutModifyAudioRoutingPermission, + removedRoutes); + } notifyRoutesRemovedToManagers(managers, removedRoutes); } if (changedRoutes.size() > 0) { - notifyRoutesChangedToRouters(routers, changedRoutes); + notifyRoutesChangedToRouters(routersWithModifyAudioRoutingPermission, + changedRoutes); + if (!provider.mIsSystemRouteProvider) { + notifyRoutesChangedToRouters(routersWithoutModifyAudioRoutingPermission, + changedRoutes); + } else if (prevInfo != null) { + notifyRoutesChangedToRouters(routersWithoutModifyAudioRoutingPermission, + defaultRoute); + } // 'else' is handled as added routes notifyRoutesChangedToManagers(managers, changedRoutes); } } @@ -1232,7 +1288,7 @@ class MediaRouter2ServiceImpl { route.getOriginalId(), sessionHints); } - // routerRecord can be null if the session is system's. + // routerRecord can be null if the session is system's or RCN. private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord, @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route, @@ -1250,7 +1306,7 @@ class MediaRouter2ServiceImpl { route.getOriginalId()); } - // routerRecord can be null if the session is system's. + // routerRecord can be null if the session is system's or RCN. private void deselectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord, @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { @@ -1270,7 +1326,7 @@ class MediaRouter2ServiceImpl { route.getOriginalId()); } - // routerRecord can be null if the session is system's. + // routerRecord can be null if the session is system's or RCN. private void transferToRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord, @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) { @@ -1289,6 +1345,8 @@ class MediaRouter2ServiceImpl { route.getOriginalId()); } + // routerRecord is null if and only if the session is created without the request, which + // includes the system's session and RCN cases. private boolean checkArgumentsForSessionControl(@Nullable RouterRecord routerRecord, @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route, @NonNull String description) { @@ -1305,12 +1363,6 @@ class MediaRouter2ServiceImpl { return true; } - //TODO(b/152950479): Handle RCN case. - if (routerRecord == null) { - Slog.w(TAG, "Ignoring " + description + " route from unknown router."); - return false; - } - RouterRecord matchingRecord = mSessionToRouterMap.get(uniqueSessionId); if (matchingRecord != routerRecord) { Slog.w(TAG, "Ignoring " + description + " route from non-matching router. " @@ -1350,11 +1402,11 @@ class MediaRouter2ServiceImpl { } private void releaseSessionOnHandler(long uniqueRequestId, - @NonNull RouterRecord routerRecord, @NonNull String uniqueSessionId) { + @Nullable RouterRecord routerRecord, @NonNull String uniqueSessionId) { final RouterRecord matchingRecord = mSessionToRouterMap.get(uniqueSessionId); if (matchingRecord != routerRecord) { - Slog.w(TAG, "Ignoring releasing session from non-matching router." - + " packageName=" + routerRecord.mPackageName + Slog.w(TAG, "Ignoring releasing session from non-matching router. packageName=" + + (routerRecord == null ? null : routerRecord.mPackageName) + " uniqueSessionId=" + uniqueSessionId); return; } @@ -1448,7 +1500,9 @@ class MediaRouter2ServiceImpl { if (service == null) { return; } - notifySessionInfoChangedToRouters(getRouters(), sessionInfo); + notifySessionInfoChangedToRouters(getRouters(true), sessionInfo); + notifySessionInfoChangedToRouters(getRouters(false), + mSystemProvider.getDefaultSessionInfo()); return; } @@ -1569,7 +1623,7 @@ class MediaRouter2ServiceImpl { } } - private List<IMediaRouter2> getRouters() { + private List<IMediaRouter2> getAllRouters() { final List<IMediaRouter2> routers = new ArrayList<>(); MediaRouter2ServiceImpl service = mServiceRef.get(); if (service == null) { @@ -1583,6 +1637,23 @@ class MediaRouter2ServiceImpl { return routers; } + private List<IMediaRouter2> getRouters(boolean hasModifyAudioRoutingPermission) { + final List<IMediaRouter2> routers = new ArrayList<>(); + MediaRouter2ServiceImpl service = mServiceRef.get(); + if (service == null) { + return routers; + } + synchronized (service.mLock) { + for (RouterRecord routerRecord : mUserRecord.mRouterRecords) { + if (hasModifyAudioRoutingPermission + == routerRecord.mHasModifyAudioRoutingPermission) { + routers.add(routerRecord.mRouter); + } + } + } + return routers; + } + private List<IMediaRouter2Manager> getManagers() { final List<IMediaRouter2Manager> managers = new ArrayList<>(); MediaRouter2ServiceImpl service = mServiceRef.get(); diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 5b16d686e04c..6e2feeb15e21 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -72,6 +72,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { // This should be the currently selected route. MediaRoute2Info mDefaultRoute; MediaRoute2Info mDeviceRoute; + RoutingSessionInfo mDefaultSessionInfo; final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() { @@ -114,6 +115,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } }); updateSessionInfosIfNeeded(); + mContext.registerReceiver(new VolumeChangeReceiver(), new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); @@ -156,6 +158,10 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { @Override public void transferToRoute(long requestId, String sessionId, String routeId) { + if (TextUtils.equals(routeId, DEFAULT_ROUTE_ID)) { + // The currently selected route is the default route. + return; + } if (mBtRouteProvider != null) { if (TextUtils.equals(routeId, mDeviceRoute.getId())) { mBtRouteProvider.transferTo(null); @@ -182,6 +188,10 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { return mDefaultRoute; } + public RoutingSessionInfo getDefaultSessionInfo() { + return mDefaultSessionInfo; + } + private void updateDeviceRoute(AudioRoutesInfo newRoutes) { int name = R.string.default_audio_route_name; if (newRoutes != null) { @@ -229,8 +239,6 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { */ boolean updateSessionInfosIfNeeded() { synchronized (mLock) { - // Prevent to execute this method before mBtRouteProvider is created. - if (mBtRouteProvider == null) return false; RoutingSessionInfo oldSessionInfo = mSessionInfos.isEmpty() ? null : mSessionInfos.get( 0); @@ -238,14 +246,19 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { SYSTEM_SESSION_ID, "" /* clientPackageName */) .setSystemSession(true); - MediaRoute2Info selectedRoute = mBtRouteProvider.getSelectedRoute(); - if (selectedRoute == null) { - selectedRoute = mDeviceRoute; - } else { - builder.addTransferableRoute(mDeviceRoute.getId()); + MediaRoute2Info selectedRoute = mDeviceRoute; + if (mBtRouteProvider != null) { + MediaRoute2Info selectedBtRoute = mBtRouteProvider.getSelectedRoute(); + if (selectedBtRoute != null) { + selectedRoute = selectedBtRoute; + builder.addTransferableRoute(mDeviceRoute.getId()); + } } mSelectedRouteId = selectedRoute.getId(); - mDefaultRoute = new MediaRoute2Info.Builder(DEFAULT_ROUTE_ID, selectedRoute).build(); + mDefaultRoute = new MediaRoute2Info.Builder(DEFAULT_ROUTE_ID, selectedRoute) + .setSystemRoute(true) + .setProviderId(mUniqueId) + .build(); builder.addSelectedRoute(mSelectedRouteId); for (MediaRoute2Info route : mBtRouteProvider.getTransferableRoutes()) { @@ -258,6 +271,12 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } else { mSessionInfos.clear(); mSessionInfos.add(newSessionInfo); + mDefaultSessionInfo = new RoutingSessionInfo.Builder( + SYSTEM_SESSION_ID, "" /* clientPackageName */) + .setProviderId(mUniqueId) + .setSystemSession(true) + .addSelectedRoute(DEFAULT_ROUTE_ID) + .build(); return true; } } @@ -302,6 +321,9 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } else if (mBtRouteProvider != null) { mBtRouteProvider.setSelectedRouteVolume(newVolume); } + mDefaultRoute = new MediaRoute2Info.Builder(mDefaultRoute) + .setVolume(newVolume) + .build(); publishProviderState(); } } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 173dfc244fe5..ec941c8aea59 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -800,7 +800,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, true); - setRestrictBackgroundUL(mLoadedRestrictBackground); + setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service"); updateRulesForGlobalChangeAL(false); updateNotificationsNL(); } @@ -2877,10 +2877,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setRestrictBackground"); try { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); + final int callingUid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { synchronized (mUidRulesFirstLock) { - setRestrictBackgroundUL(restrictBackground); + setRestrictBackgroundUL(restrictBackground, "uid:" + callingUid); } } finally { Binder.restoreCallingIdentity(token); @@ -2891,7 +2892,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @GuardedBy("mUidRulesFirstLock") - private void setRestrictBackgroundUL(boolean restrictBackground) { + private void setRestrictBackgroundUL(boolean restrictBackground, String reason) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setRestrictBackgroundUL"); try { if (restrictBackground == mRestrictBackground) { @@ -2899,7 +2900,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Slog.w(TAG, "setRestrictBackgroundUL: already " + restrictBackground); return; } - Slog.d(TAG, "setRestrictBackgroundUL(): " + restrictBackground); + Slog.d(TAG, "setRestrictBackgroundUL(): " + restrictBackground + "; reason: " + reason); final boolean oldRestrictBackground = mRestrictBackground; mRestrictBackground = restrictBackground; // Must whitelist foreground apps before turning data saver mode on. @@ -3425,7 +3426,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.print("Restrict background: "); fout.println(mRestrictBackground); fout.print("Restrict power: "); fout.println(mRestrictPower); fout.print("Device idle: "); fout.println(mDeviceIdleMode); - fout.print("Metered ifaces: "); fout.println(String.valueOf(mMeteredIfaces)); + fout.print("Metered ifaces: "); fout.println(mMeteredIfaces); + + fout.println(); + fout.print("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode); + fout.print("mRestrictBackgroundBeforeBsm: " + mRestrictBackgroundBeforeBsm); + fout.print("mLoadedRestrictBackground: " + mLoadedRestrictBackground); + fout.print("mRestrictBackgroundChangedInBsm: " + mRestrictBackgroundChangedInBsm); fout.println(); fout.println("Network policies:"); @@ -5020,7 +5027,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } if (shouldInvokeRestrictBackground) { - setRestrictBackgroundUL(restrictBackground); + setRestrictBackgroundUL(restrictBackground, "low_power"); } // Change it at last so setRestrictBackground() won't affect this variable diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java new file mode 100644 index 000000000000..0bdf3f22ee9a --- /dev/null +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -0,0 +1,211 @@ +/* + * 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.server.net; + +import static android.net.NetworkTemplate.getCollapsedRatType; + +import android.annotation.NonNull; +import android.content.Context; +import android.telephony.Annotation; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; + +/** + * Helper class that watches for events that are triggered per subscription. + */ +// TODO (b/152176562): Write tests to verify subscription changes generate corresponding +// register/unregister calls. +public class NetworkStatsSubscriptionsMonitor extends + SubscriptionManager.OnSubscriptionsChangedListener { + + /** + * Interface that this monitor uses to delegate event handling to NetworkStatsService. + */ + public interface Delegate { + /** + * Notify that the collapsed RAT type has been changed for any subscription. The method + * will also be triggered for any existing sub when start and stop monitoring. + * + * @param subscriberId IMSI of the subscription. + * @param collapsedRatType collapsed RAT type. + * @see android.net.NetworkTemplate#getCollapsedRatType(int). + */ + void onCollapsedRatTypeChanged(@NonNull String subscriberId, + @Annotation.NetworkType int collapsedRatType); + } + private final Delegate mDelegate; + + /** + * Receivers that watches for {@link ServiceState} changes for each subscription, to + * monitor the transitioning between Radio Access Technology(RAT) types for each sub. + */ + @NonNull + private final CopyOnWriteArrayList<RatTypeListener> mRatListeners = + new CopyOnWriteArrayList<>(); + + @NonNull + private final SubscriptionManager mSubscriptionManager; + @NonNull + private final TelephonyManager mTeleManager; + + @NonNull + private final Executor mExecutor; + + NetworkStatsSubscriptionsMonitor(@NonNull Context context, @NonNull Executor executor, + @NonNull Delegate delegate) { + super(); + mSubscriptionManager = (SubscriptionManager) context.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + mExecutor = executor; + mDelegate = delegate; + } + + @Override + public void onSubscriptionsChanged() { + // Collect active subId list, hidden subId such as opportunistic subscriptions are + // also needed to track CBRS. + final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager); + + for (final int subId : newSubs) { + final RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> it.mSubId == subId); + if (match != null) continue; + + // Create listener for every newly added sub. Also store subscriberId into it to + // prevent binder call to telephony when querying RAT. + final String subscriberId = mTeleManager.getSubscriberId(subId); + if (TextUtils.isEmpty(subscriberId)) { + Log.wtf(NetworkStatsService.TAG, + "Empty subscriberId for newly added sub: " + subId); + } + final RatTypeListener listener = + new RatTypeListener(mExecutor, this, subId, subscriberId); + mRatListeners.add(listener); + + // Register listener to the telephony manager that associated with specific sub. + mTeleManager.createForSubscriptionId(subId) + .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); + } + + for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { + // If the new list contains the subId of the listener, keeps it. + final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId); + if (match != null) continue; + + handleRemoveRatTypeListener(listener); + } + } + + @NonNull + private List<Integer> getActiveSubIdList(@NonNull SubscriptionManager subscriptionManager) { + final ArrayList<Integer> ret = new ArrayList<>(); + final int[] ids = subscriptionManager.getCompleteActiveSubscriptionIdList(); + for (int id : ids) ret.add(id); + return ret; + } + + /** + * Get a collapsed RatType for the given subscriberId. + * + * @param subscriberId the target subscriberId + * @return collapsed RatType for the given subscriberId + */ + public int getRatTypeForSubscriberId(@NonNull String subscriberId) { + final RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> TextUtils.equals(subscriberId, it.mSubscriberId)); + return match != null ? match.mLastCollapsedRatType : TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + + /** + * Start monitoring events that triggered per subscription. + */ + public void start() { + mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, this); + } + + /** + * Unregister subscription changes and all listeners for each subscription. + */ + public void stop() { + mSubscriptionManager.removeOnSubscriptionsChangedListener(this); + + for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { + handleRemoveRatTypeListener(listener); + } + } + + private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { + mTeleManager.createForSubscriptionId(listener.mSubId) + .listen(listener, PhoneStateListener.LISTEN_NONE); + mRatListeners.remove(listener); + + // Removal of subscriptions doesn't generate RAT changed event, fire it for every + // RatTypeListener. + mDelegate.onCollapsedRatTypeChanged( + listener.mSubscriberId, TelephonyManager.NETWORK_TYPE_UNKNOWN); + } + + static class RatTypeListener extends PhoneStateListener { + // Unique id for the subscription. See {@link SubscriptionInfo#getSubscriptionId}. + @NonNull + private final int mSubId; + + // IMSI to identifying the corresponding network from {@link NetworkState}. + // See {@link TelephonyManager#getSubscriberId}. + @NonNull + private final String mSubscriberId; + + private volatile int mLastCollapsedRatType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + @NonNull + private final NetworkStatsSubscriptionsMonitor mMonitor; + + RatTypeListener(@NonNull Executor executor, + @NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, + @NonNull String subscriberId) { + super(executor); + mSubId = subId; + mSubscriberId = subscriberId; + mMonitor = monitor; + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState ss) { + final int networkType = ss.getDataNetworkType(); + final int collapsedRatType = getCollapsedRatType(networkType); + if (collapsedRatType == mLastCollapsedRatType) return; + + if (NetworkStatsService.LOGD) { + Log.d(NetworkStatsService.TAG, "subtype changed for sub(" + mSubId + "): " + + mLastCollapsedRatType + " -> " + collapsedRatType); + } + mLastCollapsedRatType = collapsedRatType; + mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType); + } + } +} diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java index 2fa80cd8e4e4..27802ffc013d 100644 --- a/services/core/java/com/android/server/notification/BubbleExtractor.java +++ b/services/core/java/com/android/server/notification/BubbleExtractor.java @@ -16,12 +16,18 @@ package com.android.server.notification; import static android.app.Notification.FLAG_BUBBLE; +import static android.app.Notification.FLAG_FOREGROUND_SERVICE; +import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; import static com.android.internal.util.FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING; import static com.android.internal.util.FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE; import android.app.ActivityManager; import android.app.Notification; +import android.app.NotificationChannel; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -32,13 +38,13 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; /** - * Determines whether a bubble can be shown for this notification + * Determines whether a bubble can be shown for this notification. */ public class BubbleExtractor implements NotificationSignalExtractor { private static final String TAG = "BubbleExtractor"; private static final boolean DBG = false; - private BubbleChecker mBubbleChecker; + private ShortcutHelper mShortcutHelper; private RankingConfig mConfig; private ActivityManager mActivityManager; private Context mContext; @@ -60,24 +66,35 @@ public class BubbleExtractor implements NotificationSignalExtractor { return null; } - if (mBubbleChecker == null) { - if (DBG) Slog.d(TAG, "missing bubble checker"); + if (mShortcutHelper == null) { + if (DBG) Slog.d(TAG, "missing shortcut helper"); return null; } - boolean appCanShowBubble = - mConfig.areBubblesAllowed(record.getSbn().getPackageName(), record.getSbn().getUid()); - if (!mConfig.bubblesEnabled() || !appCanShowBubble) { + int bubblePreference = + mConfig.getBubblePreference( + record.getSbn().getPackageName(), record.getSbn().getUid()); + NotificationChannel recordChannel = record.getChannel(); + + if (!mConfig.bubblesEnabled() || bubblePreference == BUBBLE_PREFERENCE_NONE) { record.setAllowBubble(false); - } else { - if (record.getChannel() != null) { - record.setAllowBubble(record.getChannel().canBubble() && appCanShowBubble); - } else { - record.setAllowBubble(appCanShowBubble); - } + } else if (recordChannel == null) { + // the app is allowed but there's no channel to check + record.setAllowBubble(true); + } else if (bubblePreference == BUBBLE_PREFERENCE_ALL) { + // by default the channel is not allowed, only don't bubble if the user specified + boolean userLockedNoBubbles = !recordChannel.canBubble() + && (recordChannel.getUserLockedFields() & USER_LOCKED_ALLOW_BUBBLE) != 0; + record.setAllowBubble(!userLockedNoBubbles); + } else if (bubblePreference == BUBBLE_PREFERENCE_SELECTED) { + record.setAllowBubble(recordChannel.canBubble()); } - final boolean applyFlag = mBubbleChecker.isNotificationAppropriateToBubble(record) - && !record.isFlagBubbleRemoved(); + + final boolean fulfillsPolicy = record.canBubble() + && record.isConversation() + && !mActivityManager.isLowRamDevice() + && (record.getNotification().flags & FLAG_FOREGROUND_SERVICE) == 0; + final boolean applyFlag = fulfillsPolicy && canPresentAsBubble(record); if (applyFlag) { record.getNotification().flags |= FLAG_BUBBLE; } else { @@ -95,165 +112,95 @@ public class BubbleExtractor implements NotificationSignalExtractor { public void setZenHelper(ZenModeHelper helper) { } - /** - * Expected to be called after {@link #setConfig(RankingConfig)} has occurred. - */ - void setShortcutHelper(ShortcutHelper helper) { - if (mConfig == null) { - if (DBG) Slog.d(TAG, "setting shortcut helper prior to setConfig"); - return; - } - mBubbleChecker = new BubbleChecker(mContext, helper, mConfig, mActivityManager); + public void setShortcutHelper(ShortcutHelper helper) { + mShortcutHelper = helper; } @VisibleForTesting - void setBubbleChecker(BubbleChecker checker) { - mBubbleChecker = checker; + public void setActivityManager(ActivityManager manager) { + mActivityManager = manager; } /** - * Encapsulates special checks to see if a notification can be flagged as a bubble. This - * makes testing a bit easier. + * @return whether there is valid information for the notification to bubble. */ - public static class BubbleChecker { - - private ActivityManager mActivityManager; - private RankingConfig mRankingConfig; - private Context mContext; - private ShortcutHelper mShortcutHelper; - - BubbleChecker(Context context, ShortcutHelper helper, RankingConfig config, - ActivityManager activityManager) { - mContext = context; - mActivityManager = activityManager; - mShortcutHelper = helper; - mRankingConfig = config; + @VisibleForTesting + boolean canPresentAsBubble(NotificationRecord r) { + Notification notification = r.getNotification(); + Notification.BubbleMetadata metadata = notification.getBubbleMetadata(); + String pkg = r.getSbn().getPackageName(); + if (metadata == null) { + return false; } - /** - * @return whether the provided notification record is allowed to be represented as a - * bubble, accounting for user choice & policy. - */ - public boolean isNotificationAppropriateToBubble(NotificationRecord r) { - final String pkg = r.getSbn().getPackageName(); - final int userId = r.getSbn().getUser().getIdentifier(); - Notification notification = r.getNotification(); - if (!canBubble(r, pkg, userId)) { - // no log: canBubble has its own - return false; - } - - if (mActivityManager.isLowRamDevice()) { - logBubbleError(r.getKey(), "low ram device"); - return false; - } - - boolean isMessageStyle = Notification.MessagingStyle.class.equals( - notification.getNotificationStyle()); - if (!isMessageStyle) { - logBubbleError(r.getKey(), "must be Notification.MessageStyle"); - return false; - } + String shortcutId = metadata.getShortcutId(); + String notificationShortcutId = r.getShortcutInfo() != null + ? r.getShortcutInfo().getId() + : null; + boolean shortcutValid = false; + if (notificationShortcutId != null && shortcutId != null) { + // NoMan already checks validity of shortcut, just check if they match. + shortcutValid = shortcutId.equals(notificationShortcutId); + } else if (shortcutId != null) { + shortcutValid = + mShortcutHelper.getValidShortcutInfo(shortcutId, pkg, r.getUser()) != null; + } + if (metadata.getIntent() == null && !shortcutValid) { + // Should have a shortcut if intent is null + logBubbleError(r.getKey(), + "couldn't find valid shortcut for bubble with shortcutId: " + shortcutId); + return false; + } + if (shortcutValid) { + // TODO: check the shortcut intent / ensure it can show in activity view return true; } + return canLaunchInActivityView(mContext, metadata.getIntent(), pkg); + } - /** - * @return whether the user has enabled the provided notification to bubble, and if the - * developer has provided valid information for the notification to bubble. - */ - @VisibleForTesting - boolean canBubble(NotificationRecord r, String pkg, int userId) { - Notification notification = r.getNotification(); - Notification.BubbleMetadata metadata = notification.getBubbleMetadata(); - if (metadata == null) { - // no log: no need to inform dev if they didn't attach bubble metadata - return false; - } - if (!mRankingConfig.bubblesEnabled()) { - logBubbleError(r.getKey(), "bubbles disabled for user: " + userId); - return false; - } - if (!mRankingConfig.areBubblesAllowed(pkg, userId)) { - logBubbleError(r.getKey(), - "bubbles for package: " + pkg + " disabled for user: " + userId); - return false; - } - if (!r.getChannel().canBubble()) { - logBubbleError(r.getKey(), - "bubbles for channel " + r.getChannel().getId() + " disabled"); - return false; - } - - String shortcutId = metadata.getShortcutId(); - String notificationShortcutId = r.getShortcutInfo() != null - ? r.getShortcutInfo().getId() - : null; - boolean shortcutValid = false; - if (notificationShortcutId != null && shortcutId != null) { - // NoMan already checks validity of shortcut, just check if they match. - shortcutValid = shortcutId.equals(notificationShortcutId); - } else if (shortcutId != null) { - shortcutValid = - mShortcutHelper.getValidShortcutInfo(shortcutId, pkg, r.getUser()) != null; - } - if (metadata.getIntent() == null && !shortcutValid) { - // Should have a shortcut if intent is null - logBubbleError(r.getKey(), - "couldn't find valid shortcut for bubble with shortcutId: " + shortcutId); - return false; - } - if (shortcutValid) { - return true; - } - // no log: canLaunch method has the failure log - return canLaunchInActivityView(mContext, metadata.getIntent(), pkg); + /** + * Whether an intent is properly configured to display in an {@link + * android.app.ActivityView} for bubbling. + * + * @param context the context to use. + * @param pendingIntent the pending intent of the bubble. + * @param packageName the notification package name for this bubble. + */ + // Keep checks in sync with BubbleController#canLaunchInActivityView. + @VisibleForTesting + protected boolean canLaunchInActivityView(Context context, PendingIntent pendingIntent, + String packageName) { + if (pendingIntent == null) { + Slog.w(TAG, "Unable to create bubble -- no intent"); + return false; } - /** - * Whether an intent is properly configured to display in an {@link - * android.app.ActivityView}. - * - * @param context the context to use. - * @param pendingIntent the pending intent of the bubble. - * @param packageName the notification package name for this bubble. - */ - // Keep checks in sync with BubbleController#canLaunchInActivityView. - @VisibleForTesting - protected boolean canLaunchInActivityView(Context context, PendingIntent pendingIntent, - String packageName) { - if (pendingIntent == null) { - Slog.w(TAG, "Unable to create bubble -- no intent"); - return false; - } - - Intent intent = pendingIntent.getIntent(); - - ActivityInfo info = intent != null - ? intent.resolveActivityInfo(context.getPackageManager(), 0) - : null; - if (info == null) { - FrameworkStatsLog.write(FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, - packageName, - BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING); - Slog.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: " - + intent); - return false; - } - if (!ActivityInfo.isResizeableMode(info.resizeMode)) { - FrameworkStatsLog.write(FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, - packageName, - BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE); - Slog.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: " - + intent); - return false; - } - return true; + Intent intent = pendingIntent.getIntent(); + ActivityInfo info = intent != null + ? intent.resolveActivityInfo(context.getPackageManager(), 0) + : null; + if (info == null) { + FrameworkStatsLog.write(FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, + packageName, + BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING); + Slog.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: " + + intent); + return false; + } + if (!ActivityInfo.isResizeableMode(info.resizeMode)) { + FrameworkStatsLog.write(FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, + packageName, + BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE); + Slog.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: " + + intent); + return false; } + return true; + } - private void logBubbleError(String key, String failureMessage) { - if (DBG) { - Slog.w(TAG, "Bubble notification: " + key + " failed: " + failureMessage); - } + private void logBubbleError(String key, String failureMessage) { + if (DBG) { + Slog.w(TAG, "Bubble notification: " + key + " failed: " + failureMessage); } } } diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index b8140be2e266..1051423ea17f 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -51,7 +51,7 @@ public interface NotificationDelegate { /** * Called when the state of {@link Notification#FLAG_BUBBLE} is changed. */ - void onNotificationBubbleChanged(String key, boolean isBubble); + void onNotificationBubbleChanged(String key, boolean isBubble, int flags); /** * Called when the state of {@link Notification.BubbleMetadata#FLAG_SUPPRESS_NOTIFICATION} * changes. diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index f9fc82bf05b1..54efe543a29f 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -32,6 +32,7 @@ import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED; import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED; import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID; import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS; import static android.app.NotificationManager.IMPORTANCE_LOW; @@ -1195,14 +1196,7 @@ public class NotificationManagerService extends SystemService { } @Override - public void onNotificationBubbleChanged(String key, boolean isBubble) { - String pkg; - synchronized (mNotificationLock) { - NotificationRecord r = mNotificationsByKey.get(key); - pkg = r != null && r.getSbn() != null ? r.getSbn().getPackageName() : null; - } - boolean isAppForeground = pkg != null - && mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; + public void onNotificationBubbleChanged(String key, boolean isBubble, int flags) { synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); if (r != null) { @@ -1219,8 +1213,13 @@ public class NotificationManagerService extends SystemService { // be applied there. r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; r.setFlagBubbleRemoved(false); + if (r.getNotification().getBubbleMetadata() != null) { + r.getNotification().getBubbleMetadata().setFlags(flags); + } + // Force isAppForeground true here, because for sysui's purposes we + // want to adjust the flag behaviour. mHandler.post(new EnqueueNotificationRunnable(r.getUser().getIdentifier(), - r, isAppForeground)); + r, true /* isAppForeground*/)); } } } @@ -3079,40 +3078,37 @@ public class NotificationManagerService extends SystemService { return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE; } + /** + * @return true if and only if "all" bubbles are allowed from the provided package. + */ @Override public boolean areBubblesAllowed(String pkg) { - return areBubblesAllowedForPackage(pkg, Binder.getCallingUid()); + return getBubblePreferenceForPackage(pkg, Binder.getCallingUid()) + == BUBBLE_PREFERENCE_ALL; } @Override - public boolean areBubblesAllowedForPackage(String pkg, int uid) { + public int getBubblePreferenceForPackage(String pkg, int uid) { enforceSystemOrSystemUIOrSamePackage(pkg, "Caller not system or systemui or same package"); if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { getContext().enforceCallingPermission( android.Manifest.permission.INTERACT_ACROSS_USERS, - "canNotifyAsPackage for uid " + uid); + "getBubblePreferenceForPackage for uid " + uid); } - return mPreferencesHelper.areBubblesAllowed(pkg, uid); + return mPreferencesHelper.getBubblePreference(pkg, uid); } @Override - public void setBubblesAllowed(String pkg, int uid, boolean allowed) { - enforceSystemOrSystemUI("Caller not system or systemui"); - mPreferencesHelper.setBubblesAllowed(pkg, uid, allowed); + public void setBubblesAllowed(String pkg, int uid, int bubblePreference) { + checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell"); + mPreferencesHelper.setBubblesAllowed(pkg, uid, bubblePreference); handleSavePolicyFile(); } @Override - public boolean hasUserApprovedBubblesForPackage(String pkg, int uid) { - enforceSystemOrSystemUI("Caller not system or systemui"); - int lockedFields = mPreferencesHelper.getAppLockedFields(pkg, uid); - return (lockedFields & PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE) != 0; - } - - @Override public boolean shouldHideSilentStatusIcons(String callingPkg) { checkCallerIsSameApp(callingPkg); @@ -3308,7 +3304,7 @@ public class NotificationManagerService extends SystemService { String targetPkg, String channelId, boolean returnParentIfNoConversationChannel, String conversationId) { if (canNotifyAsPackage(callingPkg, targetPkg, userId) - || isCallerIsSystemOrSystemUi()) { + || isCallerIsSystemOrSysemUiOrShell()) { int targetUid = -1; try { targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId); @@ -3418,7 +3414,7 @@ public class NotificationManagerService extends SystemService { @Override public void updateNotificationChannelForPackage(String pkg, int uid, NotificationChannel channel) { - enforceSystemOrSystemUI("Caller not system or systemui"); + checkCallerIsSystemOrSystemUiOrShell("Caller not system or sysui or shell"); Objects.requireNonNull(channel); updateNotificationChannelInt(pkg, uid, channel, false); } @@ -5848,6 +5844,7 @@ public class NotificationManagerService extends SystemService { synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); if (r != null) { + r.setShortcutInfo(null); // Enqueue will trigger resort & flag is updated that way. r.getNotification().flags |= FLAG_ONLY_ALERT_ONCE; mHandler.post( @@ -7210,7 +7207,10 @@ public class NotificationManagerService extends SystemService { boolean interruptiveChanged = record.canBubble() && (interruptiveBefore != record.isInterruptive()); - changed = indexChanged || interceptChanged || visibilityChanged || interruptiveChanged; + changed = indexChanged + || interceptChanged + || visibilityChanged + || interruptiveChanged; if (interceptBefore && !record.isIntercepted() && record.isNewEnoughForAlerting(System.currentTimeMillis())) { buzzBeepBlinkLocked(record); @@ -8248,6 +8248,14 @@ public class NotificationManagerService extends SystemService { == PERMISSION_GRANTED; } + private boolean isCallerIsSystemOrSysemUiOrShell() { + int callingUid = Binder.getCallingUid(); + if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { + return true; + } + return isCallerIsSystemOrSystemUi(); + } + private void checkCallerIsSystemOrShell() { int callingUid = Binder.getCallingUid(); if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { @@ -8264,6 +8272,10 @@ public class NotificationManagerService extends SystemService { } private void checkCallerIsSystemOrSystemUiOrShell() { + checkCallerIsSystemOrSystemUiOrShell(null); + } + + private void checkCallerIsSystemOrSystemUiOrShell(String message) { int callingUid = Binder.getCallingUid(); if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { return; @@ -8271,7 +8283,8 @@ public class NotificationManagerService extends SystemService { if (isCallerSystemOrPhone()) { return; } - getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, null); + getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, + message); } private void checkCallerIsSystemOrSameApp(String pkg) { diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java index 2b5ba2528429..e4a17740b0b7 100644 --- a/services/core/java/com/android/server/notification/NotificationShellCmd.java +++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java @@ -38,7 +38,6 @@ import android.content.res.Resources; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; -import android.media.IRingtonePlayer; import android.net.Uri; import android.os.Binder; import android.os.Process; @@ -48,8 +47,6 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.Slog; -import com.android.internal.util.FunctionalUtils; - import java.io.PrintWriter; import java.net.URISyntaxException; import java.util.Collections; @@ -72,7 +69,11 @@ public class NotificationShellCmd extends ShellCommand { + " unsuspend_package PACKAGE\n" + " reset_assistant_user_set [user_id (current user if not specified)]\n" + " get_approved_assistant [user_id (current user if not specified)]\n" - + " post [--help | flags] TAG TEXT"; + + " post [--help | flags] TAG TEXT\n" + + " set_bubbles PACKAGE PREFERENCE (0=none 1=all 2=selected) " + + "[user_id (current user if not specified)]\n" + + " set_bubbles_channel PACKAGE CHANNEL_ID ALLOW " + + "[user_id (current user if not specified)]\n"; private static final String NOTIFY_USAGE = "usage: cmd notification post [flags] <tag> <text>\n\n" @@ -109,6 +110,7 @@ public class NotificationShellCmd extends ShellCommand { private final NotificationManagerService mDirectService; private final INotificationManager mBinderService; private final PackageManager mPm; + private NotificationChannel mChannel; public NotificationShellCmd(NotificationManagerService service) { mDirectService = service; @@ -276,6 +278,40 @@ public class NotificationShellCmd extends ShellCommand { } break; } + case "set_bubbles": { + // only use for testing + String packageName = getNextArgRequired(); + int preference = Integer.parseInt(getNextArgRequired()); + if (preference > 3 || preference < 0) { + pw.println("Invalid preference - must be between 0-3 " + + "(0=none 1=all 2=selected)"); + return -1; + } + int userId = ActivityManager.getCurrentUser(); + if (peekNextArg() != null) { + userId = Integer.parseInt(getNextArgRequired()); + } + int appUid = UserHandle.getUid(userId, mPm.getPackageUid(packageName, 0)); + mBinderService.setBubblesAllowed(packageName, appUid, preference); + break; + } + case "set_bubbles_channel": { + // only use for testing + String packageName = getNextArgRequired(); + String channelId = getNextArgRequired(); + boolean allow = Boolean.parseBoolean(getNextArgRequired()); + int userId = ActivityManager.getCurrentUser(); + if (peekNextArg() != null) { + userId = Integer.parseInt(getNextArgRequired()); + } + NotificationChannel channel = mBinderService.getNotificationChannel( + callingPackage, userId, packageName, channelId); + channel.setAllowBubbles(allow); + int appUid = UserHandle.getUid(userId, mPm.getPackageUid(packageName, 0)); + mBinderService.updateNotificationChannelForPackage(packageName, appUid, + channel); + break; + } case "post": case "notify": doNotify(pw, callingPackage, callingUid); diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 8154988a4917..b3d373ffab3a 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -17,6 +17,7 @@ package com.android.server.notification; import static android.app.NotificationChannel.PLACEHOLDER_CONVERSATION_ID; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; @@ -117,10 +118,14 @@ public class PreferencesHelper implements RankingConfig { @VisibleForTesting static final boolean DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS = false; private static final boolean DEFAULT_SHOW_BADGE = true; - static final boolean DEFAULT_ALLOW_BUBBLE = true; + private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE = false; private static final boolean DEFAULT_APP_LOCKED_IMPORTANCE = false; + static final boolean DEFAULT_GLOBAL_ALLOW_BUBBLE = true; + @VisibleForTesting + static final int DEFAULT_BUBBLE_PREFERENCE = BUBBLE_PREFERENCE_NONE; + /** * Default value for what fields are user locked. See {@link LockableAppFields} for all lockable * fields. @@ -148,7 +153,7 @@ public class PreferencesHelper implements RankingConfig { private final NotificationChannelLogger mNotificationChannelLogger; private SparseBooleanArray mBadgingEnabled; - private boolean mBubblesEnabled = DEFAULT_ALLOW_BUBBLE; + private boolean mBubblesEnabledGlobally = DEFAULT_GLOBAL_ALLOW_BUBBLE; private boolean mAreChannelsBypassingDnd; private boolean mHideSilentStatusBarIcons = DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS; @@ -226,8 +231,8 @@ public class PreferencesHelper implements RankingConfig { parser, ATT_VISIBILITY, DEFAULT_VISIBILITY), XmlUtils.readBooleanAttribute( parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE), - XmlUtils.readBooleanAttribute( - parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE)); + XmlUtils.readIntAttribute( + parser, ATT_ALLOW_BUBBLE, DEFAULT_BUBBLE_PREFERENCE)); r.importance = XmlUtils.readIntAttribute( parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); r.priority = XmlUtils.readIntAttribute( @@ -339,19 +344,19 @@ public class PreferencesHelper implements RankingConfig { int uid) { return getOrCreatePackagePreferencesLocked(pkg, UserHandle.getUserId(uid), uid, DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE, - DEFAULT_ALLOW_BUBBLE); + DEFAULT_BUBBLE_PREFERENCE); } private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, @UserIdInt int userId, int uid) { return getOrCreatePackagePreferencesLocked(pkg, userId, uid, DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE, - DEFAULT_ALLOW_BUBBLE); + DEFAULT_BUBBLE_PREFERENCE); } private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, @UserIdInt int userId, int uid, int importance, int priority, int visibility, - boolean showBadge, boolean allowBubble) { + boolean showBadge, int bubblePreference) { final String key = packagePreferencesKey(pkg, uid); PackagePreferences r = (uid == UNKNOWN_UID) @@ -365,7 +370,7 @@ public class PreferencesHelper implements RankingConfig { r.priority = priority; r.visibility = visibility; r.showBadge = showBadge; - r.allowBubble = allowBubble; + r.bubblePreference = bubblePreference; try { createDefaultChannelIfNeededLocked(r); @@ -479,7 +484,7 @@ public class PreferencesHelper implements RankingConfig { || r.channels.size() > 0 || r.groups.size() > 0 || r.delegate != null - || r.allowBubble != DEFAULT_ALLOW_BUBBLE; + || r.bubblePreference != DEFAULT_BUBBLE_PREFERENCE; if (hasNonDefaultSettings) { out.startTag(null, TAG_PACKAGE); out.attribute(null, ATT_NAME, r.pkg); @@ -492,8 +497,8 @@ public class PreferencesHelper implements RankingConfig { if (r.visibility != DEFAULT_VISIBILITY) { out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility)); } - if (r.allowBubble != DEFAULT_ALLOW_BUBBLE) { - out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(r.allowBubble)); + if (r.bubblePreference != DEFAULT_BUBBLE_PREFERENCE) { + out.attribute(null, ATT_ALLOW_BUBBLE, Integer.toString(r.bubblePreference)); } out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(r.showBadge)); out.attribute(null, ATT_APP_USER_LOCKED_FIELDS, @@ -544,14 +549,14 @@ public class PreferencesHelper implements RankingConfig { * * @param pkg the package to allow or not allow bubbles for. * @param uid the uid to allow or not allow bubbles for. - * @param allowed whether bubbles are allowed. + * @param bubblePreference whether bubbles are allowed. */ - public void setBubblesAllowed(String pkg, int uid, boolean allowed) { + public void setBubblesAllowed(String pkg, int uid, int bubblePreference) { boolean changed = false; synchronized (mPackagePreferences) { PackagePreferences p = getOrCreatePackagePreferencesLocked(pkg, uid); - changed = p.allowBubble != allowed; - p.allowBubble = allowed; + changed = p.bubblePreference != bubblePreference; + p.bubblePreference = bubblePreference; p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_BUBBLE; } if (changed) { @@ -567,9 +572,9 @@ public class PreferencesHelper implements RankingConfig { * @return whether bubbles are allowed. */ @Override - public boolean areBubblesAllowed(String pkg, int uid) { + public int getBubblePreference(String pkg, int uid) { synchronized (mPackagePreferences) { - return getOrCreatePackagePreferencesLocked(pkg, uid).allowBubble; + return getOrCreatePackagePreferencesLocked(pkg, uid).bubblePreference; } } @@ -788,6 +793,7 @@ public class PreferencesHelper implements RankingConfig { } if (fromTargetApp) { channel.setLockscreenVisibility(r.visibility); + channel.setAllowBubbles(existing != null && existing.canBubble()); } clearLockedFieldsLocked(channel); channel.setImportanceLockedByOEM(r.oemLockedImportance); @@ -2125,7 +2131,7 @@ public class PreferencesHelper implements RankingConfig { p.groups = new ArrayMap<>(); p.delegate = null; p.lockedAppFields = DEFAULT_LOCKED_APP_FIELDS; - p.allowBubble = DEFAULT_ALLOW_BUBBLE; + p.bubblePreference = DEFAULT_BUBBLE_PREFERENCE; p.importance = DEFAULT_IMPORTANCE; p.priority = DEFAULT_PRIORITY; p.visibility = DEFAULT_VISIBILITY; @@ -2165,15 +2171,15 @@ public class PreferencesHelper implements RankingConfig { public void updateBubblesEnabled() { final boolean newValue = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.NOTIFICATION_BUBBLES, - DEFAULT_ALLOW_BUBBLE ? 1 : 0) == 1; - if (newValue != mBubblesEnabled) { - mBubblesEnabled = newValue; + DEFAULT_GLOBAL_ALLOW_BUBBLE ? 1 : 0) == 1; + if (newValue != mBubblesEnabledGlobally) { + mBubblesEnabledGlobally = newValue; updateConfig(); } } public boolean bubblesEnabled() { - return mBubblesEnabled; + return mBubblesEnabledGlobally; } public void updateBadgingEnabled() { @@ -2229,7 +2235,7 @@ public class PreferencesHelper implements RankingConfig { int priority = DEFAULT_PRIORITY; int visibility = DEFAULT_VISIBILITY; boolean showBadge = DEFAULT_SHOW_BADGE; - boolean allowBubble = DEFAULT_ALLOW_BUBBLE; + int bubblePreference = DEFAULT_BUBBLE_PREFERENCE; int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS; // these fields are loaded on boot from a different source of truth and so are not // written to notification policy xml diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java index 7e98be7fe065..7fc79e6a9bf7 100644 --- a/services/core/java/com/android/server/notification/RankingConfig.java +++ b/services/core/java/com/android/server/notification/RankingConfig.java @@ -29,7 +29,7 @@ public interface RankingConfig { void setShowBadge(String packageName, int uid, boolean showBadge); boolean canShowBadge(String packageName, int uid); boolean badgingEnabled(UserHandle userHandle); - boolean areBubblesAllowed(String packageName, int uid); + int getBubblePreference(String packageName, int uid); boolean bubblesEnabled(); boolean isGroupBlocked(String packageName, int uid, String groupId); diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java index 43fc7ed0e39d..90c85ada9def 100644 --- a/services/core/java/com/android/server/om/IdmapManager.java +++ b/services/core/java/com/android/server/om/IdmapManager.java @@ -63,20 +63,23 @@ class IdmapManager { mIdmapDaemon = IdmapDaemon.getInstance(); } + /** + * Creates the idmap for the target/overlay combination and returns whether the idmap file was + * modified. + */ boolean createIdmap(@NonNull final PackageInfo targetPackage, @NonNull final PackageInfo overlayPackage, int userId) { if (DEBUG) { Slog.d(TAG, "create idmap for " + targetPackage.packageName + " and " + overlayPackage.packageName); } - final int sharedGid = UserHandle.getSharedAppGid(targetPackage.applicationInfo.uid); final String targetPath = targetPackage.applicationInfo.getBaseCodePath(); final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath(); try { int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId); boolean enforce = enforceOverlayable(overlayPackage); if (mIdmapDaemon.verifyIdmap(targetPath, overlayPath, policies, enforce, userId)) { - return true; + return false; } return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies, enforce, userId) != null; diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index d108e76e37df..05a4a38feef1 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -700,14 +700,15 @@ final class OverlayManagerServiceImpl { final PackageInfo overlayPackage = mPackageManager.getPackageInfo(overlayPackageName, userId); - // Immutable RROs targeting to "android", ie framework-res.apk, are handled by native layers. + // Immutable RROs targeting to "android", ie framework-res.apk, are handled by native + // layers. + boolean modified = false; if (targetPackage != null && overlayPackage != null && !("android".equals(targetPackageName) && !isPackageConfiguredMutable(overlayPackageName))) { - mIdmapManager.createIdmap(targetPackage, overlayPackage, userId); + modified |= mIdmapManager.createIdmap(targetPackage, overlayPackage, userId); } - boolean modified = false; if (overlayPackage != null) { modified |= mSettings.setBaseCodePath(overlayPackageName, userId, overlayPackage.applicationInfo.getBaseCodePath()); diff --git a/services/core/java/com/android/server/om/TEST_MAPPING b/services/core/java/com/android/server/om/TEST_MAPPING index 75229a1adccc..6edd76f1810a 100644 --- a/services/core/java/com/android/server/om/TEST_MAPPING +++ b/services/core/java/com/android/server/om/TEST_MAPPING @@ -15,6 +15,9 @@ "name": "OverlayHostTests" }, { + "name": "OverlayRemountedTest" + }, + { "name": "CtsAppSecurityHostTestCases", "options": [ { diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index f06b50a9fdb0..daf4bf271ca2 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -30,7 +30,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; +import android.content.pm.PackageParser.PackageParserException; import android.content.pm.parsing.PackageInfoWithoutStateUtils; import android.os.Binder; import android.os.Environment; @@ -137,7 +137,8 @@ public abstract class ApexManager { /** * Called by package manager service to scan apex package files when device boots up. * - * @param packageParser The package parser which supports caches. + * @param packageParser The package parser to support apex package parsing and caching parsed + * results. * @param executorService An executor to support parallel package parsing. */ abstract void scanApexPackagesTraced(@NonNull PackageParser2 packageParser, @@ -398,7 +399,9 @@ public abstract class ApexManager { @VisibleForTesting protected IApexService waitForApexService() { try { - return IApexService.Stub.asInterface(Binder.waitForService("apexservice")); + // Since apexd is a trusted platform component, synchronized calls are allowable + return IApexService.Stub.asInterface( + Binder.allowBlocking(Binder.waitForService("apexservice"))); } catch (RemoteException e) { throw new IllegalStateException("Required service apexservice not available"); } @@ -505,7 +508,13 @@ public abstract class ApexManager { } factoryPackagesSet.add(packageInfo.packageName); } - } else if (throwable instanceof PackageParser.PackageParserException) { + } else if (throwable instanceof PackageParserException) { + final PackageParserException e = (PackageParserException) throwable; + // Skip parsing non-coreApp apex file if system is in minimal boot state. + if (e.error == PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED) { + Slog.w(TAG, "Scan apex failed, not a coreApp:" + ai.modulePath); + continue; + } throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable); } else { throw new IllegalStateException("Unexpected exception occurred while parsing " diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 09b782d768d2..7c47cf0450d4 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -113,6 +113,7 @@ public class AppsFilter { private final OverlayReferenceMapper mOverlayReferenceMapper; private PackageParser.SigningDetails mSystemSigningDetails; + private Set<String> mProtectedBroadcasts = new ArraySet<>(); AppsFilter(FeatureConfig featureConfig, String[] forceQueryableWhitelist, boolean systemAppsQueryable, @@ -298,10 +299,10 @@ public class AppsFilter { /** Returns true if the querying package may query for the potential target package */ private static boolean canQueryViaComponents(AndroidPackage querying, - AndroidPackage potentialTarget) { + AndroidPackage potentialTarget, Set<String> protectedBroadcasts) { if (!querying.getQueriesIntents().isEmpty()) { for (Intent intent : querying.getQueriesIntents()) { - if (matchesIntentFilters(intent, potentialTarget)) { + if (matchesIntentFilters(intent, potentialTarget, protectedBroadcasts)) { return true; } } @@ -353,13 +354,14 @@ public class AppsFilter { return false; } - private static boolean matchesIntentFilters(Intent intent, AndroidPackage potentialTarget) { + private static boolean matchesIntentFilters(Intent intent, AndroidPackage potentialTarget, + Set<String> protectedBroadcasts) { for (int s = ArrayUtils.size(potentialTarget.getServices()) - 1; s >= 0; s--) { ParsedService service = potentialTarget.getServices().get(s); if (!service.isExported()) { continue; } - if (matchesAnyFilter(intent, service)) { + if (matchesAnyFilter(intent, service, null /*protectedBroadcasts*/)) { return true; } } @@ -368,7 +370,8 @@ public class AppsFilter { if (!activity.isExported()) { continue; } - if (matchesAnyFilter(intent, activity)) { + + if (matchesAnyFilter(intent, activity, null /*protectedBroadcasts*/)) { return true; } } @@ -377,25 +380,32 @@ public class AppsFilter { if (!receiver.isExported()) { continue; } - if (matchesAnyFilter(intent, receiver)) { + if (matchesAnyFilter(intent, receiver, protectedBroadcasts)) { return true; } } return false; } - private static boolean matchesAnyFilter(Intent intent, ParsedComponent component) { + private static boolean matchesAnyFilter(Intent intent, ParsedComponent component, + Set<String> protectedBroadcasts) { List<ParsedIntentInfo> intents = component.getIntents(); for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) { IntentFilter intentFilter = intents.get(i); - if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(), - intent.getData(), intent.getCategories(), "AppsFilter", true) > 0) { + if (matchesIntentFilter(intent, intentFilter, protectedBroadcasts)) { return true; } } return false; } + private static boolean matchesIntentFilter(Intent intent, IntentFilter intentFilter, + @Nullable Set<String> protectedBroadcasts) { + return intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(), + intent.getData(), intent.getCategories(), "AppsFilter", true, protectedBroadcasts) + > 0; + } + /** * Grants access based on an interaction between a calling and target package, granting * visibility of the caller from the target. @@ -434,6 +444,12 @@ public class AppsFilter { } } } + + if (!newPkgSetting.pkg.getProtectedBroadcasts().isEmpty()) { + mProtectedBroadcasts.addAll(newPkgSetting.pkg.getProtectedBroadcasts()); + recomputeComponentVisibility(existingSettings, newPkgSetting.pkg.getPackageName()); + } + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); try { final AndroidPackage newPkg = newPkgSetting.pkg; @@ -464,7 +480,7 @@ public class AppsFilter { final AndroidPackage existingPkg = existingSetting.pkg; // let's evaluate the ability of already added packages to see this new package if (!newIsForceQueryable) { - if (canQueryViaComponents(existingPkg, newPkg)) { + if (canQueryViaComponents(existingPkg, newPkg, mProtectedBroadcasts)) { mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId); } if (canQueryViaPackage(existingPkg, newPkg) @@ -474,7 +490,7 @@ public class AppsFilter { } // now we'll evaluate our new package's ability to see existing packages if (!mForceQueryable.contains(existingSetting.appId)) { - if (canQueryViaComponents(newPkg, existingPkg)) { + if (canQueryViaComponents(newPkg, existingPkg, mProtectedBroadcasts)) { mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId); } if (canQueryViaPackage(newPkg, existingPkg) @@ -511,10 +527,47 @@ public class AppsFilter { && pkgSetting.signatures.mSigningDetails.signaturesMatchExactly(sysSigningDetails); } - private static void sort(int[] uids, int nextUidIndex) { - Arrays.sort(uids, 0, nextUidIndex); + private ArraySet<String> collectProtectedBroadcasts( + ArrayMap<String, PackageSetting> existingSettings, @Nullable String excludePackage) { + ArraySet<String> ret = new ArraySet<>(); + for (int i = existingSettings.size() - 1; i >= 0; i--) { + PackageSetting setting = existingSettings.valueAt(i); + if (setting.pkg == null || setting.pkg.getPackageName().equals(excludePackage)) { + continue; + } + final List<String> protectedBroadcasts = setting.pkg.getProtectedBroadcasts(); + if (!protectedBroadcasts.isEmpty()) { + ret.addAll(protectedBroadcasts); + } + } + return ret; } + private void recomputeComponentVisibility(ArrayMap<String, PackageSetting> existingSettings, + @Nullable String excludePackage) { + mQueriesViaComponent.clear(); + for (int i = existingSettings.size() - 1; i >= 0; i--) { + PackageSetting setting = existingSettings.valueAt(i); + if (setting.pkg == null + || setting.pkg.getPackageName().equals(excludePackage) + || mForceQueryable.contains(setting.appId)) { + continue; + } + for (int j = existingSettings.size() - 1; j >= 0; j--) { + if (i == j) { + continue; + } + final PackageSetting otherSetting = existingSettings.valueAt(j); + if (otherSetting.pkg == null + || otherSetting.pkg.getPackageName().equals(excludePackage)) { + continue; + } + if (canQueryViaComponents(setting.pkg, otherSetting.pkg, mProtectedBroadcasts)) { + mQueriesViaComponent.add(setting.appId, otherSetting.appId); + } + } + } + } /** * Fetches all app Ids that a given setting is currently visible to, per provided user. This * only includes UIDs >= {@link Process#FIRST_APPLICATION_UID} as all other UIDs can already see @@ -608,6 +661,14 @@ public class AppsFilter { } } + if (!setting.pkg.getProtectedBroadcasts().isEmpty()) { + final String removingPackageName = setting.pkg.getPackageName(); + mProtectedBroadcasts.clear(); + mProtectedBroadcasts.addAll( + collectProtectedBroadcasts(existingSettings, removingPackageName)); + recomputeComponentVisibility(existingSettings, removingPackageName); + } + mOverlayReferenceMapper.removePkg(setting.name); mFeatureConfig.updatePackageState(setting, true /*removed*/); } diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index ba7583fe7f7a..dab4bfd4df5a 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -46,6 +46,7 @@ import com.android.server.pm.dex.DexoptOptions; import java.io.File; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -106,6 +107,8 @@ public class BackgroundDexOptService extends JobService { private static final long mDowngradeUnusedAppsThresholdInMillis = getDowngradeUnusedAppsThresholdInMillis(); + private static List<PackagesUpdatedListener> sPackagesUpdatedListeners = new ArrayList<>(); + public static void schedule(Context context) { if (isBackgroundDexoptDisabled()) { return; @@ -244,6 +247,7 @@ public class BackgroundDexOptService extends JobService { } } notifyPinService(updatedPackages); + notifyPackagesUpdated(updatedPackages); // Ran to completion, so we abandon our timeslice and do not reschedule. jobFinished(jobParams, /* reschedule */ false); } @@ -391,6 +395,7 @@ public class BackgroundDexOptService extends JobService { } finally { // Always let the pinner service know about changes. notifyPinService(updatedPackages); + notifyPackagesUpdated(updatedPackages); } } @@ -642,6 +647,32 @@ public class BackgroundDexOptService extends JobService { } } + public static interface PackagesUpdatedListener { + /** Callback when packages have been updated by the bg-dexopt service. */ + public void onPackagesUpdated(ArraySet<String> updatedPackages); + } + + public static void addPackagesUpdatedListener(PackagesUpdatedListener listener) { + synchronized (sPackagesUpdatedListeners) { + sPackagesUpdatedListeners.add(listener); + } + } + + public static void removePackagesUpdatedListener(PackagesUpdatedListener listener) { + synchronized (sPackagesUpdatedListeners) { + sPackagesUpdatedListeners.remove(listener); + } + } + + /** Notify all listeners (#addPackagesUpdatedListener) that packages have been updated. */ + private void notifyPackagesUpdated(ArraySet<String> updatedPackages) { + synchronized (sPackagesUpdatedListeners) { + for (PackagesUpdatedListener listener : sPackagesUpdatedListeners) { + listener.onPackagesUpdated(updatedPackages); + } + } + } + private static long getDowngradeUnusedAppsThresholdInMillis() { final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days"; String sysPropValue = SystemProperties.get(sysPropKey); diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java index 40876754eae8..28c8642d3e60 100644 --- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java @@ -294,6 +294,12 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { .getAllCrossProfilePackages().contains(packageName)); } + private boolean isCrossProfilePackageWhitelistedByDefault(String packageName) { + return mInjector.withCleanCallingIdentity(() -> + mInjector.getDevicePolicyManagerInternal() + .getDefaultCrossProfilePackages().contains(packageName)); + } + private List<UserHandle> getTargetUserProfilesUnchecked( String packageName, @UserIdInt int userId) { return mInjector.withCleanCallingIdentity(() -> { @@ -528,6 +534,9 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { @Override public boolean canConfigureInteractAcrossProfiles(String packageName) { + if (!canUserAttemptToConfigureInteractAcrossProfiles(packageName)) { + return false; + } if (!hasOtherProfileWithPackageInstalled(packageName, mInjector.getCallingUserId())) { return false; } @@ -546,7 +555,35 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { return false; } return hasRequestedAppOpPermission( - AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName); + AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName) + && !isPlatformSignedAppWithNonUserConfigurablePermission(packageName, profileIds); + } + + private boolean isPlatformSignedAppWithNonUserConfigurablePermission( + String packageName, int[] profileIds) { + return !isCrossProfilePackageWhitelistedByDefault(packageName) + && isPlatformSignedAppWithAutomaticProfilesPermission(packageName, profileIds); + } + + /** + * Only platform-signed apps can be granted INTERACT_ACROSS_PROFILES automatically without user + * consent. + * + * Returns true if the app is automatically granted the permission in at least one profile. + */ + private boolean isPlatformSignedAppWithAutomaticProfilesPermission( + String packageName, int[] profileIds) { + for (int userId : profileIds) { + final int uid = mInjector.getPackageManagerInternal().getPackageUidInternal( + packageName, /* flags= */ 0, userId); + if (uid == -1) { + continue; + } + if (isPermissionGranted(Manifest.permission.INTERACT_ACROSS_PROFILES, uid)) { + return true; + } + } + return false; } private boolean hasOtherProfileWithPackageInstalled(String packageName, @UserIdInt int userId) { diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java index 09baf6e0a817..ae9c38498b10 100644 --- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java +++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java @@ -204,6 +204,12 @@ public class DataLoaderManagerService extends SystemService { @Override public void onServiceDisconnected(ComponentName arg0) { + if (mListener != null) { + try { + mListener.onStatusChanged(mId, IDataLoaderStatusListener.DATA_LOADER_DESTROYED); + } catch (RemoteException ignored) { + } + } remove(); } diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index f37af3aef657..9fb468e8db6e 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -724,6 +724,30 @@ public class Installer extends SystemService { } /** + * Deletes all snapshots of credential encrypted user data, where the snapshot id is not + * included in {@code retainSnapshotIds}. + * + * @param userId id of the user whose user data snapshots to delete. + * @param retainSnapshotIds ids of the snapshots that should not be deleted. + * + * @return {@code true} if the operation was successful, or {@code false} if a remote call + * shouldn't be continued. See {@link #checkBeforeRemote}. + * + * @throws InstallerException if failed to delete user data snapshot. + */ + public boolean destroyCeSnapshotsNotSpecified(@UserIdInt int userId, + int[] retainSnapshotIds) throws InstallerException { + if (!checkBeforeRemote()) return false; + + try { + mInstalld.destroyCeSnapshotsNotSpecified(null, userId, retainSnapshotIds); + return true; + } catch (Exception e) { + throw InstallerException.from(e); + } + } + + /** * Migrates obb data from its legacy location {@code /data/media/obb} to * {@code /data/media/0/Android/obb}. This call is idempotent and a fast no-op if data has * already been migrated. diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index e7d0c41c0fea..65b7cf3eabd1 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.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.WorkSource; +import android.os.storage.StorageManager; import android.util.Log; import android.util.Slog; import android.util.SparseArray; @@ -79,7 +80,7 @@ import java.util.Map; * Helper class for running dexopt command on packages. */ public class PackageDexOptimizer { - private static final String TAG = "PackageManager.DexOptimizer"; + private static final String TAG = "PackageDexOptimizer"; static final String OAT_DIR_NAME = "oat"; // TODO b/19550105 Remove error codes and use exceptions public static final int DEX_OPT_SKIPPED = 0; @@ -307,6 +308,55 @@ public class PackageDexOptimizer { } } + /** + * Perform dexopt (if needed) on a system server code path). + */ + public int dexoptSystemServerPath( + String dexPath, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) { + int dexoptFlags = DEXOPT_PUBLIC + | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0) + | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0); + + int result = DEX_OPT_SKIPPED; + for (String isa : dexUseInfo.getLoaderIsas()) { + int dexoptNeeded = getDexoptNeeded( + dexPath, + isa, + options.getCompilerFilter(), + dexUseInfo.getClassLoaderContext(), + /* newProfile= */false, + /* downgrade= */ false); + + if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) { + continue; + } + try { + mInstaller.dexopt( + dexPath, + android.os.Process.SYSTEM_UID, + /* packageName= */ "android", + isa, + dexoptNeeded, + /* oatDir= */ null, + dexoptFlags, + options.getCompilerFilter(), + StorageManager.UUID_PRIVATE_INTERNAL, + dexUseInfo.getClassLoaderContext(), + /* seInfo= */ null, + /* downgrade= */ false , + /* targetSdk= */ 0, + /* profileName */ null, + /* dexMetadataPath */ null, + getReasonName(options.getCompilationReason())); + } catch (InstallerException e) { + Slog.w(TAG, "Failed to dexopt", e); + return DEX_OPT_FAILED; + } + result = DEX_OPT_PERFORMED; + } + return result; + } + private String getAugmentedReasonName(int compilationReason, boolean useDexMetadata) { String annotation = useDexMetadata ? ArtManagerService.DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION : ""; diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 8ff7ea9d61dd..4cfd1ab73c9e 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -82,6 +82,8 @@ import com.android.internal.util.ImageUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.IoThread; import com.android.server.LocalServices; +import com.android.server.SystemConfig; +import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.permission.PermissionManagerServiceInternal; import libcore.io.IoUtils; @@ -105,6 +107,7 @@ import java.util.List; import java.util.Objects; import java.util.Random; import java.util.function.IntPredicate; +import java.util.function.Supplier; /** The service responsible for installing packages. */ public class PackageInstallerService extends IPackageInstaller.Stub implements @@ -149,6 +152,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements private final Callbacks mCallbacks; private volatile boolean mOkToSendBroadcasts = false; + private volatile boolean mBypassNextStagedInstallerCheck = false; /** * File storing persisted {@link #mSessions} metadata. @@ -194,7 +198,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } }; - public PackageInstallerService(Context context, PackageManagerService pm) { + public PackageInstallerService(Context context, PackageManagerService pm, + Supplier<PackageParser2> apexParserSupplier) { mContext = context; mPm = pm; mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class); @@ -213,7 +218,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements mSessionsDir.mkdirs(); mApexManager = ApexManager.getInstance(); - mStagingManager = new StagingManager(this, context); + mStagingManager = new StagingManager(this, context, apexParserSupplier); } boolean okToSendBroadcasts() { @@ -538,7 +543,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } } - if (Build.IS_DEBUGGABLE || isDowngradeAllowedForCaller(callingUid)) { + if (Build.IS_DEBUGGABLE || isCalledBySystemOrShell(callingUid)) { params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; } else { params.installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE; @@ -568,6 +573,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } } + if (mBypassNextStagedInstallerCheck) { + mBypassNextStagedInstallerCheck = false; + } else if (params.isStaged + && !isCalledBySystemOrShell(callingUid) + && !isWhitelistedStagedInstaller(requestedInstallerPackageName)) { + throw new SecurityException("Installer not allowed to commit staged install"); + } + if (!params.isMultiPackage) { // Only system components can circumvent runtime permissions when installing. if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0 @@ -680,11 +693,15 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements return sessionId; } - private boolean isDowngradeAllowedForCaller(int callingUid) { + private boolean isCalledBySystemOrShell(int callingUid) { return callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID || callingUid == Process.SHELL_UID; } + private boolean isWhitelistedStagedInstaller(String installerName) { + return SystemConfig.getInstance().getWhitelistedStagedInstallers().contains(installerName); + } + @Override public void updateSessionAppIcon(int sessionId, Bitmap appIcon) { synchronized (mSessions) { @@ -960,6 +977,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } } + @Override + public void bypassNextStagedInstallerCheck(boolean value) { + mBypassNextStagedInstallerCheck = value; + } + private static int getSessionCount(SparseArray<PackageInstallerSession> sessions, int installerUid) { int count = 0; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 1248ec01e020..2221644bff47 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -128,6 +128,7 @@ import com.android.internal.content.PackageHelper; import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.pm.Installer.InstallerException; @@ -1801,6 +1802,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + private void logDataLoaderInstallationSession(int returnCode, String extraMessage) { + final long currentTimestamp = System.currentTimeMillis(); + FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLER_V2_REPORTED, + isIncrementalInstallation(), + mPackageName, + currentTimestamp - createdMillis, + returnCode); + } + /** * Returns true if the session should attempt to inherit any existing native libraries already * extracted at the current install location. This is necessary to prevent double loading of @@ -1830,7 +1840,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throws PackageManagerException { final List<File> addedFiles = getAddedApksLocked(); if (addedFiles.isEmpty()) { - throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged"); + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + String.format("Session: %d. No packages staged in %s", sessionId, + stageDir.getAbsolutePath())); } if (ArrayUtils.size(addedFiles) > 1) { @@ -1921,7 +1933,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final List<File> addedFiles = getAddedApksLocked(); if (addedFiles.isEmpty() && removeSplitList.size() == 0) { - throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged"); + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + String.format("Session: %d. No packages staged in %s", sessionId, + stageDir.getAbsolutePath())); } // Verify that all staged packages are internally consistent @@ -2785,6 +2799,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } mCallback.onSessionFinished(this, success); + if (isDataLoaderInstallation()) { + logDataLoaderInstallationSession(returnCode, msg); + } } /** {@hide} */ diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ab3b2be46988..59ac603875e2 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -263,6 +263,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.os.incremental.IncrementalManager; +import android.os.incremental.IncrementalStorage; import android.os.storage.DiskInfo; import android.os.storage.IStorageManager; import android.os.storage.StorageEventListener; @@ -417,6 +418,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.function.Supplier; /** * Keep track of all those APKs everywhere. @@ -3571,7 +3573,11 @@ public class PackageManagerService extends IPackageManager.Stub } } - mInstallerService = new PackageInstallerService(mContext, this); + // Prepare a supplier of package parser for the staging manager to parse apex file + // during the staging installation. + final Supplier<PackageParser2> apexParserSupplier = () -> new PackageParser2( + mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, mPackageParserCallback); + mInstallerService = new PackageInstallerService(mContext, this, apexParserSupplier); final Pair<ComponentName, String> instantAppResolverComponent = getInstantAppResolverLPr(); if (instantAppResolverComponent != null) { @@ -9679,6 +9685,20 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap, String loaderIsa) { + if (PLATFORM_PACKAGE_NAME.equals(loadingPackageName) + && Binder.getCallingUid() != Process.SYSTEM_UID) { + Slog.w(TAG, "Non System Server process reporting dex loads as system server. uid=" + + Binder.getCallingUid()); + // Do not record dex loads from processes pretending to be system server. + // Only the system server should be assigned the package "android", so reject calls + // that don't satisfy the constraint. + // + // notifyDexLoad is a PM API callable from the app process. So in theory, apps could + // craft calls to this API and pretend to be system server. Doing so poses no particular + // danger for dex load reporting or later dexopt, however it is a sensible check to do + // in order to verify the expectations. + return; + } int userId = UserHandle.getCallingUserId(); ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId); if (ai == null) { @@ -9836,6 +9856,11 @@ public class PackageManagerService extends IPackageManager.Stub private int performDexOptInternalWithDependenciesLI(AndroidPackage p, @NonNull PackageSetting pkgSetting, DexoptOptions options) { + // System server gets a special path. + if (PLATFORM_PACKAGE_NAME.equals(p.getPackageName())) { + return mDexManager.dexoptSystemServer(options); + } + // Select the dex optimizer based on the force parameter. // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to // allocate an object here. @@ -11305,7 +11330,7 @@ public class PackageManagerService extends IPackageManager.Stub Slog.i(TAG, "Using ABIS and native lib paths from settings : " + parsedPackage.getPackageName() + " " + AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage) - + ", " + + ", " + AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage)); } } @@ -16572,6 +16597,7 @@ public class PackageManagerService extends IPackageManager.Stub * locks on {@link #mLock}. */ private void executePostCommitSteps(CommitRequest commitRequest) { + final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>(); for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) { final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags & PackageManagerService.SCAN_AS_INSTANT_APP) != 0); @@ -16579,6 +16605,14 @@ public class PackageManagerService extends IPackageManager.Stub final String packageName = pkg.getPackageName(); final boolean onIncremental = mIncrementalManager != null && isIncrementalPath(pkg.getCodePath()); + if (onIncremental) { + IncrementalStorage storage = mIncrementalManager.openStorage(pkg.getCodePath()); + if (storage == null) { + throw new IllegalArgumentException( + "Install: null storage for incremental package " + packageName); + } + incrementalStorages.add(storage); + } prepareAppDataAfterInstallLIF(pkg); if (reconciledPkg.prepareResult.clearCodeCache) { clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE @@ -16676,6 +16710,7 @@ public class PackageManagerService extends IPackageManager.Stub notifyPackageChangeObserversOnUpdate(reconciledPkg); } + NativeLibraryHelper.waitForNativeBinariesExtraction(incrementalStorages); } private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) { @@ -17567,11 +17602,13 @@ public class PackageManagerService extends IPackageManager.Stub } if (needToVerify) { + final boolean needsVerification = needsNetworkVerificationLPr(packageName); final int verificationId = mIntentFilterVerificationToken++; for (ParsedActivity a : activities) { for (ParsedIntentInfo filter : a.getIntents()) { - if (filter.handlesWebUris(true) - && needsNetworkVerificationLPr(a.getPackageName())) { + // Run verification against hosts mentioned in any web-nav intent filter, + // even if the filter matches non-web schemes as well + if (needsVerification && filter.handlesWebUris(false)) { if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Verification needed for IntentFilter:" + filter.toString()); mIntentFilterVerifier.addOneIntentFilterVerification( diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index b4eacf6226ce..88f442c7b6a0 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -297,6 +297,8 @@ class PackageManagerShellCommand extends ShellCommand { return runGetModuleInfo(); case "log-visibility": return runLogVisibility(); + case "bypass-staged-installer-check": + return runBypassStagedInstallerCheck(); default: { String nextArg = getNextArg(); if (nextArg == null) { @@ -392,6 +394,20 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } + private int runBypassStagedInstallerCheck() { + final PrintWriter pw = getOutPrintWriter(); + try { + mInterface.getPackageInstaller() + .bypassNextStagedInstallerCheck(Boolean.parseBoolean(getNextArg())); + return 0; + } catch (RemoteException e) { + pw.println("Failure [" + + e.getClass().getName() + " - " + + e.getMessage() + "]"); + return -1; + } + } + private int uninstallSystemUpdates() { final PrintWriter pw = getOutPrintWriter(); List<String> failedUninstalls = new LinkedList<>(); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index e8696f60b59a..f6e4e1f26bd5 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -4667,6 +4667,10 @@ public final class Settings { pw.print(prefix); pw.print(" privateFlags="); printFlags(pw, privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println(); } + if (pkg.hasPreserveLegacyExternalStorage()) { + pw.print(prefix); pw.print(" hasPreserveLegacyExternalStorage=true"); + pw.println(); + } pw.print(prefix); pw.print(" forceQueryable="); pw.print(ps.pkg.isForceQueryable()); if (ps.forceQueryableOverride) { pw.print(" (override=true)"); diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 0b1b71a08660..8f6bd026a9bd 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -35,11 +35,11 @@ import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; -import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.ParceledListSlice; +import android.content.pm.parsing.PackageInfoWithoutStateUtils; import android.content.rollback.IRollbackManager; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; @@ -68,8 +68,10 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageHelper; import com.android.internal.os.BackgroundThread; import com.android.server.LocalServices; +import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.AndroidPackageUtils; +import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.rollback.WatchdogRollbackLogger; import java.io.File; @@ -80,6 +82,7 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.function.Supplier; /** * This class handles staged install sessions, i.e. install sessions that require packages to @@ -94,6 +97,7 @@ public class StagingManager { private final PowerManager mPowerManager; private final Context mContext; private final PreRebootVerificationHandler mPreRebootVerificationHandler; + private final Supplier<PackageParser2> mPackageParserSupplier; @GuardedBy("mStagedSessions") private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>(); @@ -105,9 +109,11 @@ public class StagingManager { private final List<String> mFailedPackageNames = new ArrayList<>(); private String mNativeFailureReason; - StagingManager(PackageInstallerService pi, Context context) { + StagingManager(PackageInstallerService pi, Context context, + Supplier<PackageParser2> packageParserSupplier) { mPi = pi; mContext = context; + mPackageParserSupplier = packageParserSupplier; mApexManager = ApexManager.getInstance(); mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); @@ -223,17 +229,21 @@ public class StagingManager { final List<String> apexPackageNames = new ArrayList<>(); for (ApexInfo apexInfo : apexInfoList.apexInfos) { final PackageInfo packageInfo; - int flags = PackageManager.GET_META_DATA; - PackageParser.Package pkg; - try { + final int flags = PackageManager.GET_META_DATA; + try (PackageParser2 packageParser = mPackageParserSupplier.get()) { File apexFile = new File(apexInfo.modulePath); - PackageParser pp = new PackageParser(); - pkg = pp.parsePackage(apexFile, flags, false); + final ParsedPackage parsedPackage = packageParser.parsePackage( + apexFile, flags, false); + packageInfo = PackageInfoWithoutStateUtils.generate(parsedPackage, apexInfo, flags); + if (packageInfo == null) { + throw new PackageManagerException( + SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, + "Unable to generate package info: " + apexInfo.modulePath); + } } catch (PackageParserException e) { throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, "Failed to parse APEX package " + apexInfo.modulePath, e); } - packageInfo = PackageParser.generatePackageInfo(pkg, apexInfo, flags); final PackageInfo activePackage = mApexManager.getPackageInfo(packageInfo.packageName, ApexManager.MATCH_ACTIVE_PACKAGE); if (activePackage == null) { diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index e8765ad973f3..6dcf71e9fbf0 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -17,13 +17,17 @@ package com.android.server.pm.dex; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; +import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo; import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo; +import static java.util.function.Function.identity; + import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; +import android.content.pm.PackagePartitions; import android.os.FileUtils; import android.os.RemoteException; import android.os.SystemProperties; @@ -45,6 +49,8 @@ import dalvik.system.VMRuntime; import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -67,13 +73,12 @@ import java.util.zip.ZipEntry; */ public class DexManager { private static final String TAG = "DexManager"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob"; private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST = "pm.dexopt.priv-apps-oob-list"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private final Context mContext; // Maps package name to code locations. @@ -178,12 +183,14 @@ public class DexManager { boolean primaryOrSplit = searchResult.mOutcome == DEX_SEARCH_FOUND_PRIMARY || searchResult.mOutcome == DEX_SEARCH_FOUND_SPLIT; - if (primaryOrSplit && !isUsedByOtherApps) { + if (primaryOrSplit && !isUsedByOtherApps + && !PLATFORM_PACKAGE_NAME.equals(searchResult.mOwningPackageName)) { // If the dex file is the primary apk (or a split) and not isUsedByOtherApps // do not record it. This case does not bring any new usable information // and can be safely skipped. // Note this is just an optimization that makes things easier to read in the // package-dex-use file since we don't need to pollute it with redundant info. + // However, we always record system server packages. continue; } @@ -217,6 +224,27 @@ public class DexManager { } /** + * Check if the dexPath belongs to system server. + * System server can load code from different location, so we cast a wide-net here, and + * assume that if the paths is on any of the registered system partitions then it can be loaded + * by system server. + */ + private boolean isSystemServerDexPathSupportedForOdex(String dexPath) { + ArrayList<PackagePartitions.SystemPartition> partitions = + PackagePartitions.getOrderedPartitions(identity()); + // First check the apex partition as it's not part of the SystemPartitions. + if (dexPath.startsWith("/apex/")) { + return true; + } + for (int i = 0; i < partitions.size(); i++) { + if (partitions.get(i).containsPath(dexPath)) { + return true; + } + } + return false; + } + + /** * Read the dex usage from disk and populate the code cache locations. * @param existingPackages a map containing information about what packages * are available to what users. Only packages in this list will be @@ -415,15 +443,7 @@ public class DexManager { * because they don't need to be compiled).. */ public boolean dexoptSecondaryDex(DexoptOptions options) { - // Select the dex optimizer based on the force parameter. - // Forced compilation is done through ForcedUpdatePackageDexOptimizer which will adjust - // the necessary dexopt flags to make sure that compilation is not skipped. This avoid - // passing the force flag through the multitude of layers. - // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to - // allocate an object here. - PackageDexOptimizer pdo = options.isForce() - ? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPackageDexOptimizer) - : mPackageDexOptimizer; + PackageDexOptimizer pdo = getPackageDexOptimizer(options); String packageName = options.getPackageName(); PackageUseInfo useInfo = getPackageUseInfoOrDefault(packageName); if (useInfo.getDexUseInfoMap().isEmpty()) { @@ -464,6 +484,83 @@ public class DexManager { } /** + * Performs dexopt on system server dex files. + * + * <p>Verfifies that the package name is {@link PackageManagerService#PLATFORM_PACKAGE_NAME}. + * + * @return + * <p>PackageDexOptimizer.DEX_OPT_SKIPPED if dexopt was skipped because no system server + * files were recorded or if no dexopt was needed. + * <p>PackageDexOptimizer.DEX_OPT_FAILED if any dexopt operation failed. + * <p>PackageDexOptimizer.DEX_OPT_PERFORMED if all dexopt operations succeeded. + */ + public int dexoptSystemServer(DexoptOptions options) { + if (!PLATFORM_PACKAGE_NAME.equals(options.getPackageName())) { + Slog.wtf(TAG, "Non system server package used when trying to dexopt system server:" + + options.getPackageName()); + return PackageDexOptimizer.DEX_OPT_FAILED; + } + + PackageDexOptimizer pdo = getPackageDexOptimizer(options); + String packageName = options.getPackageName(); + PackageUseInfo useInfo = getPackageUseInfoOrDefault(packageName); + if (useInfo.getDexUseInfoMap().isEmpty()) { + if (DEBUG) { + Slog.d(TAG, "No dex files recorded for system server"); + } + // Nothing to compile, return true. + return PackageDexOptimizer.DEX_OPT_SKIPPED; + } + + boolean usageUpdated = false; + int result = PackageDexOptimizer.DEX_OPT_SKIPPED; + for (Map.Entry<String, DexUseInfo> entry : useInfo.getDexUseInfoMap().entrySet()) { + String dexPath = entry.getKey(); + DexUseInfo dexUseInfo = entry.getValue(); + if (!Files.exists(Paths.get(dexPath))) { + if (DEBUG) { + Slog.w(TAG, "A dex file previously loaded by System Server does not exist " + + " anymore: " + dexPath); + } + usageUpdated = mPackageDexUsage.removeDexFile( + packageName, dexPath, dexUseInfo.getOwnerUserId()) || usageUpdated; + continue; + } + + int newResult = pdo.dexoptSystemServerPath(dexPath, dexUseInfo, options); + + // The end result is: + // - FAILED if any path failed, + // - PERFORMED if at least one path needed compilation, + // - SKIPPED when all paths are up to date + if ((result != PackageDexOptimizer.DEX_OPT_FAILED) + && (newResult != PackageDexOptimizer.DEX_OPT_SKIPPED)) { + result = newResult; + } + } + + if (usageUpdated) { + mPackageDexUsage.maybeWriteAsync(); + } + + return result; + } + + /** + * Select the dex optimizer based on the force parameter. + * Forced compilation is done through ForcedUpdatePackageDexOptimizer which will adjust + * the necessary dexopt flags to make sure that compilation is not skipped. This avoid + * passing the force flag through the multitude of layers. + * Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to + * allocate an object here. + */ + private PackageDexOptimizer getPackageDexOptimizer(DexoptOptions options) { + return options.isForce() + ? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPackageDexOptimizer) + : mPackageDexOptimizer; + } + + /** * Reconcile the information we have about the secondary dex files belonging to * {@code packagName} and the actual dex files. For all dex files that were * deleted, update the internal records and delete any generated oat files. @@ -607,12 +704,6 @@ public class DexManager { */ private DexSearchResult getDexPackage( ApplicationInfo loadingAppInfo, String dexPath, int userId) { - // Ignore framework code. - // TODO(calin): is there a better way to detect it? - if (dexPath.startsWith("/system/framework/")) { - return new DexSearchResult("framework", DEX_SEARCH_NOT_FOUND); - } - // First, check if the package which loads the dex file actually owns it. // Most of the time this will be true and we can return early. PackageCodeLocations loadingPackageCodeLocations = @@ -635,6 +726,28 @@ public class DexManager { } } + // We could not find the owning package amongst regular apps. + // If the loading package is system server, see if the dex file resides + // on any of the potentially system server owning location and if so, + // assuming system server ownership. + // + // Note: We don't have any way to detect which code paths are actually + // owned by system server. We can only assume that such paths are on + // system partitions. + if (PLATFORM_PACKAGE_NAME.equals(loadingAppInfo.packageName)) { + if (isSystemServerDexPathSupportedForOdex(dexPath)) { + // We record system server dex files as secondary dex files. + // The reason is that we only record the class loader context for secondary dex + // files and we expect that all primary apks are loaded with an empty class loader. + // System server dex files may be loaded in non-empty class loader so we need to + // keep track of their context. + return new DexSearchResult(PLATFORM_PACKAGE_NAME, DEX_SEARCH_FOUND_SECONDARY); + } else { + Slog.wtf(TAG, "System server loads dex files outside paths supported for odex: " + + dexPath); + } + } + if (DEBUG) { // TODO(calin): Consider checking for /data/data symlink. // /data/data/ symlinks /data/user/0/ and there's nothing stopping apps diff --git a/services/core/java/com/android/server/pm/dex/SystemServerDexLoadReporter.java b/services/core/java/com/android/server/pm/dex/SystemServerDexLoadReporter.java new file mode 100644 index 000000000000..807c82d887e3 --- /dev/null +++ b/services/core/java/com/android/server/pm/dex/SystemServerDexLoadReporter.java @@ -0,0 +1,83 @@ +/* + * 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.server.pm.dex; + +import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; + +import android.content.pm.IPackageManager; +import android.os.RemoteException; +import android.util.Log; +import android.util.Slog; + +import dalvik.system.BaseDexClassLoader; +import dalvik.system.VMRuntime; + +import java.util.Map; + +/** + * Reports dex file use to the package manager on behalf of system server. + */ +public class SystemServerDexLoadReporter implements BaseDexClassLoader.Reporter { + private static final String TAG = "SystemServerDexLoadReporter"; + + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private final IPackageManager mPackageManager; + + private SystemServerDexLoadReporter(IPackageManager pm) { + mPackageManager = pm; + } + + @Override + public void report(Map<String, String> classLoaderContextMap) { + if (DEBUG) { + Slog.i(TAG, "Reporting " + classLoaderContextMap); + } + if (classLoaderContextMap.isEmpty()) { + Slog.wtf(TAG, "Bad call to DexLoadReporter: empty classLoaderContextMap"); + return; + } + + try { + mPackageManager.notifyDexLoad( + PLATFORM_PACKAGE_NAME, + classLoaderContextMap, + VMRuntime.getRuntime().vmInstructionSet()); + } catch (RemoteException ignored) { + // We're in system server, it can't happen. + } + } + + /** + * Configures system server dex file reporting. + * <p>The method will install a reporter in the BaseDexClassLoader and also + * force the reporting of any dex files already loaded by the system server. + */ + public static void configureSystemServerDexReporter(IPackageManager pm) { + Slog.i(TAG, "Configuring system server dex reporter"); + + SystemServerDexLoadReporter reporter = new SystemServerDexLoadReporter(pm); + BaseDexClassLoader.setReporter(reporter); + ClassLoader currrentClassLoader = reporter.getClass().getClassLoader(); + if (currrentClassLoader instanceof BaseDexClassLoader) { + ((BaseDexClassLoader) currrentClassLoader).reportClassLoaderChain(); + } else { + Slog.wtf(TAG, "System server class loader is not a BaseDexClassLoader. type=" + + currrentClassLoader.getClass().getName()); + } + } +} diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index a726d39b8595..e3faffa0699b 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -882,7 +882,7 @@ public final class DefaultPermissionGrantPolicy { public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) { Log.i(TAG, "Granting permissions to default browser for user:" + userId); - grantPermissionsToSystemPackage(packageName, userId, ALWAYS_LOCATION_PERMISSIONS); + grantPermissionsToSystemPackage(packageName, userId, FOREGROUND_LOCATION_PERMISSIONS); } private String getDefaultSystemHandlerActivityPackage(String intentAction, int userId) { diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java index 976ce1f3dde0..1c4568095ce3 100644 --- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java +++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java @@ -21,9 +21,14 @@ import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHE import android.annotation.NonNull; import android.app.ActivityManager; import android.app.AlarmManager; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.os.Handler; import android.permission.PermissionControllerManager; +import android.provider.DeviceConfig; import android.util.Log; import android.util.SparseArray; @@ -36,7 +41,10 @@ public class OneTimePermissionUserManager { private static final String LOG_TAG = OneTimePermissionUserManager.class.getSimpleName(); - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; + private static final long DEFAULT_KILLED_DELAY_MILLIS = 5000; + public static final String PROPERTY_KILLED_DELAY_CONFIG_KEY = + "one_time_permissions_killed_delay_millis"; private final @NonNull Context mContext; private final @NonNull ActivityManager mActivityManager; @@ -45,15 +53,37 @@ public class OneTimePermissionUserManager { private final Object mLock = new Object(); + private final BroadcastReceiver mUninstallListener = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_UID_REMOVED.equals(intent.getAction())) { + int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); + PackageInactivityListener listener = mListeners.get(uid); + if (listener != null) { + if (DEBUG) { + Log.d(LOG_TAG, "Removing the inactivity listener for " + uid); + } + listener.cancel(); + mListeners.remove(uid); + } + } + } + }; + /** Maps the uid to the PackageInactivityListener */ @GuardedBy("mLock") private final SparseArray<PackageInactivityListener> mListeners = new SparseArray<>(); + private final Handler mHandler; OneTimePermissionUserManager(@NonNull Context context) { mContext = context; mActivityManager = context.getSystemService(ActivityManager.class); mAlarmManager = context.getSystemService(AlarmManager.class); mPermissionControllerManager = context.getSystemService(PermissionControllerManager.class); + mHandler = context.getMainThreadHandler(); + + // Listen for tracked uid being uninstalled + context.registerReceiver(mUninstallListener, new IntentFilter(Intent.ACTION_UID_REMOVED)); } /** @@ -132,6 +162,15 @@ public class OneTimePermissionUserManager { } /** + * The delay to wait before revoking on the event an app is terminated. Recommended to be long + * enough so that apps don't lose permission on an immediate restart + */ + private static long getKilledDelayMillis() { + return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS, + PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS); + } + + /** * A class which watches a package for inactivity and notifies the permission controller when * the package becomes inactive */ @@ -155,16 +194,15 @@ public class OneTimePermissionUserManager { private final ActivityManager.OnUidImportanceListener mGoneListener; private final Object mInnerLock = new Object(); + private final Object mToken = new Object(); private PackageInactivityListener(int uid, @NonNull String packageName, long timeout, int importanceToResetTimer, int importanceToKeepSessionAlive) { - if (DEBUG) { - Log.d(LOG_TAG, - "Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout - + " importanceToResetTimer=" + importanceToResetTimer - + " importanceToKeepSessionAlive=" + importanceToKeepSessionAlive); - } + Log.i(LOG_TAG, + "Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout + + " importanceToResetTimer=" + importanceToResetTimer + + " importanceToKeepSessionAlive=" + importanceToKeepSessionAlive); mUid = uid; mPackageName = packageName; @@ -193,18 +231,34 @@ public class OneTimePermissionUserManager { return; } - - if (DEBUG) { - Log.d(LOG_TAG, "Importance changed for " + mPackageName + " (" + mUid + ")." - + " importance=" + importance); - } + Log.v(LOG_TAG, "Importance changed for " + mPackageName + " (" + mUid + ")." + + " importance=" + importance); synchronized (mInnerLock) { + // Remove any pending inactivity callback + mHandler.removeCallbacksAndMessages(mToken); + if (importance > IMPORTANCE_CACHED) { - onPackageInactiveLocked(); + // Delay revocation in case app is restarting + mHandler.postDelayed(() -> { + int imp = mActivityManager.getUidImportance(mUid); + if (imp > IMPORTANCE_CACHED) { + onPackageInactiveLocked(); + } else { + if (DEBUG) { + Log.d(LOG_TAG, "No longer gone after delayed revocation. " + + "Rechecking for " + mPackageName + " (" + mUid + ")."); + } + onImportanceChanged(mUid, imp); + } + }, mToken, getKilledDelayMillis()); return; } if (importance > mImportanceToResetTimer) { if (mTimerStart == TIMER_INACTIVE) { + if (DEBUG) { + Log.d(LOG_TAG, "Start the timer for " + + mPackageName + " (" + mUid + ")."); + } mTimerStart = System.currentTimeMillis(); } } else { @@ -240,10 +294,13 @@ public class OneTimePermissionUserManager { return; } + if (DEBUG) { + Log.d(LOG_TAG, "Scheduling alarm for " + mPackageName + " (" + mUid + ")."); + } long revokeTime = mTimerStart + mTimeout; if (revokeTime > System.currentTimeMillis()) { mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, revokeTime, LOG_TAG, this, - mContext.getMainThreadHandler()); + mHandler); mIsAlarmSet = true; } else { mIsAlarmSet = true; @@ -257,6 +314,9 @@ public class OneTimePermissionUserManager { @GuardedBy("mInnerLock") private void cancelAlarmLocked() { if (mIsAlarmSet) { + if (DEBUG) { + Log.d(LOG_TAG, "Canceling alarm for " + mPackageName + " (" + mUid + ")."); + } mAlarmManager.cancel(this); mIsAlarmSet = false; } @@ -270,14 +330,16 @@ public class OneTimePermissionUserManager { if (mIsFinished) { return; } + if (DEBUG) { + Log.d(LOG_TAG, "onPackageInactiveLocked stack trace for " + + mPackageName + " (" + mUid + ").", new RuntimeException()); + } mIsFinished = true; cancelAlarmLocked(); - mContext.getMainThreadHandler().post( + mHandler.post( () -> { - if (DEBUG) { - Log.d(LOG_TAG, "One time session expired for " - + mPackageName + " (" + mUid + ")."); - } + Log.i(LOG_TAG, "One time session expired for " + + mPackageName + " (" + mUid + ")."); mPermissionControllerManager.notifyOneTimePermissionSessionTimeout( mPackageName); @@ -292,6 +354,9 @@ public class OneTimePermissionUserManager { @Override public void onAlarm() { + if (DEBUG) { + Log.d(LOG_TAG, "Alarm received for " + mPackageName + " (" + mUid + ")."); + } synchronized (mInnerLock) { if (!mIsAlarmSet) { return; diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index b7c9ecb604f8..ccc749232dc3 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -2519,7 +2519,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; String upgradedActivityRecognitionPermission = null; - if (DEBUG_INSTALL) { + if (DEBUG_INSTALL && bp != null) { Log.i(TAG, "Package " + pkg.getPackageName() + " checking " + permName + ": " + bp); } @@ -3881,8 +3881,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { */ private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg, @NonNull PermissionCallback callback) { + // If the package is being deleted, update the permissions of all the apps final int flags = - (pkg != null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG : 0); + (pkg == null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG + : UPDATE_PERMISSIONS_REPLACE_PKG); updatePermissions( packageName, pkg, getVolumeUuidForPackage(pkg), flags, callback); } @@ -4007,6 +4009,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (permissionTreesSourcePackageChanged | permissionSourcePackageChanged) { // Permission ownership has changed. This e.g. changes which packages can get signature // permissions + Slog.i(TAG, "Permission ownership changed. Updating all permissions."); flags |= UPDATE_PERMISSIONS_ALL; } @@ -4057,8 +4060,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { private boolean updatePermissionSourcePackage(@Nullable String packageName, @Nullable AndroidPackage pkg, final @Nullable PermissionCallback callback) { - boolean changed = false; + // Always need update if packageName is null + if (packageName == null) { + return true; + } + boolean changed = false; Set<BasePermission> needsUpdate = null; synchronized (mLock) { final Iterator<BasePermission> it = mSettings.mPermissions.values().iterator(); @@ -4067,54 +4074,29 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (bp.isDynamic()) { bp.updateDynamicPermission(mSettings.mPermissionTrees.values()); } - if (bp.getSourcePackageSetting() != null) { - if (packageName != null && packageName.equals(bp.getSourcePackageName()) - && (pkg == null || !hasPermission(pkg, bp.getName()))) { - Slog.i(TAG, "Removing permission " + bp.getName() - + " that used to be declared by " + bp.getSourcePackageName()); - if (bp.isRuntime()) { - final int[] userIds = mUserManagerInt.getUserIds(); - final int numUserIds = userIds.length; - for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) { - final int userId = userIds[userIdNum]; - - mPackageManagerInt.forEachPackage((AndroidPackage p) -> { - final String pName = p.getPackageName(); - final ApplicationInfo appInfo = - mPackageManagerInt.getApplicationInfo(pName, 0, - Process.SYSTEM_UID, UserHandle.USER_SYSTEM); - if (appInfo != null - && appInfo.targetSdkVersion < Build.VERSION_CODES.M) { - return; - } - - final String permissionName = bp.getName(); - if (checkPermissionImpl(permissionName, pName, userId) - == PackageManager.PERMISSION_GRANTED) { - try { - revokeRuntimePermissionInternal( - permissionName, - pName, - false, - Process.SYSTEM_UID, - userId, - callback); - } catch (IllegalArgumentException e) { - Slog.e(TAG, - "Failed to revoke " - + permissionName - + " from " - + pName, - e); - } - } - }); - } + if (bp.getSourcePackageSetting() == null + || !packageName.equals(bp.getSourcePackageName())) { + continue; + } + // The target package is the source of the current permission + // Set to changed for either install or uninstall + changed = true; + // If the target package is being uninstalled, we need to revoke this permission + // From all other packages + if (pkg == null || !hasPermission(pkg, bp.getName())) { + Slog.i(TAG, "Removing permission " + bp.getName() + + " that used to be declared by " + bp.getSourcePackageName()); + if (bp.isRuntime()) { + final int[] userIds = mUserManagerInt.getUserIds(); + final int numUserIds = userIds.length; + for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) { + final int userId = userIds[userIdNum]; + mPackageManagerInt.forEachPackage((AndroidPackage p) -> + revokePermissionFromPackageForUser(p.getPackageName(), + bp.getName(), userId, callback)); } - changed = true; - it.remove(); } - continue; + it.remove(); } if (needsUpdate == null) { needsUpdate = new ArraySet<>(mSettings.mPermissions.size()); @@ -4146,6 +4128,39 @@ public class PermissionManagerService extends IPermissionManager.Stub { } /** + * Revoke a runtime permission from a package for a given user ID. + */ + private void revokePermissionFromPackageForUser(@NonNull String pName, + @NonNull String permissionName, int userId, @Nullable PermissionCallback callback) { + final ApplicationInfo appInfo = + mPackageManagerInt.getApplicationInfo(pName, 0, + Process.SYSTEM_UID, UserHandle.USER_SYSTEM); + if (appInfo != null + && appInfo.targetSdkVersion < Build.VERSION_CODES.M) { + return; + } + + if (checkPermissionImpl(permissionName, pName, userId) + == PackageManager.PERMISSION_GRANTED) { + try { + revokeRuntimePermissionInternal( + permissionName, + pName, + false, + Process.SYSTEM_UID, + userId, + callback); + } catch (IllegalArgumentException e) { + Slog.e(TAG, + "Failed to revoke " + + permissionName + + " from " + + pName, + e); + } + } + } + /** * Update which app owns a permission trees. * * <p>Possible parameter combinations @@ -4164,6 +4179,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { */ private boolean updatePermissionTreeSourcePackage(@Nullable String packageName, @Nullable AndroidPackage pkg) { + // Always need update if packageName is null + if (packageName == null) { + return true; + } boolean changed = false; Set<BasePermission> needsUpdate = null; @@ -4171,16 +4190,18 @@ public class PermissionManagerService extends IPermissionManager.Stub { final Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator(); while (it.hasNext()) { final BasePermission bp = it.next(); - if (bp.getSourcePackageSetting() != null) { - if (packageName != null && packageName.equals(bp.getSourcePackageName()) - && (pkg == null || !hasPermission(pkg, bp.getName()))) { - Slog.i(TAG, "Removing permission tree " + bp.getName() - + " that used to be declared by " + bp.getSourcePackageName()); - changed = true; - it.remove(); - } + if (bp.getSourcePackageSetting() == null + || !packageName.equals(bp.getSourcePackageName())) { continue; } + // The target package is the source of the current permission tree + // Set to changed for either install or uninstall + changed = true; + if (pkg == null || !hasPermission(pkg, bp.getName())) { + Slog.i(TAG, "Removing permission tree " + bp.getName() + + " that used to be declared by " + bp.getSourcePackageName()); + it.remove(); + } if (needsUpdate == null) { needsUpdate = new ArraySet<>(mSettings.mPermissionTrees.size()); } diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 161f30449a52..27288d852fb2 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -30,6 +30,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.app.AppOpsManagerInternal; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -47,6 +48,7 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManagerInternal; import android.permission.PermissionControllerManager; +import android.provider.Settings; import android.provider.Telephony; import android.telecom.TelecomManager; import android.util.ArrayMap; @@ -70,7 +72,9 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal; import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutionException; /** @@ -180,8 +184,6 @@ public final class PermissionPolicyService extends SystemService { intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); intentFilter.addDataScheme("package"); - - /* TODO ntmyren: enable receiver when test flakes are fixed getContext().registerReceiverAsUser(new BroadcastReceiver() { final List<Integer> mUserSetupUids = new ArrayList<>(200); final Map<UserHandle, PermissionControllerManager> mPermControllerManagers = @@ -232,7 +234,6 @@ public final class PermissionPolicyService extends SystemService { manager.updateUserSensitiveForApp(uid); } }, UserHandle.ALL, intentFilter, null, null); - */ } /** diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index c9736401f680..4624e9ea0209 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4468,12 +4468,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void wakeUpFromPowerKey(long eventTime) { wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey, PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER"); - - // Turn on the connected TV and switch HDMI input if we're a HDMI playback device. - final HdmiControl hdmiControl = getHdmiControl(); - if (hdmiControl != null) { - hdmiControl.turnOnTv(); - } } private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason, @@ -4489,6 +4483,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mPowerManager.wakeUp(wakeTime, reason, details); + + // Turn on the connected TV and switch HDMI input if we're a HDMI playback device. + final HdmiControl hdmiControl = getHdmiControl(); + if (hdmiControl != null) { + hdmiControl.turnOnTv(); + } return true; } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index b41bc5c2dc51..5a3464d8a35f 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -513,10 +513,7 @@ public final class PowerManagerService extends SystemService // The screen brightness setting override from the window manager // to allow the current foreground activity to override the brightness. - // Use -1 to disable. - private int mScreenBrightnessOverrideFromWindowManager = -1; - - private float mScreenBrightnessOverrideFromWindowManagerFloat = + private float mScreenBrightnessOverrideFromWindowManager = PowerManager.BRIGHTNESS_INVALID_FLOAT; // The window manager has determined the user to be inactive via other means. @@ -2846,7 +2843,7 @@ public final class PowerManagerService extends SystemService screenBrightnessOverride = mScreenBrightnessSettingDefault; } else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) { autoBrightness = false; - screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManagerFloat; + screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager; } else { autoBrightness = (mScreenBrightnessModeSetting == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); @@ -2927,8 +2924,8 @@ public final class PowerManagerService extends SystemService return !mIsVrModeEnabled && mScreenBrightnessBoostInProgress; } - private static boolean isValidBrightness(int value) { - return value >= 0 && value <= 255; + private static boolean isValidBrightness(float value) { + return value >= PowerManager.BRIGHTNESS_MIN && value <= PowerManager.BRIGHTNESS_MAX; } @VisibleForTesting @@ -3222,6 +3219,10 @@ public final class PowerManagerService extends SystemService private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm, @Nullable final String reason, boolean wait) { if (PowerManager.REBOOT_USERSPACE.equals(reason)) { + if (!PowerManager.isRebootingUserspaceSupportedImpl()) { + throw new UnsupportedOperationException( + "Attempted userspace reboot on a device that doesn't support it"); + } UserspaceRebootLogger.noteUserspaceRebootWasRequested(); } if (mHandler == null || !mSystemReady) { @@ -3583,13 +3584,11 @@ public final class PowerManagerService extends SystemService } } - // TODO(brightnessfloat): change to float - private void setScreenBrightnessOverrideFromWindowManagerInternal(int brightness) { + private void setScreenBrightnessOverrideFromWindowManagerInternal(float brightness) { synchronized (mLock) { - if (mScreenBrightnessOverrideFromWindowManager != brightness) { + if (!BrightnessSynchronizer.floatEquals(mScreenBrightnessOverrideFromWindowManager, + brightness)) { mScreenBrightnessOverrideFromWindowManager = brightness; - mScreenBrightnessOverrideFromWindowManagerFloat = - BrightnessSynchronizer.brightnessIntToFloat(mContext, brightness); mDirty |= DIRTY_SETTINGS; updatePowerStateLocked(); } @@ -3890,8 +3889,8 @@ public final class PowerManagerService extends SystemService + isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() + ")"); pw.println(" mStayOnWhilePluggedInSetting=" + mStayOnWhilePluggedInSetting); pw.println(" mScreenBrightnessModeSetting=" + mScreenBrightnessModeSetting); - pw.println(" mScreenBrightnessOverrideFromWindowManagerFloat=" - + mScreenBrightnessOverrideFromWindowManagerFloat); + pw.println(" mScreenBrightnessOverrideFromWindowManager=" + + mScreenBrightnessOverrideFromWindowManager); pw.println(" mUserActivityTimeoutOverrideFromWindowManager=" + mUserActivityTimeoutOverrideFromWindowManager); pw.println(" mUserInactiveOverrideFromWindowManager=" @@ -4231,7 +4230,7 @@ public final class PowerManagerService extends SystemService proto.write( PowerServiceSettingsAndConfigurationDumpProto .SCREEN_BRIGHTNESS_OVERRIDE_FROM_WINDOW_MANAGER, - mScreenBrightnessOverrideFromWindowManagerFloat); + mScreenBrightnessOverrideFromWindowManager); proto.write( PowerServiceSettingsAndConfigurationDumpProto .USER_ACTIVITY_TIMEOUT_OVERRIDE_FROM_WINDOW_MANAGER_MS, @@ -5430,10 +5429,10 @@ public final class PowerManagerService extends SystemService @VisibleForTesting final class LocalService extends PowerManagerInternal { @Override - public void setScreenBrightnessOverrideFromWindowManager(int screenBrightness) { - if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT - || screenBrightness > PowerManager.BRIGHTNESS_ON) { - screenBrightness = PowerManager.BRIGHTNESS_DEFAULT; + public void setScreenBrightnessOverrideFromWindowManager(float screenBrightness) { + if (screenBrightness < PowerManager.BRIGHTNESS_MIN + || screenBrightness > PowerManager.BRIGHTNESS_MAX) { + screenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; } setScreenBrightnessOverrideFromWindowManagerInternal(screenBrightness); } diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 5f871ad4f9e4..83e99b008b68 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -505,6 +505,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { rollbackIds[i] = mRollbacks.get(i).info.getRollbackId(); } ApexManager.getInstance().destroyCeSnapshotsNotSpecified(userId, rollbackIds); + try { + mInstaller.destroyCeSnapshotsNotSpecified(userId, rollbackIds); + } catch (Installer.InstallerException ie) { + Slog.e(TAG, "Failed to delete snapshots for user: " + userId, ie); + } } @WorkerThread 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 929d92f56c44..635cb613b934 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java @@ -27,7 +27,9 @@ import android.media.soundtrigger_middleware.PhraseSoundModel; import android.media.soundtrigger_middleware.RecognitionConfig; import android.media.soundtrigger_middleware.SoundModel; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; +import android.os.Parcel; import android.os.RemoteException; +import android.os.SystemProperties; import android.util.Log; import com.android.server.SystemService; @@ -99,6 +101,28 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic } } + @Override + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + try { + return super.onTransact(code, data, reply, flags); + } catch (InternalServerError e) { + if (e.getCause() instanceof HalException) { + // We recover from any sort of HAL failure by rebooting the HAL process. + // This will likely reboot more than just the sound trigger HAL. + // The rest of the system should be able to tolerate that. + rebootHal(); + } + throw e; + } + } + + private static void rebootHal() { + Log.i(TAG, "Rebooting the sound trigger HAL"); + // This property needs to be defined in an init.rc script and trigger a HAL reboot. + SystemProperties.set("sys.audio.restart.hal", "1"); + } + private final static class ModuleService extends ISoundTriggerModule.Stub { private final ISoundTriggerModule mDelegate; @@ -119,7 +143,6 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic @Override public void unloadModel(int modelHandle) throws RemoteException { mDelegate.unloadModel(modelHandle); - ; } @Override @@ -159,6 +182,22 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic public void detach() throws RemoteException { mDelegate.detach(); } + + @Override + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + try { + return super.onTransact(code, data, reply, flags); + } catch (InternalServerError e) { + if (e.getCause() instanceof HalException) { + // We recover from any sort of HAL failure by rebooting the HAL process. + // This will likely reboot more than just the sound trigger HAL. + // The rest of the system should be able to tolerate that. + rebootHal(); + } + throw e; + } + } } /** 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 da1b7f3113c4..23259558eeb7 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java @@ -149,13 +149,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware e.getMessage()); } - /* Throwing an exception is not enough in this case. When the HAL behaves unexpectedly, the - system service and the HAL must be reset and the client must be notified. Without a full - reset in this catastrophic case, the state of the HAL and the system service cannot be - guaranteed to the client. - */ - Log.wtf(TAG, "Crashing system server due to unrecoverable exception", e); - Process.killProcess(Process.myPid()); + Log.wtf(TAG, "Unexpected exception", e); throw new InternalServerError(e); } diff --git a/services/core/java/com/android/server/stats/pull/SettingsStatsUtil.java b/services/core/java/com/android/server/stats/pull/SettingsStatsUtil.java new file mode 100644 index 000000000000..7cdb84ba0404 --- /dev/null +++ b/services/core/java/com/android/server/stats/pull/SettingsStatsUtil.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.stats.pull; + +import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE; +import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE; +import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE; +import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ContentResolver; +import android.content.Context; +import android.provider.DeviceConfig; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Base64; +import android.util.Slog; +import android.util.StatsEvent; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; +import com.android.service.nano.StringListParamProto; + +import java.util.ArrayList; +import java.util.List; + +/** + * Utility methods for creating {@link StatsEvent} data. + */ +final class SettingsStatsUtil { + private static final String TAG = "SettingsStatsUtil"; + private static final FlagsData[] GLOBAL_SETTINGS = new FlagsData[]{ + new FlagsData("GlobalFeature__boolean_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), + new FlagsData("GlobalFeature__integer_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), + new FlagsData("GlobalFeature__float_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), + new FlagsData("GlobalFeature__string_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) + }; + private static final FlagsData[] SECURE_SETTINGS = new FlagsData[]{ + new FlagsData("SecureFeature__boolean_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), + new FlagsData("SecureFeature__integer_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), + new FlagsData("SecureFeature__float_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), + new FlagsData("SecureFeature__string_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) + }; + private static final FlagsData[] SYSTEM_SETTINGS = new FlagsData[]{ + new FlagsData("SystemFeature__boolean_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), + new FlagsData("SystemFeature__integer_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), + new FlagsData("SystemFeature__float_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), + new FlagsData("SystemFeature__string_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) + }; + + @VisibleForTesting + @NonNull + static List<StatsEvent> logGlobalSettings(Context context, int atomTag, int userId) { + final List<StatsEvent> output = new ArrayList<>(); + final ContentResolver resolver = context.getContentResolver(); + + for (FlagsData flagsData : GLOBAL_SETTINGS) { + StringListParamProto proto = getList(flagsData.mFlagName); + if (proto == null) { + continue; + } + for (String key : proto.element) { + final String value = Settings.Global.getStringForUser(resolver, key, userId); + output.add(createStatsEvent(atomTag, key, value, userId, + flagsData.mDataType)); + } + } + return output; + } + + @NonNull + static List<StatsEvent> logSystemSettings(Context context, int atomTag, int userId) { + final List<StatsEvent> output = new ArrayList<>(); + final ContentResolver resolver = context.getContentResolver(); + + for (FlagsData flagsData : SYSTEM_SETTINGS) { + StringListParamProto proto = getList(flagsData.mFlagName); + if (proto == null) { + continue; + } + for (String key : proto.element) { + final String value = Settings.System.getStringForUser(resolver, key, userId); + output.add(createStatsEvent(atomTag, key, value, userId, + flagsData.mDataType)); + } + } + return output; + } + + @NonNull + static List<StatsEvent> logSecureSettings(Context context, int atomTag, int userId) { + final List<StatsEvent> output = new ArrayList<>(); + final ContentResolver resolver = context.getContentResolver(); + + for (FlagsData flagsData : SECURE_SETTINGS) { + StringListParamProto proto = getList(flagsData.mFlagName); + if (proto == null) { + continue; + } + for (String key : proto.element) { + final String value = Settings.Secure.getStringForUser(resolver, key, userId); + output.add(createStatsEvent(atomTag, key, value, userId, + flagsData.mDataType)); + } + } + return output; + } + + @VisibleForTesting + @Nullable + static StringListParamProto getList(String flag) { + final String base64 = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, flag); + if (TextUtils.isEmpty(base64)) { + return null; + } + final byte[] decode = Base64.decode(base64, Base64.NO_PADDING | Base64.NO_WRAP); + StringListParamProto list = null; + try { + list = StringListParamProto.parseFrom(decode); + } catch (Exception e) { + Slog.e(TAG, "Error parsing string list proto", e); + } + return list; + } + + /** + * Create {@link StatsEvent} for SETTING_SNAPSHOT atom + */ + @NonNull + private static StatsEvent createStatsEvent(int atomTag, String key, String value, int userId, + int type) { + final StatsEvent.Builder builder = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeString(key); + boolean booleanValue = false; + int intValue = 0; + float floatValue = 0; + String stringValue = ""; + if (TextUtils.isEmpty(value)) { + builder.writeInt(FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__NOTASSIGNED) + .writeBoolean(booleanValue) + .writeInt(intValue) + .writeFloat(floatValue) + .writeString(stringValue) + .writeInt(userId); + } else { + switch (type) { + case SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE: + booleanValue = "1".equals(value); + break; + case FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE: + try { + intValue = Integer.parseInt(value); + } catch (NumberFormatException e) { + Slog.w(TAG, "Can not parse value to float: " + value); + } + break; + case SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE: + try { + floatValue = Float.parseFloat(value); + } catch (NumberFormatException e) { + Slog.w(TAG, "Can not parse value to float: " + value); + } + break; + case FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE: + stringValue = value; + break; + default: + Slog.w(TAG, "Unexpected value type " + type); + } + builder.writeInt(type) + .writeBoolean(booleanValue) + .writeInt(intValue) + .writeFloat(floatValue) + .writeString(stringValue) + .writeInt(userId); + } + return builder.build(); + } + + /** Class for defining flag name and its data type. */ + static final class FlagsData { + /** {@link DeviceConfig} flag name, value of the flag is {@link StringListParamProto} */ + String mFlagName; + /** Data type of the value getting from {@link Settings} keys. */ + int mDataType; + + FlagsData(String flagName, int dataType) { + mFlagName = flagName; + mDataType = dataType; + } + } +} diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index e9da2c4c8472..288c22a94b45 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -416,6 +416,8 @@ public class StatsPullAtomService extends SystemService { return pullHealthHal(atomTag, data); case FrameworkStatsLog.ATTRIBUTED_APP_OPS: return pullAttributedAppOps(atomTag, data); + case FrameworkStatsLog.SETTING_SNAPSHOT: + return pullSettingsStats(atomTag, data); default: throw new UnsupportedOperationException("Unknown tagId=" + atomTag); } @@ -580,6 +582,7 @@ public class StatsPullAtomService extends SystemService { registerFullBatteryCapacity(); registerBatteryVoltage(); registerBatteryCycleCount(); + registerSettingsStats(); } /** @@ -3244,6 +3247,43 @@ public class StatsPullAtomService extends SystemService { return StatsManager.PULL_SUCCESS; } + private void registerSettingsStats() { + int tagId = FrameworkStatsLog.SETTING_SNAPSHOT; + mStatsManager.setPullAtomCallback( + tagId, + null, // use default PullAtomMetadata values + BackgroundThread.getExecutor(), + mStatsCallbackImpl + ); + } + + int pullSettingsStats(int atomTag, List<StatsEvent> pulledData) { + UserManager userManager = mContext.getSystemService(UserManager.class); + if (userManager == null) { + return StatsManager.PULL_SKIP; + } + + final long token = Binder.clearCallingIdentity(); + try { + for (UserInfo user : userManager.getUsers()) { + final int userId = user.getUserHandle().getIdentifier(); + + if (userId == UserHandle.USER_SYSTEM) { + pulledData.addAll(SettingsStatsUtil.logGlobalSettings(mContext, atomTag, + UserHandle.USER_SYSTEM)); + } + pulledData.addAll(SettingsStatsUtil.logSystemSettings(mContext, atomTag, userId)); + pulledData.addAll(SettingsStatsUtil.logSecureSettings(mContext, atomTag, userId)); + } + } catch (Exception e) { + Slog.e(TAG, "failed to pullSettingsStats", e); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(token); + } + return StatsManager.PULL_SUCCESS; + } + // Thermal event received from vendor thermal management subsystem private static final class ThermalEventListener extends IThermalEventListener.Stub { @Override diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index d7a0c9871b48..289bf66e1add 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -1380,11 +1380,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override - public void onNotificationBubbleChanged(String key, boolean isBubble) { + public void onNotificationBubbleChanged(String key, boolean isBubble, int flags) { enforceStatusBarService(); long identity = Binder.clearCallingIdentity(); try { - mNotificationDelegate.onNotificationBubbleChanged(key, isBubble); + mNotificationDelegate.onNotificationBubbleChanged(key, isBubble, flags); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/textclassifier/IconsContentProvider.java b/services/core/java/com/android/server/textclassifier/IconsContentProvider.java new file mode 100644 index 000000000000..d19a707770e2 --- /dev/null +++ b/services/core/java/com/android/server/textclassifier/IconsContentProvider.java @@ -0,0 +1,124 @@ +/* + * 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.server.textclassifier; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; +import android.net.Uri; +import android.os.ParcelFileDescriptor; +import android.os.ParcelFileDescriptor.AutoCloseOutputStream; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.textclassifier.IconsUriHelper.ResourceInfo; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * A content provider that is used to access icons returned from the TextClassifier service. + * + * <p>Use {@link IconsUriHelper#getContentUri(String, int)} to access a uri for a specific resource. + * The uri may be passed to other processes to access the specified resource. + * + * <p>NOTE: Care must be taken to avoid leaking resources to non-permitted apps via this provider. + */ +public final class IconsContentProvider extends ContentProvider { + + private static final String TAG = "IconsContentProvider"; + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) { + try { + final ResourceInfo res = IconsUriHelper.getInstance().getResourceInfo(uri); + final Drawable drawable = Icon.createWithResource(res.packageName, res.id) + .loadDrawable(getContext()); + final byte[] data = getBitmapData(drawable); + final ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); + final ParcelFileDescriptor readSide = pipe[0]; + final ParcelFileDescriptor writeSide = pipe[1]; + try (OutputStream out = new AutoCloseOutputStream(writeSide)) { + out.write(data); + return readSide; + } + } catch (IOException | RuntimeException e) { + Log.e(TAG, "Error retrieving icon for uri: " + uri, e); + } + return null; + } + + /** + * Returns the bitmap data for the specified drawable. + */ + @VisibleForTesting + public static byte[] getBitmapData(Drawable drawable) { + if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { + throw new IllegalStateException("The icon is zero-sized"); + } + + final Bitmap bitmap = Bitmap.createBitmap( + drawable.getIntrinsicWidth(), + drawable.getIntrinsicHeight(), + Bitmap.Config.ARGB_8888); + + final Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + + final ByteArrayOutputStream stream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); + final byte[] byteArray = stream.toByteArray(); + bitmap.recycle(); + return byteArray; + } + + @Override + public String getType(Uri uri) { + return "image/png"; + } + + @Override + public boolean onCreate() { + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + return null; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + return 0; + } +} diff --git a/services/core/java/com/android/server/textclassifier/IconsUriHelper.java b/services/core/java/com/android/server/textclassifier/IconsUriHelper.java new file mode 100644 index 000000000000..f17b0f14bd0e --- /dev/null +++ b/services/core/java/com/android/server/textclassifier/IconsUriHelper.java @@ -0,0 +1,144 @@ +/* + * 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.server.textclassifier; + +import android.annotation.Nullable; +import android.net.Uri; +import android.util.ArrayMap; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.function.Supplier; + +/** + * A helper for mapping an icon resource to a content uri. + * + * <p>NOTE: Care must be taken to avoid passing resource uris to non-permitted apps via this helper. + */ +@VisibleForTesting(visibility = Visibility.PACKAGE) +public final class IconsUriHelper { + + public static final String AUTHORITY = "com.android.textclassifier.icons"; + + private static final String TAG = "IconsUriHelper"; + private static final Supplier<String> DEFAULT_ID_SUPPLIER = () -> UUID.randomUUID().toString(); + + // TODO: Consider using an LRU cache to limit resource usage. + // This may depend on the expected number of packages that a device typically has. + @GuardedBy("mPackageIds") + private final Map<String, String> mPackageIds = new ArrayMap<>(); + + private final Supplier<String> mIdSupplier; + + private static final IconsUriHelper sSingleton = new IconsUriHelper(null); + + private IconsUriHelper(@Nullable Supplier<String> idSupplier) { + mIdSupplier = (idSupplier != null) ? idSupplier : DEFAULT_ID_SUPPLIER; + + // Useful for testing: + // Magic id for the android package so it is the same across classloaders. + // This is okay as this package does not have access restrictions, and + // the TextClassifierService hardly returns icons from this package. + mPackageIds.put("android", "android"); + } + + /** + * Returns a new instance of this object for testing purposes. + */ + public static IconsUriHelper newInstanceForTesting(@Nullable Supplier<String> idSupplier) { + return new IconsUriHelper(idSupplier); + } + + static IconsUriHelper getInstance() { + return sSingleton; + } + + /** + * Returns a Uri for the specified icon resource. + * + * @param packageName the resource's package name + * @param resId the resource id + * @see #getResourceInfo(Uri) + */ + public Uri getContentUri(String packageName, int resId) { + Objects.requireNonNull(packageName); + synchronized (mPackageIds) { + if (!mPackageIds.containsKey(packageName)) { + // TODO: Ignore packages that don't actually exist on the device. + mPackageIds.put(packageName, mIdSupplier.get()); + } + return new Uri.Builder() + .scheme("content") + .authority(AUTHORITY) + .path(mPackageIds.get(packageName)) + .appendPath(Integer.toString(resId)) + .build(); + } + } + + /** + * Returns a valid {@link ResourceInfo} for the specified uri. Returns {@code null} if a valid + * {@link ResourceInfo} cannot be returned for the specified uri. + * + * @see #getContentUri(String, int); + */ + @Nullable + public ResourceInfo getResourceInfo(Uri uri) { + if (!"content".equals(uri.getScheme())) { + return null; + } + if (!AUTHORITY.equals(uri.getAuthority())) { + return null; + } + + final List<String> pathItems = uri.getPathSegments(); + try { + synchronized (mPackageIds) { + final String packageId = pathItems.get(0); + final int resId = Integer.parseInt(pathItems.get(1)); + for (String packageName : mPackageIds.keySet()) { + if (packageId.equals(mPackageIds.get(packageName))) { + return new ResourceInfo(packageName, resId); + } + } + } + } catch (Exception e) { + Log.v(TAG, "Could not get resource info. Reason: " + e.getMessage()); + } + return null; + } + + /** + * A holder for a resource's package name and id. + */ + public static final class ResourceInfo { + + public final String packageName; + public final int id; + + private ResourceInfo(String packageName, int id) { + this.packageName = Objects.requireNonNull(packageName); + this.id = id; + } + } +} diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 68224b59a287..4fe58433ddb6 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY; @@ -48,6 +49,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.TypedValue; import android.view.Display; +import android.view.InsetsState; import android.view.MagnificationSpec; import android.view.Surface; import android.view.Surface.OutOfResourcesException; @@ -672,6 +674,15 @@ final class AccessibilityController { availableBounds.op(windowBounds, Region.Op.DIFFERENCE); } + // If the navigation bar window doesn't have touchable region, count + // navigation bar insets into nonMagnifiedBounds. It happens when + // navigation mode is gestural. + if (isUntouchableNavigationBar(windowState, mTempRegion3)) { + final Rect navBarInsets = getNavBarInsets(mDisplayContent); + nonMagnifiedBounds.op(navBarInsets, Region.Op.UNION); + availableBounds.op(navBarInsets, Region.Op.DIFFERENCE); + } + // Count letterbox into nonMagnifiedBounds if (windowState.isLetterboxedForDisplayCutoutLw()) { Region letterboxBounds = getLetterboxBounds(windowState); @@ -1089,6 +1100,24 @@ final class AccessibilityController { } } + static boolean isUntouchableNavigationBar(WindowState windowState, + Region touchableRegion) { + if (windowState.mAttrs.type != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR) { + return false; + } + + // Gets the touchable region. + windowState.getTouchableRegion(touchableRegion); + + return touchableRegion.isEmpty(); + } + + static Rect getNavBarInsets(DisplayContent displayContent) { + final InsetsState insetsState = + displayContent.getInsetsStateController().getRawInsetsState(); + return insetsState.getSource(ITYPE_NAVIGATION_BAR).getFrame(); + } + /** * This class encapsulates the functionality related to computing the windows * reported for accessibility purposes. These windows are all windows a sighted @@ -1203,6 +1232,13 @@ final class AccessibilityController { updateUnaccountedSpace(windowState, regionInScreen, unaccountedSpace, skipRemainingWindowsForTasks); focusedWindowAdded |= windowState.isFocused(); + } else if (isUntouchableNavigationBar(windowState, mTempRegion1)) { + // If this widow is navigation bar without touchable region, accounting the + // region of navigation bar inset because all touch events from this region + // would be received by launcher, i.e. this region is a un-touchable one + // for the application. + unaccountedSpace.op(getNavBarInsets(dc), unaccountedSpace, + Region.Op.REVERSE_DIFFERENCE); } if (unaccountedSpace.isEmpty() && focusedWindowAdded) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5ce63de87ee9..e79b804f76f9 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -42,7 +42,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.activityTypeToString; import static android.content.Intent.ACTION_MAIN; import static android.content.Intent.CATEGORY_HOME; @@ -109,7 +108,6 @@ import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; import static android.view.WindowManager.TRANSIT_TASK_CLOSE; import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_UNSET; -import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; @@ -1300,6 +1298,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (newTask != null && isState(RESUMED)) { newTask.setResumedActivity(this, "onParentChanged"); } + + if (stack != null && stack.topRunningActivity() == this) { + // carry over the PictureInPictureParams to the parent stack without calling + // TaskOrganizerController#dispatchTaskInfoChanged. + // this is to ensure the stack holding up-to-dated pinned stack information + // when activity is re-parented to enter pip mode, see also + // RootWindowContainer#moveActivityToPinnedStack + stack.mPictureInPictureParams.copyOnlySet(pictureInPictureArgs); + // make ensure the TaskOrganizer still works after re-parenting + if (firstWindowDrawn) { + stack.setHasBeenVisible(true); + } + } } private void updateColorTransform() { @@ -2658,6 +2669,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return this; } + // Ensure activity visibilities and update lockscreen occluded/dismiss state when + // finishing the top activity that occluded keyguard. So that, the + // ActivityStack#mTopActivityOccludesKeyguard can be updated and the activity below won't + // be resumed. + if (isState(PAUSED) + && mStackSupervisor.getKeyguardController().isKeyguardLocked() + && getStack().topActivityOccludesKeyguard()) { + getStack().ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, + false /* preserveWindows */, false /* notifyClients */); + } + boolean activityRemoved = false; // If this activity is currently visible, and the resumed activity is not yet visible, then @@ -5114,27 +5136,49 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void startFreezingScreen() { + startFreezingScreen(ROTATION_UNDEFINED /* overrideOriginalDisplayRotation */); + } + + void startFreezingScreen(int overrideOriginalDisplayRotation) { ProtoLog.i(WM_DEBUG_ORIENTATION, "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s", appToken, isVisible(), mFreezingScreen, mVisibleRequested, new RuntimeException().fillInStackTrace()); - if (mVisibleRequested) { - if (!mFreezingScreen) { - mFreezingScreen = true; - mWmService.registerAppFreezeListener(this); - mWmService.mAppsFreezingScreen++; - if (mWmService.mAppsFreezingScreen == 1) { - mWmService.startFreezingDisplayLocked(0, 0, getDisplayContent()); - mWmService.mH.removeMessages(H.APP_FREEZE_TIMEOUT); - mWmService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000); + if (!mVisibleRequested) { + return; + } + + // If the override is given, the rotation of display doesn't change but we still want to + // cover the activity whose configuration is changing by freezing the display and running + // the rotation animation. + final boolean forceRotation = overrideOriginalDisplayRotation != ROTATION_UNDEFINED; + if (!mFreezingScreen) { + mFreezingScreen = true; + mWmService.registerAppFreezeListener(this); + mWmService.mAppsFreezingScreen++; + if (mWmService.mAppsFreezingScreen == 1) { + if (forceRotation) { + // Make sure normal rotation animation will be applied. + mDisplayContent.getDisplayRotation().cancelSeamlessRotation(); } - } - final int count = mChildren.size(); - for (int i = 0; i < count; i++) { - final WindowState w = mChildren.get(i); - w.onStartFreezingScreen(); + mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, + mDisplayContent, overrideOriginalDisplayRotation); + mWmService.mH.removeMessages(H.APP_FREEZE_TIMEOUT); + mWmService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000); } } + if (forceRotation) { + // The rotation of the real display won't change, so in order to unfreeze the screen + // via {@link #checkAppWindowsReadyToShow}, the windows have to be able to call + // {@link WindowState#reportResized} (it is skipped if the window is freezing) to update + // the drawn state. + return; + } + final int count = mChildren.size(); + for (int i = 0; i < count; i++) { + final WindowState w = mChildren.get(i); + w.onStartFreezingScreen(); + } } boolean isFreezingScreen() { @@ -5214,6 +5258,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A updateReportedVisibilityLocked(); } + void onStartingWindowDrawn() { + if (task != null) { + task.setHasBeenVisible(true); + } + } + /** Called when the windows associated app window container are drawn. */ void onWindowsDrawn(boolean drawn, long timestampNs) { mDrawn = drawn; @@ -5588,6 +5638,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A _taskDescription.setIconFilename(iconFilePath); } taskDescription = _taskDescription; + getTask().updateTaskDescription(); } void setVoiceSessionLocked(IVoiceInteractionSession session) { @@ -5812,18 +5863,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } @VisibleForTesting - boolean shouldAnimate(int transit) { - if (task != null && !task.shouldAnimate()) { - return false; - } - final boolean isSplitScreenPrimary = - getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; - final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN; - - // We animate always if it's not split screen primary, and only some special cases in split - // screen primary because it causes issues with stack clipping when we run an un-minimize - // animation at the same time. - return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation; + boolean shouldAnimate() { + return task == null || task.shouldAnimate(); } /** @@ -6151,6 +6192,21 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); } + @Override + void onCancelFixedRotationTransform(int originalDisplayRotation) { + if (this != mDisplayContent.getLastOrientationSource() + || getRequestedConfigurationOrientation() != ORIENTATION_UNDEFINED) { + // Only need to handle the activity that should be rotated with display. + return; + } + + // Perform rotation animation according to the rotation of this activity. + startFreezingScreen(originalDisplayRotation); + // This activity may relaunch or perform configuration change so once it has reported drawn, + // the screen can be unfrozen. + ensureActivityConfiguration(0 /* globalChanges */, !PRESERVE_WINDOWS); + } + void setRequestedOrientation(int requestedOrientation) { setOrientation(requestedOrientation, mayFreezeScreenLocked()); mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( @@ -6496,11 +6552,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final Rect containingBounds = mTmpBounds; mCompatDisplayInsets.getContainerBounds(containingAppBounds, containingBounds, rotation, orientation, orientationRequested, canChangeOrientation); - resolvedBounds.set(containingAppBounds); + resolvedBounds.set(containingBounds); // The size of floating task is fixed (only swap), so the aspect ratio is already correct. if (!mCompatDisplayInsets.mIsFloating) { applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds); } + // If the bounds are restricted by fixed aspect ratio, the resolved bounds should be put in + // the container app bounds. Otherwise the entire container bounds are available. + final boolean fillContainer = resolvedBounds.equals(containingBounds); + if (!fillContainer) { + // The horizontal position should not cover insets. + resolvedBounds.left = containingAppBounds.left; + } // Use resolvedBounds to compute other override configurations such as appBounds. The bounds // are calculated in compat container space. The actual position on screen will be applied @@ -6569,7 +6632,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final int offsetX = getHorizontalCenterOffset( (int) viewportW, (int) (contentW * mSizeCompatScale)); // Above coordinates are in "@" space, now place "*" and "#" to screen space. - final int screenPosX = parentAppBounds.left + offsetX; + final int screenPosX = (fillContainer ? parentBounds.left : parentAppBounds.left) + offsetX; final int screenPosY = parentBounds.top; if (screenPosX != 0 || screenPosY != 0) { if (mSizeCompatBounds != null) { @@ -7367,7 +7430,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } final ActivityStack stack = getRootTask(); return stack != null && - stack.checkKeyguardVisibility(this, true /* shouldBeVisible */, true /* isTop */); + stack.checkKeyguardVisibility(this, true /* shouldBeVisible */, + stack.topRunningActivity() == this /* isTop */); } void setTurnScreenOn(boolean turnScreenOn) { @@ -7666,8 +7730,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Ensure the app bounds won't overlap with insets. Task.intersectWithInsetsIfFits(outAppBounds, outBounds, mNonDecorInsets[rotation]); } - // The horizontal position is centered and it should not cover insets. - outBounds.left = outAppBounds.left; } } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index f5eba96a96d1..8bf46bc7c2e8 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -20,7 +20,6 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; @@ -685,9 +684,7 @@ class ActivityStack extends Task { return; } - setWindowingMode(windowingMode, false /* animate */, false /* showRecents */, - false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */, - false /* creating */); + setWindowingMode(windowingMode, false /* creating */); } /** @@ -709,27 +706,22 @@ class ActivityStack extends Task { * @param preferredWindowingMode the preferred windowing mode. This may not be honored depending * on the state of things. For example, WINDOWING_MODE_UNDEFINED will resolve to the * previous non-transient mode if this stack is currently in a transient mode. - * @param animate Can be used to prevent animation. - * @param showRecents Controls whether recents is shown on the other side of a split while - * entering split mode. - * @param enteringSplitScreenMode {@code true} if entering split mode. - * @param deferEnsuringVisibility Whether visibility updates are deferred. This is set when - * many operations (which can effect visibility) are being performed in bulk. * @param creating {@code true} if this is being run during ActivityStack construction. */ - void setWindowingMode(int preferredWindowingMode, boolean animate, boolean showRecents, - boolean enteringSplitScreenMode, boolean deferEnsuringVisibility, boolean creating) { + void setWindowingMode(int preferredWindowingMode, boolean creating) { mWmService.inSurfaceTransaction(() -> setWindowingModeInSurfaceTransaction( - preferredWindowingMode, animate, showRecents, enteringSplitScreenMode, - deferEnsuringVisibility, creating)); + preferredWindowingMode, creating)); } - private void setWindowingModeInSurfaceTransaction(int preferredWindowingMode, boolean animate, - boolean showRecents, boolean enteringSplitScreenMode, boolean deferEnsuringVisibility, + private void setWindowingModeInSurfaceTransaction(int preferredWindowingMode, boolean creating) { + final TaskDisplayArea taskDisplayArea = getDisplayArea(); + if (taskDisplayArea == null) { + Slog.d(TAG, "taskDisplayArea is null, bail early"); + return; + } final int currentMode = getWindowingMode(); final int currentOverrideMode = getRequestedOverrideWindowingMode(); - final TaskDisplayArea taskDisplayArea = getDisplayArea(); final Task topTask = getTopMostTask(); int windowingMode = preferredWindowingMode; if (preferredWindowingMode == WINDOWING_MODE_UNDEFINED @@ -753,12 +745,9 @@ class ActivityStack extends Task { final boolean alreadyInSplitScreenMode = taskDisplayArea.isSplitScreenModeActivated(); - // Don't send non-resizeable notifications if the windowing mode changed was a side effect - // of us entering split-screen mode. - final boolean sendNonResizeableNotification = !enteringSplitScreenMode; // Take any required action due to us not supporting the preferred windowing mode. if (alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN - && sendNonResizeableNotification && isActivityTypeStandardOrUndefined()) { + && isActivityTypeStandardOrUndefined()) { final boolean preferredSplitScreen = preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; @@ -768,7 +757,7 @@ class ActivityStack extends Task { // warning toast about it. mAtmService.getTaskChangeNotificationController() .notifyActivityDismissingDockedStack(); - taskDisplayArea.onSplitScreenModeDismissed(); + taskDisplayArea.onSplitScreenModeDismissed(this); } } @@ -794,7 +783,12 @@ class ActivityStack extends Task { if (currentMode == WINDOWING_MODE_PINNED) { mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned(); } - if (sendNonResizeableNotification && likelyResolvedMode != WINDOWING_MODE_FULLSCREEN + if (likelyResolvedMode == WINDOWING_MODE_PINNED + && taskDisplayArea.getRootPinnedTask() != null) { + // Can only have 1 pip at a time, so replace an existing pip + taskDisplayArea.getRootPinnedTask().dismissPip(); + } + if (likelyResolvedMode != WINDOWING_MODE_FULLSCREEN && topActivity != null && !topActivity.noDisplay && topActivity.isNonResizableOrForcedResizable(likelyResolvedMode)) { // Inform the user that they are starting an app that may not work correctly in @@ -806,7 +800,7 @@ class ActivityStack extends Task { mAtmService.deferWindowLayout(); try { - if (!animate && topActivity != null) { + if (topActivity != null) { mStackSupervisor.mNoAnimActivities.add(topActivity); } super.setWindowingMode(windowingMode); @@ -845,36 +839,11 @@ class ActivityStack extends Task { false /*preserveWindows*/, true /*deferResume*/); } } finally { - if (showRecents && !alreadyInSplitScreenMode && isOnHomeDisplay() - && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - // Make sure recents stack exist when creating a dock stack as it normally needs to - // be on the other side of the docked stack and we make visibility decisions based - // on that. - // TODO: This is only here to help out with the case where recents stack doesn't - // exist yet. For that case the initial size of the split-screen stack will be the - // the one where the home stack is visible since recents isn't visible yet, but the - // divider will be off. I think we should just make the initial bounds that of home - // so that the divider matches and remove this logic. - // TODO: This is currently only called when entering split-screen while in another - // task, and from the tests - // TODO (b/78247419): Fix the rotation animation from fullscreen to minimized mode - final boolean isRecentsComponentHome = - mAtmService.getRecentTasks().isRecentsComponentHomeActivity(mCurrentUser); - final ActivityStack recentStack = taskDisplayArea.getOrCreateStack( - WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, - isRecentsComponentHome ? ACTIVITY_TYPE_HOME : ACTIVITY_TYPE_RECENTS, - true /* onTop */); - recentStack.moveToFront("setWindowingMode"); - // If task moved to docked stack - show recents if needed. - mWmService.showRecentApps(); - } mAtmService.continueWindowLayout(); } - if (!deferEnsuringVisibility) { - mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); - mRootWindowContainer.resumeFocusedStacksTopActivities(); - } + mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); + mRootWindowContainer.resumeFocusedStacksTopActivities(); } @Override @@ -1085,6 +1054,9 @@ class ActivityStack extends Task { } /** + * This moves 'task' to the back of this task and also recursively moves this task to the back + * of its parents (if applicable). + * * @param reason The reason for moving the stack to the back. * @param task If non-null, the task will be moved to the bottom of the stack. **/ @@ -1092,18 +1064,41 @@ class ActivityStack extends Task { if (!isAttached()) { return; } - - getDisplayArea().positionStackAtBottom(this, reason); - if (task != null && task != this) { - positionChildAtBottom(task); + final TaskDisplayArea displayArea = getDisplayArea(); + if (!mCreatedByOrganizer) { + // If this is just a normal task, so move to back of parent and then move 'task' to + // back of this. + final WindowContainer parent = getParent(); + final Task parentTask = parent != null ? parent.asTask() : null; + if (parentTask != null) { + ((ActivityStack) parentTask).moveToBack(reason, this); + } else { + displayArea.positionStackAtBottom(this, reason); + } + if (task != null && task != this) { + positionChildAtBottom(task); + } + return; } - - /** - * The intent behind moving a primary split screen stack to the back is usually to hide - * behind the home stack. Exit split screen in this case. - */ - if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - setWindowingMode(WINDOWING_MODE_UNDEFINED); + if (task == null || task == this) { + return; + } + // This is a created-by-organizer task. In this case, let the organizer deal with this + // task's ordering. However, we still need to move 'task' to back. The intention is that + // this ends up behind the home-task so that it is made invisible; so, if the home task + // is not a child of this, reparent 'task' to the back of the home task's actual parent. + final ActivityStack home = displayArea.getOrCreateRootHomeTask(); + final WindowContainer homeParent = home.getParent(); + final Task homeParentTask = homeParent != null ? homeParent.asTask() : null; + if (homeParentTask == null) { + ((ActivityStack) task).reparent(displayArea, false /* onTop */); + } else if (homeParentTask == this) { + // Apparently reparent early-outs if same stack, so we have to explicitly reorder. + positionChildAtBottom(task); + } else { + task.reparent((ActivityStack) homeParentTask, false /* toTop */, + REPARENT_LEAVE_STACK_IN_PLACE, false /* animate */, false /* deferResume */, + "moveToBack"); } } @@ -2308,7 +2303,7 @@ class ActivityStack extends Task { ActivityOptions.abort(options); if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeNextFocusableActivityWhenStackIsEmpty: " + reason + ", go home"); - return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayId()); + return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea()); } void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity, @@ -3443,18 +3438,6 @@ class ActivityStack extends Task { outBounds.set(mBoundsAnimationSourceHintBounds); } - /** - * @return the final animation bounds if the task stack is currently being animated, or the - * current stack bounds otherwise. - */ - void getAnimationOrCurrentBounds(Rect outBounds) { - if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) { - getFinalAnimationBounds(outBounds); - return; - } - getBounds(outBounds); - } - /** Bounds of the stack with other system factors taken into consideration. */ void getDimBounds(Rect out) { getBounds(out); diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 02601ff4b6e3..f924bd4ea194 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -44,7 +44,6 @@ import static android.os.Process.INVALID_UID; import static android.os.Process.SYSTEM_UID; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.TYPE_VIRTUAL; import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; @@ -80,8 +79,6 @@ import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE; import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED; import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT; -import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE; -import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowContainer.POSITION_TOP; @@ -140,7 +137,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.ReferrerIntent; import com.android.internal.os.TransferPipe; -import com.android.internal.os.logging.MetricsLoggerWrapper; import com.android.internal.util.ArrayUtils; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledLambda; @@ -382,71 +378,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { private boolean mInitialized; - private final MoveTaskToFullscreenHelper mMoveTaskToFullscreenHelper = - new MoveTaskToFullscreenHelper(); - private class MoveTaskToFullscreenHelper { - private TaskDisplayArea mToDisplayArea; - private boolean mOnTop; - private Task mTopTask; - private boolean mSchedulePictureInPictureModeChange; - - void process(ActivityStack fromStack, TaskDisplayArea toDisplayArea, boolean onTop, - boolean schedulePictureInPictureModeChange) { - mSchedulePictureInPictureModeChange = schedulePictureInPictureModeChange; - mToDisplayArea = toDisplayArea; - mOnTop = onTop; - mTopTask = fromStack.getTopMostTask(); - - final PooledConsumer c = PooledLambda.obtainConsumer( - MoveTaskToFullscreenHelper::processLeafTask, this, PooledLambda.__(Task.class)); - fromStack.forAllLeafTasks(c, false /* traverseTopToBottom */); - c.recycle(); - mToDisplayArea = null; - mTopTask = null; - } - - private void processLeafTask(Task task) { - // This is a one level task that we don't need to create stack for reparenting to. - if (task.isRootTask() && DisplayContent.alwaysCreateStack(WINDOWING_MODE_FULLSCREEN, - task.getActivityType())) { - final ActivityStack stack = (ActivityStack) task; - stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - if (mToDisplayArea.getDisplayId() != stack.getDisplayId()) { - stack.reparent(mToDisplayArea, mOnTop); - } else if (mOnTop) { - mToDisplayArea.positionStackAtTop(stack, false /* includingParents */); - } else { - mToDisplayArea.positionStackAtBottom(stack); - } - return; - } - - final ActivityStack toStack = mToDisplayArea.getOrCreateStack(null, mTmpOptions, task, - task.getActivityType(), mOnTop); - if (task == toStack) { - // The task was reused as the root task. - return; - } - - if (mOnTop) { - final boolean isTopTask = task == mTopTask; - // Defer resume until all the tasks have been moved to the fullscreen stack - task.reparent(toStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, isTopTask /*animate*/, - DEFER_RESUME, mSchedulePictureInPictureModeChange, - "moveTasksToFullscreenStack - onTop"); - MetricsLoggerWrapper.logPictureInPictureFullScreen(mService.mContext, - task.effectiveUid, task.realActivity.flattenToString()); - } else { - // Position the tasks in the fullscreen stack in order at the bottom of the - // stack. Also defer resume until all the tasks have been moved to the - // fullscreen stack. - task.reparent(toStack, ON_TOP, REPARENT_LEAVE_STACK_IN_PLACE, - !ANIMATE, DEFER_RESUME, mSchedulePictureInPictureModeChange, - "moveTasksToFullscreenStack - NOT_onTop"); - } - } - } - /** * Description of a request to start a new activity, which has been held * due to app switches being disabled. @@ -1446,8 +1377,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { if (DEBUG_STACK) Slog.d(TAG_STACK, "findTaskToMoveToFront: moved to front of stack=" + currentStack); - handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, - currentStack, forceNonResizeable); + handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, + mRootWindowContainer.getDefaultTaskDisplayArea(), currentStack, forceNonResizeable); } private void moveHomeStackToFrontIfNeeded(int flags, TaskDisplayArea taskDisplayArea, @@ -1501,41 +1432,43 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mResizingTasksDuringAnimation.clear(); } - /** - * TODO: This should just change the windowing mode and resize vs. actually moving task around. - * Can do that once we are no longer using static stack ids. - */ - private void moveTasksToFullscreenStackInSurfaceTransaction(ActivityStack fromStack, - int toDisplayId, boolean onTop) { + void setSplitScreenResizing(boolean resizing) { + if (resizing == mDockedStackResizing) { + return; + } - mService.deferWindowLayout(); - try { - final int windowingMode = fromStack.getWindowingMode(); - final TaskDisplayArea toDisplayArea = mRootWindowContainer - .getDisplayContent(toDisplayId).getDefaultTaskDisplayArea(); + mDockedStackResizing = resizing; + mWindowManager.setDockedStackResizing(resizing); + } - if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - // We are moving all tasks from the docked stack to the fullscreen stack, - // which is dismissing the docked stack, so resize all other stacks to - // fullscreen here already so we don't end up with resize trashing. - for (int i = toDisplayArea.getStackCount() - 1; i >= 0; --i) { - final ActivityStack otherStack = toDisplayArea.getStackAt(i); - if (!otherStack.inSplitScreenSecondaryWindowingMode()) { - continue; - } - otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED); - } - } + private void removePinnedStackInSurfaceTransaction(ActivityStack stack) { + /** + * Workaround: Force-stop all the activities in the pinned stack before we reparent them + * to the fullscreen stack. This is to guarantee that when we are removing a stack, + * that the client receives onStop() before it is reparented. We do this by detaching + * the stack from the display so that it will be considered invisible when + * ensureActivitiesVisible() is called, and all of its activities will be marked + * invisible as well and added to the stopping list. After which we process the + * stopping list by handling the idle. + */ + stack.cancelAnimation(); + stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */); + stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); + stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */); + activityIdleInternal(null /* idleActivity */, false /* fromTimeout */, + true /* processPausingActivities */, null /* configuration */); - // If we are moving from the pinned stack, then the animation takes care of updating - // the picture-in-picture mode. - final boolean schedulePictureInPictureModeChange = - windowingMode == WINDOWING_MODE_PINNED; + // Reparent all the tasks to the bottom of the display + final DisplayContent toDisplay = + mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY); - if (fromStack.hasChild()) { - mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); - mMoveTaskToFullscreenHelper.process( - fromStack, toDisplayArea, onTop, schedulePictureInPictureModeChange); + mService.deferWindowLayout(); + try { + stack.setWindowingMode(WINDOWING_MODE_UNDEFINED); + if (toDisplay.getDisplayId() != stack.getDisplayId()) { + stack.reparent(toDisplay.getDefaultTaskDisplayArea(), false /* onTop */); + } else { + toDisplay.getDefaultTaskDisplayArea().positionStackAtBottom(stack); } mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); @@ -1545,41 +1478,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } } - void moveTasksToFullscreenStackLocked(ActivityStack fromStack, boolean onTop) { - // TODO(b/153089193): Support moving within the same task display area - mWindowManager.inSurfaceTransaction(() -> - moveTasksToFullscreenStackInSurfaceTransaction(fromStack, DEFAULT_DISPLAY, onTop)); - } - - void setSplitScreenResizing(boolean resizing) { - if (resizing == mDockedStackResizing) { - return; - } - - mDockedStackResizing = resizing; - mWindowManager.setDockedStackResizing(resizing); - } - private void removeStackInSurfaceTransaction(ActivityStack stack) { if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) { - /** - * Workaround: Force-stop all the activities in the pinned stack before we reparent them - * to the fullscreen stack. This is to guarantee that when we are removing a stack, - * that the client receives onStop() before it is reparented. We do this by detaching - * the stack from the display so that it will be considered invisible when - * ensureActivitiesVisible() is called, and all of its activities will be marked - * invisible as well and added to the stopping list. After which we process the - * stopping list by handling the idle. - */ - stack.cancelAnimation(); - stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */); - stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); - stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */); - activityIdleInternal(null /* idleActivity */, false /* fromTimeout */, - true /* processPausingActivities */, null /* configuration */); - - // Move all the tasks to the bottom of the fullscreen stack - moveTasksToFullscreenStackLocked(stack, !ON_TOP); + removePinnedStackInSurfaceTransaction(stack); } else { final PooledConsumer c = PooledLambda.obtainConsumer( ActivityStackSupervisor::processRemoveTask, this, PooledLambda.__(Task.class)); @@ -2232,16 +2133,29 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION); } + // TODO(b/152116619): Remove after complete switch to TaskDisplayArea void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode, int preferredDisplayId, ActivityStack actualStack) { - handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId, + final DisplayContent preferredDisplayContent = mRootWindowContainer + .getDisplayContent(preferredDisplayId); + final TaskDisplayArea preferredDisplayArea = preferredDisplayContent != null + ? preferredDisplayContent.getDefaultTaskDisplayArea() + : null; + handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayArea, + actualStack); + } + + void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode, + TaskDisplayArea preferredTaskDisplayArea, ActivityStack actualStack) { + handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredTaskDisplayArea, actualStack, false /* forceNonResizable */); } void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode, - int preferredDisplayId, ActivityStack actualStack, boolean forceNonResizable) { - final boolean isSecondaryDisplayPreferred = - (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY); + TaskDisplayArea preferredTaskDisplayArea, ActivityStack actualStack, + boolean forceNonResizable) { + final boolean isSecondaryDisplayPreferred = preferredTaskDisplayArea != null + && preferredTaskDisplayArea.getDisplayId() != DEFAULT_DISPLAY; final boolean inSplitScreenMode = actualStack != null && actualStack.getDisplayArea().isSplitScreenModeActivated(); if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) @@ -2251,33 +2165,31 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // Handle incorrect launch/move to secondary display if needed. if (isSecondaryDisplayPreferred) { - final int actualDisplayId = task.getDisplayId(); - if (!task.canBeLaunchedOnDisplay(actualDisplayId)) { + if (!task.canBeLaunchedOnDisplay(task.getDisplayId())) { throw new IllegalStateException("Task resolved to incompatible display"); } - final DisplayContent preferredDisplay = - mRootWindowContainer.getDisplayContent(preferredDisplayId); + final DisplayContent preferredDisplay = preferredTaskDisplayArea.mDisplayContent; final boolean singleTaskInstance = preferredDisplay != null && preferredDisplay.isSingleTaskInstance(); - if (preferredDisplayId != actualDisplayId) { + if (preferredDisplay != task.getDisplayContent()) { // Suppress the warning toast if the preferredDisplay was set to singleTask. // The singleTaskInstance displays will only contain one task and any attempt to // launch new task will re-route to the default display. if (singleTaskInstance) { mService.getTaskChangeNotificationController() .notifyActivityLaunchOnSecondaryDisplayRerouted(task.getTaskInfo(), - preferredDisplayId); + preferredDisplay.mDisplayId); return; } - Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplayId); + Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplay.mDisplayId); // Display a warning toast that we failed to put a task on a secondary display. mService.getTaskChangeNotificationController() .notifyActivityLaunchOnSecondaryDisplayFailed(task.getTaskInfo(), - preferredDisplayId); + preferredDisplay.mDisplayId); } else if (!forceNonResizable) { handleForcedResizableTaskIfNeeded(task, FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY); } @@ -2296,7 +2208,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // split-screen in split-screen. mService.getTaskChangeNotificationController() .notifyActivityDismissingDockedStack(); - taskDisplayArea.onSplitScreenModeDismissed(); + taskDisplayArea.onSplitScreenModeDismissed(task.getStack()); taskDisplayArea.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS, true /* notifyClients */); } diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index d777f3fee1a2..ad54356bced6 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.ActivityManager.START_SUCCESS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL; @@ -171,7 +172,8 @@ public class ActivityStartController { mLastStarter.postStartActivityProcessing(r, result, targetStack); } - void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) { + void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, + TaskDisplayArea taskDisplayArea) { final ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); if (!ActivityRecord.isResolverActivity(aInfo.name)) { @@ -180,19 +182,20 @@ public class ActivityStartController { // foreground instead of bring home stack to front. options.setLaunchActivityType(ACTIVITY_TYPE_HOME); } + final int displayId = taskDisplayArea.getDisplayId(); options.setLaunchDisplayId(displayId); + // TODO(b/152116619): Enable after complete switch to WindowContainerToken + //options.setLaunchWindowContainerToken(taskDisplayArea.getWindowContainerToken()); - final DisplayContent display = - mService.mRootWindowContainer.getDisplayContent(displayId); // The home activity will be started later, defer resuming to avoid unneccerary operations // (e.g. start home recursively) when creating home stack. mSupervisor.beginDeferResume(); final ActivityStack homeStack; try { - // TODO(multi-display-area): Support starting home in a task display area - // Make sure home stack exist on display. - homeStack = display.getDefaultTaskDisplayArea().getOrCreateStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); + // Make sure home stack exists on display area. + // TODO(b/153624902): Replace with TaskDisplayArea#getOrCreateRootHomeTask() + homeStack = taskDisplayArea.getOrCreateStack(WINDOWING_MODE_UNDEFINED, + ACTIVITY_TYPE_HOME, ON_TOP); } finally { mSupervisor.endDeferResume(); } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 7a6da6739dc1..0bd1aca4030a 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2422,7 +2422,7 @@ class ActivityStarter { // be destroyed. mTargetStack = intentActivity.getRootTask(); mSupervisor.handleNonResizableTaskIfNeeded(intentTask, WINDOWING_MODE_UNDEFINED, - DEFAULT_DISPLAY, mTargetStack); + mRootWindowContainer.getDefaultTaskDisplayArea(), mTargetStack); } private void resumeTargetStackIfNeeded() { diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 0b1968765300..7a04894523f5 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -3061,8 +3061,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r != null) { r.setTaskDescription(td); - final Task task = r.getTask(); - task.updateTaskDescription(); } } } @@ -3324,33 +3322,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found"); return; } - // Place the task in the right stack if it isn't there already based on - // the requested bounds. - // The stack transition logic is: - // - a null bounds on a freeform task moves that task to fullscreen - // - a non-null bounds on a non-freeform (fullscreen OR docked) task moves - // that task to freeform - // - otherwise the task is not moved - ActivityStack stack = task.getStack(); if (!task.getWindowConfiguration().canResizeTask()) { throw new IllegalArgumentException("resizeTask not allowed on task=" + task); } - if (bounds == null && stack.getWindowingMode() == WINDOWING_MODE_FREEFORM) { - stack = stack.getDisplayArea().getOrCreateStack( - WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), ON_TOP); - } else if (bounds != null && stack.getWindowingMode() != WINDOWING_MODE_FREEFORM) { - stack = stack.getDisplayArea().getOrCreateStack( - WINDOWING_MODE_FREEFORM, stack.getActivityType(), ON_TOP); - } // Reparent the task to the right stack if necessary boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0; - if (stack != task.getStack()) { - // Defer resume until the task is resized below - task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, - DEFER_RESUME, "resizeTask"); - preserveWindow = false; - } // After reparenting (which only resizes the task to the stack bounds), resize the // task to the actual bounds provided @@ -4022,28 +3999,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } - @Override - // TODO: API should just be about changing windowing modes... - public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) { - enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, - "moveTasksToFullscreenStack()"); - synchronized (mGlobalLock) { - final long origId = Binder.clearCallingIdentity(); - try { - final ActivityStack stack = mRootWindowContainer.getStack(fromStackId); - if (stack != null){ - if (!stack.isActivityTypeStandardOrUndefined()) { - throw new IllegalArgumentException( - "You can't move tasks from non-standard stacks."); - } - mStackSupervisor.moveTasksToFullscreenStackLocked(stack, onTop); - } - } finally { - Binder.restoreCallingIdentity(origId); - } - } - } - /** * Moves the top activity in the input stackId to the pinned stack. * @@ -4138,11 +4093,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { r.setPictureInPictureParams(params); final float aspectRatio = r.pictureInPictureArgs.getAspectRatio(); final List<RemoteAction> actions = r.pictureInPictureArgs.getActions(); - // Adjust the source bounds by the insets for the transition down - final Rect sourceBounds = new Rect( - r.pictureInPictureArgs.getSourceRectHint()); mRootWindowContainer.moveActivityToPinnedStack( - r, sourceBounds, aspectRatio, "enterPictureInPictureMode"); + r, "enterPictureInPictureMode"); final ActivityStack stack = r.getRootTask(); stack.setPictureInPictureAspectRatio(aspectRatio); stack.setPictureInPictureActions(actions); diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index f86aeb2244dc..6f1ddcd793a9 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -76,7 +76,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerInternal.AppTransitionListener; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; -import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE; import android.annotation.DrawableRes; @@ -404,11 +403,18 @@ public class AppTransition implements Dump { mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN; } - boolean isNextAppTransitionOpenCrossProfileApps() { return mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS; } + boolean isNextAppTransitionCustomFromRecents() { + final RecentTasks recentTasks = mService.mAtmService.getRecentTasks(); + final String recentsPackageName = + (recentTasks != null) ? recentTasks.getRecentsComponent().getPackageName() : null; + return mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM + && mNextAppTransitionPackage.equals(recentsPackageName); + } + /** * @return true if and only if we are currently fetching app transition specs from the future * passed into {@link #overridePendingAppTransitionMultiThumbFuture} @@ -1807,15 +1813,11 @@ public class AppTransition implements Dump { } int getAppStackClipMode() { - // When dismiss keyguard animation occurs, clip before the animation to prevent docked - // app from showing beyond the divider - if (mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY - || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) { - return STACK_CLIP_BEFORE_ANIM; - } return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH || mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL + || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY + || mNextAppTransition == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER ? STACK_CLIP_NONE : STACK_CLIP_AFTER_ANIM; } diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index 90fdf19d9781..a512337c96ec 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -54,7 +54,6 @@ import java.util.function.Predicate; * - BELOW_TASKS: Can only contain BELOW_TASK DisplayAreas and WindowTokens that go below tasks. * - ABOVE_TASKS: Can only contain ABOVE_TASK DisplayAreas and WindowTokens that go above tasks. * - ANY: Can contain any kind of DisplayArea, and any kind of WindowToken or the Task container. - * Cannot have a sibling that is of type ANY. * * @param <T> type of the children of the DisplayArea. */ @@ -253,6 +252,12 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { super.prepareSurfaces(); getBounds(mTmpDimBoundsRect); + // If SystemUI is dragging for recents, we want to reset the dim state so any dim layer + // on the display level fades out. + if (forAllTasks(task -> !task.canAffectSystemUiFlags())) { + mDimmer.resetDimStates(); + } + if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) { scheduleAnimation(); } @@ -268,7 +273,6 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { ANY; static void checkSiblings(Type bottom, Type top) { - checkState(!(bottom == ANY && top == ANY), "ANY cannot be a sibling of ANY"); checkState(!(bottom != BELOW_TASKS && top == BELOW_TASKS), bottom + " must be above BELOW_TASKS"); checkState(!(bottom == ABOVE_TASKS && top != ABOVE_TASKS), diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java index 982157336295..15b6f9735bf1 100644 --- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java @@ -16,9 +16,14 @@ package com.android.server.wm; +import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER; + import android.content.res.Resources; import android.text.TextUtils; +import java.util.ArrayList; +import java.util.List; + /** * Policy that manages DisplayAreas. */ @@ -37,9 +42,9 @@ public abstract class DisplayAreaPolicy { protected final DisplayArea<? extends WindowContainer> mImeContainer; /** - * The Tasks container. Tasks etc. are automatically added to this container. + * The task display areas. Tasks etc. are automatically added to these containers. */ - protected final DisplayArea<? extends ActivityStack> mTaskContainers; + protected final List<TaskDisplayArea> mTaskDisplayAreas; /** * Construct a new {@link DisplayAreaPolicy} @@ -48,19 +53,19 @@ public abstract class DisplayAreaPolicy { * @param content the display content for which the policy applies * @param root the root display area under which the policy operates * @param imeContainer the ime container that the policy must attach - * @param taskDisplayArea the task container that the policy must attach + * @param taskDisplayAreas the task display areas that the policy must attach * * @see #attachDisplayAreas() */ protected DisplayAreaPolicy(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, - DisplayArea<? extends ActivityStack> taskDisplayArea) { + List<TaskDisplayArea> taskDisplayAreas) { mWmService = wmService; mContent = content; mRoot = root; mImeContainer = imeContainer; - mTaskContainers = taskDisplayArea; + mTaskDisplayAreas = taskDisplayAreas; } /** @@ -80,15 +85,32 @@ public abstract class DisplayAreaPolicy { */ public abstract void addWindow(WindowToken token); + /** + * @return the number of task display areas on the display. + */ + public int getTaskDisplayAreaCount() { + return mTaskDisplayAreas.size(); + } + + /** + * @return the task display area at index. + */ + public TaskDisplayArea getTaskDisplayAreaAt(int index) { + return mTaskDisplayAreas.get(index); + } + /** Provider for platform-default display area policy. */ static final class DefaultProvider implements DisplayAreaPolicy.Provider { @Override public DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, - DisplayArea<? extends WindowContainer> imeContainer, - TaskDisplayArea taskDisplayArea) { + DisplayArea<? extends WindowContainer> imeContainer) { + final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService, + "DefaultTaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER); + final List<TaskDisplayArea> tdaList = new ArrayList<>(); + tdaList.add(defaultTaskDisplayArea); return new DisplayAreaPolicyBuilder() - .build(wmService, content, root, imeContainer, taskDisplayArea); + .build(wmService, content, root, imeContainer, tdaList); } } @@ -107,8 +129,7 @@ public abstract class DisplayAreaPolicy { */ DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, - DisplayArea<? extends WindowContainer> imeContainer, - TaskDisplayArea taskDisplayArea); + DisplayArea<? extends WindowContainer> imeContainer); /** * Instantiate the device-specific {@link Provider}. diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java index e8becfa27fac..2c2f43392eca 100644 --- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java +++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java @@ -201,8 +201,8 @@ class DisplayAreaPolicyBuilder { Result(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, - DisplayArea<? extends ActivityStack> taskDisplayArea, ArrayList<Feature> features) { - super(wmService, content, root, imeContainer, taskDisplayArea); + List<TaskDisplayArea> taskDisplayAreas, ArrayList<Feature> features) { + super(wmService, content, root, imeContainer, taskDisplayAreas); mFeatures = features; mAreas = new HashMap<>(features.size()); for (int i = 0; i < mFeatures.size(); i++) { @@ -267,7 +267,7 @@ class DisplayAreaPolicyBuilder { areaForLayer[layer].mChildren.add(leafArea); leafType = type; if (leafType == LEAF_TYPE_TASK_CONTAINERS) { - leafArea.mExisting = mTaskContainers; + addTaskDisplayAreasToLayer(areaForLayer[layer], layer); } else if (leafType == LEAF_TYPE_IME_CONTAINERS) { leafArea.mExisting = mImeContainer; } @@ -278,6 +278,17 @@ class DisplayAreaPolicyBuilder { root.instantiateChildren(mRoot, mAreaForLayer, 0, mAreas); } + /** Adds all task display areas to the specified layer */ + private void addTaskDisplayAreasToLayer(PendingArea parentPendingArea, int layer) { + final int count = mTaskDisplayAreas.size(); + for (int i = 0; i < count; i++) { + PendingArea leafArea = new PendingArea(null, layer, parentPendingArea); + leafArea.mExisting = mTaskDisplayAreas.get(i); + leafArea.mMaxLayer = layer; + parentPendingArea.mChildren.add(leafArea); + } + } + @Override public void addWindow(WindowToken token) { DisplayArea.Tokens area = findAreaForToken(token); @@ -317,12 +328,16 @@ class DisplayAreaPolicyBuilder { return this; } + protected List<Feature> getFeatures() { + return mFeatures; + } + Result build(WindowManagerService wmService, DisplayContent content, DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, - DisplayArea<? extends ActivityStack> taskDisplayArea) { + List<TaskDisplayArea> taskDisplayAreas) { - return new Result(wmService, content, root, imeContainer, taskDisplayArea, new ArrayList<>( + return new Result(wmService, content, root, imeContainer, taskDisplayAreas, new ArrayList<>( mFeatures)); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index a93b962c33b4..2a676e1de5af 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; @@ -197,7 +198,6 @@ import android.view.ViewRootImpl; import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowManagerPolicyConstants.PointerEventListener; -import android.window.ITaskOrganizer; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; @@ -269,8 +269,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo new NonAppWindowContainers("mOverlayContainers", mWmService); /** The containers below are the only child containers {@link #mWindowContainers} can have. */ - // Contains all window containers that are related to apps (Activities) - final TaskDisplayArea mTaskContainers = new TaskDisplayArea(this, mWmService); // Contains all IME window containers. Note that the z-ordering of the IME windows will depend // on the IME target. We mainly have this container grouping so we can keep track of all the IME @@ -495,6 +493,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * The launching activity which is using fixed rotation transformation. * * @see #handleTopActivityLaunchingInDifferentOrientation + * @see DisplayRotation#shouldRotateSeamlessly */ ActivityRecord mFixedRotationLaunchingApp; @@ -539,6 +538,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo */ WindowState mInputMethodTarget; + /** + * The window which receives input from the input method. This is also a candidate of the + * input method control target. + */ + WindowState mInputMethodInputTarget; + + /** + * This controls the visibility and animation of the input method window. + */ InsetsControlTarget mInputMethodControlTarget; /** If true hold off on modifying the animation layer of mInputMethodTarget */ @@ -972,7 +980,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo super.addChild(mOverlayContainers, null); mDisplayAreaPolicy = mWmService.mDisplayAreaPolicyProvider.instantiate( - mWmService, this, mRootDisplayArea, mImeWindowsContainers, mTaskContainers); + mWmService, this, mRootDisplayArea, mImeWindowsContainers); mWindowContainers.addChildren(); // Sets the display content for the children. @@ -1082,8 +1090,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return null; } mShellRoots.put(windowType, root); - SurfaceControl out = new SurfaceControl(); - out.copyFrom(rootLeash); + SurfaceControl out = new SurfaceControl(rootLeash); return out; } @@ -1239,7 +1246,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (configChanged) { mWaitingForConfig = true; - mWmService.startFreezingDisplayLocked(0 /* exitAnim */, 0 /* enterAnim */, this); + mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, this); sendNewConfiguration(); } @@ -1477,6 +1484,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo sendNewConfiguration(); return true; } + // The display won't rotate (e.g. the orientation from sensor has updated again before + // applying rotation to display), so clear it to stop using seamless rotation. + mFixedRotationLaunchingApp = null; return false; } @@ -2071,13 +2081,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } protected int getTaskDisplayAreaCount() { - // TODO(multi-display-area): Report actual display area count - return 1; + return mDisplayAreaPolicy.getTaskDisplayAreaCount(); } protected TaskDisplayArea getTaskDisplayAreaAt(int index) { - // TODO(multi-display-area): Report actual display area values - return mTaskContainers; + return mDisplayAreaPolicy.getTaskDisplayAreaAt(index); } ActivityStack getStack(int rootTaskId) { @@ -2403,7 +2411,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * or for cases when multi-instance is not supported yet (like Split-screen, PiP or Recents). */ TaskDisplayArea getDefaultTaskDisplayArea() { - return mTaskContainers; + return mDisplayAreaPolicy.getTaskDisplayAreaAt(0); } @Override @@ -3246,6 +3254,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mInsetsStateController.getSourceProvider(ITYPE_IME).setWindow(win, null /* frameProvider */, null /* imeFrameProvider */); computeImeTarget(true /* updateImeTarget */); + updateImeControlTarget(); } /** @@ -3425,8 +3434,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim) { - // Always update control target. This is needed to handle rotation. - updateImeControlTarget(target); if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) { return; } @@ -3435,32 +3442,34 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mInputMethodTargetWaitingAnim = targetWaitingAnim; assignWindowLayers(false /* setLayoutNeeded */); updateImeParent(); + updateImeControlTarget(); } /** - * IME control target is the window that controls the IME visibility and animation. - * This window is same as the window on which startInput is called. - * @param target the window that receives IME control. This is ignored if we aren't attaching - * the IME to an app (eg. when in multi-window mode). + * The IME input target is the window which receives input from IME. It is also a candidate + * which controls the visibility and animation of the input method window. * - * @see #getImeControlTarget() + * @param target the window that receives input from IME. */ - void updateImeControlTarget(InsetsControlTarget target) { + void setInputMethodInputTarget(WindowState target) { + if (mInputMethodInputTarget != target) { + mInputMethodInputTarget = target; + updateImeControlTarget(); + } + } + + private void updateImeControlTarget() { if (!isImeAttachedToApp() && mRemoteInsetsControlTarget != null) { mInputMethodControlTarget = mRemoteInsetsControlTarget; } else { - // Otherwise, we just use the ime target - mInputMethodControlTarget = target; + // Otherwise, we just use the ime input target + mInputMethodControlTarget = mInputMethodInputTarget; } mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget); } private void updateImeParent() { - // Force attaching IME to the display when magnifying, or it would be magnified with - // target app together. - final boolean shouldAttachToDisplay = (mMagnificationSpec != null); - final SurfaceControl newParent = - shouldAttachToDisplay ? mWindowContainers.getSurfaceControl() : computeImeParent(); + final SurfaceControl newParent = computeImeParent(); if (newParent != null) { getPendingTransaction().reparent(mImeWindowsContainers.mSurfaceControl, newParent); scheduleAnimation(); @@ -3472,16 +3481,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo */ @VisibleForTesting SurfaceControl computeImeParent() { + // Force attaching IME to the display when magnifying, or it would be magnified with + // target app together. + final boolean allowAttachToApp = (mMagnificationSpec == null); // Attach it to app if the target is part of an app and such app is covering the entire // screen. If it's not covering the entire screen the IME might extend beyond the apps // bounds. - if (isImeAttachedToApp()) { + if (allowAttachToApp && isImeAttachedToApp()) { return mInputMethodTarget.mActivityRecord.getSurfaceControl(); } - // Otherwise, we just attach it to the display. - return mWindowContainers.getSurfaceControl(); + // Otherwise, we just attach it to where the display area policy put it. + return mImeWindowsContainers.getParent().getSurfaceControl(); } void setLayoutNeeded() { @@ -3554,6 +3566,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo onWallpaper, goingToShade, subtle)); } }, true /* traverseTopToBottom */); + for (int i = mShellRoots.size() - 1; i >= 0; --i) { + mShellRoots.valueAt(i).startAnimation(policy.createHiddenByKeyguardExit( + onWallpaper, goingToShade, subtle)); + } } /** @return {@code true} if there is window to wait before enabling the screen. */ @@ -4722,6 +4738,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mWindowContainers.getSurfaceControl(); } + @VisibleForTesting + WindowContainer<?> getImeContainer() { + return mImeWindowsContainers; + } + SurfaceControl getOverlayLayer() { return mOverlayContainers.getSurfaceControl(); } @@ -5028,6 +5049,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return activityType == ACTIVITY_TYPE_STANDARD && (windowingMode == WINDOWING_MODE_FULLSCREEN || windowingMode == WINDOWING_MODE_FREEFORM + || windowingMode == WINDOWING_MODE_PINNED || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY || windowingMode == WINDOWING_MODE_MULTI_WINDOW); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index f088dbcb0174..e9d3d56ee283 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -696,6 +696,10 @@ public class DisplayPolicy { mForceShowSystemBarsFromExternal = forceShowSystemBars; } + boolean getForceShowSystemBars() { + return mForceShowSystemBarsFromExternal; + } + public boolean hasNavigationBar() { return mHasNavigationBar; } @@ -1494,9 +1498,7 @@ public class DisplayPolicy { final int behavior = mLastBehavior; boolean navVisible = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL ? (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0 - : mNavigationBar != null && mNavigationBar.getControllableInsetProvider() != null - && mNavigationBar.getControllableInsetProvider().isClientVisible() - && !mDisplayContent.getInsetsPolicy().isTransient(ITYPE_NAVIGATION_BAR); + : isNavigationBarRequestedVisible(); boolean navTranslucent = (sysui & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0; boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0 @@ -1533,6 +1535,14 @@ public class DisplayPolicy { mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation; } + boolean isNavigationBarRequestedVisible() { + final InsetsSourceProvider provider = + mDisplayContent.getInsetsStateController().peekSourceProvider(ITYPE_NAVIGATION_BAR); + return provider == null + ? InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR) + : provider.isClientVisible(); + } + void updateHideNavInputEventReceiver(boolean navVisible, boolean navAllowedHidden) { // When the navigation bar isn't visible, we put up a fake input window to catch all // touch events. This way we can detect when the user presses anywhere to bring back the diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index bef80f0a230a..ebfe70c0c371 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -537,8 +537,29 @@ public class DisplayRotation { } void prepareNormalRotationAnimation() { + cancelSeamlessRotation(); final RotationAnimationPair anim = selectRotationAnimation(); - mService.startFreezingDisplayLocked(anim.mExit, anim.mEnter, mDisplayContent); + mService.startFreezingDisplay(anim.mExit, anim.mEnter, mDisplayContent); + } + + /** + * This ensures that normal rotation animation is used. E.g. {@link #mRotatingSeamlessly} was + * set by previous {@link #updateRotationUnchecked}, but another orientation change happens + * before calling {@link DisplayContent#sendNewConfiguration} (remote rotation hasn't finished) + * and it doesn't choose seamless rotation. + */ + void cancelSeamlessRotation() { + if (!mRotatingSeamlessly) { + return; + } + mDisplayContent.forAllWindows(w -> { + if (w.mSeamlesslyRotated) { + w.finishSeamlessRotation(false /* timeout */); + w.mSeamlesslyRotated = false; + } + }, true /* traverseTopToBottom */); + mSeamlessRotationCount = 0; + mRotatingSeamlessly = false; } private void prepareSeamlessRotation() { diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index e4e57168efe7..61a199a816df 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -99,7 +99,7 @@ class InsetsPolicy { } private void updateHideNavInputEventReceiver() { - mPolicy.updateHideNavInputEventReceiver(!isHidden(ITYPE_NAVIGATION_BAR), + mPolicy.updateHideNavInputEventReceiver(mPolicy.isNavigationBarRequestedVisible(), mFocusedWin != null && mFocusedWin.mAttrs.insetsFlags.behavior != BEHAVIOR_SHOW_BARS_BY_TOUCH); } @@ -304,7 +304,10 @@ class InsetsPolicy { // We need to force system bars when the docked stack is visible, when the freeform stack // is visible but also when we are resizing for the transitions when docked stack // visibility changes. - return isDockedStackVisible || isFreeformStackVisible || isResizing; + return isDockedStackVisible + || isFreeformStackVisible + || isResizing + || mPolicy.getForceShowSystemBars(); } @VisibleForTesting diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index 337a68e62043..4a0da75cdad8 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -28,7 +28,6 @@ import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_CURRENT; import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; -import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; @@ -619,7 +618,8 @@ public class LockTaskController { } } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) { mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, - DEFAULT_DISPLAY, task.getStack(), true /* forceNonResizable */); + mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea(), + task.getStack(), true /* forceNonResizable */); } } diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java index 02a27410dc38..56312aa1b0b8 100644 --- a/services/core/java/com/android/server/wm/PinnedStackController.java +++ b/services/core/java/com/android/server/wm/PinnedStackController.java @@ -23,7 +23,6 @@ import android.app.RemoteAction; import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.content.res.Resources; -import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; @@ -285,13 +284,7 @@ class PinnedStackController { return; } try { - final Rect animatingBounds = new Rect(); - final ActivityStack pinnedStack = mDisplayContent.getDefaultTaskDisplayArea() - .getRootPinnedTask(); - if (pinnedStack != null) { - pinnedStack.getAnimationOrCurrentBounds(animatingBounds); - } - mPinnedStackListener.onMovementBoundsChanged(animatingBounds, fromImeAdjustment); + mPinnedStackListener.onMovementBoundsChanged(fromImeAdjustment); } catch (RemoteException e) { Slog.e(TAG_WM, "Error delivering actions changed event.", e); } diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index a031fe82d48b..0a9878dd660b 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -442,10 +442,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // Always prepare an app transition since we rely on the transition callbacks to cleanup mWindowManager.prepareAppTransition(TRANSIT_NONE, false); controller.setCancelOnNextTransitionStart(); - } else { - // Just cancel directly to unleash from launcher when the next launching task is the - // current top task. - mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "stackOrderChanged"); } } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 6fda1170a3f5..54210ae1c0b0 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -43,6 +43,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.IntArray; import android.util.Slog; import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; @@ -99,6 +100,8 @@ public class RecentsAnimationController implements DeathRecipient { private IRecentsAnimationRunner mRunner; private final RecentsAnimationCallbacks mCallbacks; private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>(); + private final IntArray mPendingNewTaskTargets = new IntArray(0); + private final ArrayList<WallpaperAnimationAdapter> mPendingWallpaperAnimations = new ArrayList<>(); private final int mDisplayId; @@ -220,6 +223,10 @@ public class RecentsAnimationController implements DeathRecipient { if (mCanceled) { return; } + // Remove all new task targets. + for (int i = mPendingNewTaskTargets.size() - 1; i >= 0; i--) { + removeTaskInternal(mPendingNewTaskTargets.get(i)); + } } // Note, the callback will handle its own synchronization, do not lock on WM lock @@ -310,6 +317,18 @@ public class RecentsAnimationController implements DeathRecipient { mWillFinishToHome = willFinishToHome; } } + + @Override + public boolean removeTask(int taskId) { + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mService.getWindowManagerLock()) { + return removeTaskInternal(taskId); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } }; /** @@ -405,11 +424,17 @@ public class RecentsAnimationController implements DeathRecipient { @VisibleForTesting AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) { + return addAnimation(task, isRecentTaskInvisible, null /* finishedCallback */); + } + + @VisibleForTesting + AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible, + OnAnimationFinishedCallback finishedCallback) { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName()); final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task, isRecentTaskInvisible); task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */, - ANIMATION_TYPE_RECENTS); + ANIMATION_TYPE_RECENTS, finishedCallback); task.commitPendingTransaction(); mPendingAnimations.add(taskAdapter); return taskAdapter; @@ -489,6 +514,49 @@ public class RecentsAnimationController implements DeathRecipient { } } + void addTaskToTargets(Task task, OnAnimationFinishedCallback finishedCallback) { + if (mRunner != null) { + final RemoteAnimationTarget target = createTaskRemoteAnimation(task, finishedCallback); + if (target == null) return; + + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addTaskToTargets, target: %s", target); + try { + mRunner.onTaskAppeared(target); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to report task appeared", e); + } + } + } + + private RemoteAnimationTarget createTaskRemoteAnimation(Task task, + OnAnimationFinishedCallback finishedCallback) { + final SparseBooleanArray recentTaskIds = + mService.mAtmService.getRecentTasks().getRecentTaskIds(); + TaskAnimationAdapter adapter = (TaskAnimationAdapter) addAnimation(task, + !recentTaskIds.get(task.mTaskId), finishedCallback); + mPendingNewTaskTargets.add(task.mTaskId); + return adapter.createRemoteAnimationTarget(); + } + + private boolean removeTaskInternal(int taskId) { + boolean result = false; + for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { + // Only allows when task target has became visible to user, to prevent + // the flickering during remove animation and task visible. + final TaskAnimationAdapter target = mPendingAnimations.get(i); + if (target.mTask.mTaskId == taskId && target.mTask.isOnTop()) { + removeAnimation(target); + final int taskIndex = mPendingNewTaskTargets.indexOf(taskId); + if (taskIndex != -1) { + mPendingNewTaskTargets.remove(taskIndex); + } + result = true; + break; + } + } + return result; + } + private RemoteAnimationTarget[] createAppAnimations() { final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>(); for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index e1ef76f128cd..e8f7ba550bd8 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -23,7 +23,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; @@ -38,6 +37,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE; +import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; @@ -66,6 +66,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT; import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER; import static com.android.server.wm.RootWindowContainerProto.PENDING_ACTIVITIES; @@ -178,7 +179,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> private Object mLastWindowFreezeSource = null; private Session mHoldScreen = null; - private float mScreenBrightness = -1; + private float mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT; private long mUserActivityTimeout = -1; private boolean mUpdateRotation = false; // Following variables are for debugging screen wakelock only. @@ -664,7 +665,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> void setSecureSurfaceState(int userId, boolean disabled) { forAllWindows((w) -> { - if (w.mHasSurface && userId == UserHandle.getUserId(w.mOwnerUid)) { + if (w.mHasSurface && userId == w.mShowUserId) { w.mWinAnimator.setSecureLocked(disabled); } }, true /* traverseTopToBottom */); @@ -826,7 +827,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } mHoldScreen = null; - mScreenBrightness = -1; + mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT; mUserActivityTimeout = -1; mObscureApplicationContentOnSecondaryDisplays = false; mSustainedPerformanceModeCurrent = false; @@ -936,12 +937,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mWmService.setHoldScreenLocked(mHoldScreen); if (!mWmService.mDisplayFrozen) { - final int brightness = mScreenBrightness < 0 || mScreenBrightness > 1.0f - ? -1 : toBrightnessOverride(mScreenBrightness); - + final float brightnessOverride = mScreenBrightnessOverride < PowerManager.BRIGHTNESS_MIN + || mScreenBrightnessOverride > PowerManager.BRIGHTNESS_MAX + ? PowerManager.BRIGHTNESS_INVALID_FLOAT : mScreenBrightnessOverride; + int brightnessFloatAsIntBits = Float.floatToIntBits(brightnessOverride); // Post these on a handler such that we don't call into power manager service while // holding the window manager lock to avoid lock contention with power manager lock. - mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightness, 0).sendToTarget(); + mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightnessFloatAsIntBits, + 0).sendToTarget(); mHandler.obtainMessage(SET_USER_ACTIVITY_TIMEOUT, mUserActivityTimeout).sendToTarget(); } @@ -1125,8 +1128,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> + "has FLAG_KEEP_SCREEN_ON!!! called by%s", w, Debug.getCallers(10)); } - if (!syswin && w.mAttrs.screenBrightness >= 0 && mScreenBrightness < 0) { - mScreenBrightness = w.mAttrs.screenBrightness; + if (!syswin && w.mAttrs.screenBrightness >= 0 + && Float.isNaN(mScreenBrightnessOverride)) { + mScreenBrightnessOverride = w.mAttrs.screenBrightness; } final int type = attrs.type; @@ -1190,10 +1194,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return doRequest; } - private static int toBrightnessOverride(float value) { - return (int)(value * PowerManager.BRIGHTNESS_ON); - } - private final class MyHandler extends Handler { public MyHandler(Looper looper) { @@ -1205,7 +1205,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> switch (msg.what) { case SET_SCREEN_BRIGHTNESS_OVERRIDE: mWmService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager( - msg.arg1); + Float.intBitsToFloat(msg.arg1)); break; case SET_USER_ACTIVITY_TIMEOUT: mWmService.mPowerManagerInternal. @@ -1370,8 +1370,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> calculateDefaultMinimalSizeOfResizeableTasks(); final TaskDisplayArea defaultTaskDisplayArea = getDefaultTaskDisplayArea(); - defaultTaskDisplayArea.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, - ON_TOP); + defaultTaskDisplayArea.getOrCreateRootHomeTask(); positionChildAt(POSITION_TOP, defaultTaskDisplayArea.mDisplayContent, false /* includingParents */); } @@ -1462,8 +1461,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> void startHomeOnEmptyDisplays(String reason) { for (int i = getChildCount() - 1; i >= 0; i--) { final DisplayContent display = getChildAt(i); - if (display.topRunningActivity() == null) { - startHomeOnDisplay(mCurrentUser, reason, display.mDisplayId); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + if (taskDisplayArea.topRunningActivity() == null) { + startHomeOnTaskDisplayArea(mCurrentUser, reason, taskDisplayArea, + false /* allowInstrumenting */, false /* fromHomeKey */); + } } } } @@ -1473,32 +1476,52 @@ class RootWindowContainer extends WindowContainer<DisplayContent> false /* fromHomeKey */); } + boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting, + boolean fromHomeKey) { + // Fallback to top focused display or default display if the displayId is invalid. + if (displayId == INVALID_DISPLAY) { + final ActivityStack stack = getTopDisplayFocusedStack(); + displayId = stack != null ? stack.getDisplayId() : DEFAULT_DISPLAY; + } + + final DisplayContent display = getDisplayContent(displayId); + boolean result = false; + for (int tcNdx = display.getTaskDisplayAreaCount() - 1; tcNdx >= 0; --tcNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tcNdx); + result |= startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea, + allowInstrumenting, fromHomeKey); + } + return result; + } + /** - * This starts home activity on displays that can have system decorations based on displayId - - * Default display always use primary home component. - * For Secondary displays, the home activity must have category SECONDARY_HOME and then resolves - * according to the priorities listed below. + * This starts home activity on display areas that can have system decorations based on + * displayId - default display area always uses primary home component. + * For secondary display areas, the home activity must have category SECONDARY_HOME and then + * resolves according to the priorities listed below. * - If default home is not set, always use the secondary home defined in the config. * - Use currently selected primary home activity. * - Use the activity in the same package as currently selected primary home activity. * If there are multiple activities matched, use first one. * - Use the secondary home defined in the config. */ - boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting, - boolean fromHomeKey) { - // Fallback to top focused display if the displayId is invalid. - if (displayId == INVALID_DISPLAY) { + boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea, + boolean allowInstrumenting, boolean fromHomeKey) { + // Fallback to top focused display area if the provided one is invalid. + if (taskDisplayArea == null) { final ActivityStack stack = getTopDisplayFocusedStack(); - displayId = stack != null ? stack.getDisplayId() : DEFAULT_DISPLAY; + taskDisplayArea = stack != null ? stack.getDisplayArea() + : getDefaultTaskDisplayArea(); } Intent homeIntent = null; ActivityInfo aInfo = null; - if (displayId == DEFAULT_DISPLAY) { + if (taskDisplayArea == getDefaultTaskDisplayArea()) { homeIntent = mService.getHomeIntent(); aInfo = resolveHomeActivity(userId, homeIntent); - } else if (shouldPlaceSecondaryHomeOnDisplay(displayId)) { - Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, displayId); + } else if (taskDisplayArea.getDisplayId() == DEFAULT_DISPLAY + || shouldPlaceSecondaryHomeOnDisplay(taskDisplayArea.getDisplayId())) { + Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea); aInfo = info.first; homeIntent = info.second; } @@ -1506,7 +1529,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return false; } - if (!canStartHomeOnDisplay(aInfo, displayId, allowInstrumenting)) { + if (!canStartHomeOnDisplay(aInfo, taskDisplayArea.getDisplayId(), allowInstrumenting)) { return false; } @@ -1516,13 +1539,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Updates the extra information of the intent. if (fromHomeKey) { homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true); + mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "startHomeActivity"); } // Update the reason for ANR debugging to verify if the user activity is the one that // actually launched. final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId( - aInfo.applicationInfo.uid) + ":" + displayId; + aInfo.applicationInfo.uid) + ":" + taskDisplayArea.getDisplayId(); mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason, - displayId); + taskDisplayArea); return true; } @@ -1563,10 +1587,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } @VisibleForTesting - Pair<ActivityInfo, Intent> resolveSecondaryHomeActivity(int userId, int displayId) { - if (displayId == DEFAULT_DISPLAY) { + Pair<ActivityInfo, Intent> resolveSecondaryHomeActivity(int userId, + @NonNull TaskDisplayArea taskDisplayArea) { + if (taskDisplayArea == getDefaultTaskDisplayArea()) { throw new IllegalArgumentException( - "resolveSecondaryHomeActivity: Should not be DEFAULT_DISPLAY"); + "resolveSecondaryHomeActivity: Should not be default task container"); } // Resolve activities in the same package as currently selected primary home activity. Intent homeIntent = mService.getHomeIntent(); @@ -1600,7 +1625,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } if (aInfo != null) { - if (!canStartHomeOnDisplay(aInfo, displayId, false /* allowInstrumenting */)) { + if (!canStartHomeOnDisplay(aInfo, taskDisplayArea.getDisplayId(), + false /* allowInstrumenting */)) { aInfo = null; } } @@ -1633,19 +1659,18 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return resolutions; } - boolean resumeHomeActivity(ActivityRecord prev, String reason, int displayId) { + boolean resumeHomeActivity(ActivityRecord prev, String reason, + TaskDisplayArea taskDisplayArea) { if (!mService.isBooting() && !mService.isBooted()) { // Not ready yet! return false; } - if (displayId == INVALID_DISPLAY) { - displayId = DEFAULT_DISPLAY; + if (taskDisplayArea == null) { + taskDisplayArea = getDefaultTaskDisplayArea(); } - // TODO(multi-display-area): Resume home on the right task container - final ActivityRecord r = getDisplayContent(displayId).getDefaultTaskDisplayArea() - .getHomeActivity(); + final ActivityRecord r = taskDisplayArea.getHomeActivity(); final String myReason = reason + " resumeHomeActivity"; // Only resume home activity if isn't finishing. @@ -1653,7 +1678,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> r.moveFocusableActivityToTop(myReason); return resumeFocusedStacksTopActivities(r.getRootTask(), prev, null); } - return startHomeOnDisplay(mCurrentUser, myReason, displayId); + return startHomeOnTaskDisplayArea(mCurrentUser, myReason, taskDisplayArea, + false /* allowInstrumenting */, false /* fromHomeKey */); } /** @@ -2023,7 +2049,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> stack.moveToFront("switchUserOnHomeDisplay"); } else { // Stack was moved to another display while user was swapped out. - resumeHomeActivity(null, "switchUserOnOtherDisplay", DEFAULT_DISPLAY); + resumeHomeActivity(null, "switchUserOnOtherDisplay", getDefaultTaskDisplayArea()); } return homeInFront; } @@ -2047,43 +2073,58 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } /** - * Move stack with all its existing content to specified display. + * Move stack with all its existing content to specified task display area. * @param stackId Id of stack to move. - * @param displayId Id of display to move stack to. + * @param taskDisplayArea The task display area to move stack to. * @param onTop Indicates whether container should be place on top or on bottom. */ - void moveStackToDisplay(int stackId, int displayId, boolean onTop) { - final DisplayContent displayContent = getDisplayContentOrCreate(displayId); - if (displayContent == null) { - throw new IllegalArgumentException("moveStackToDisplay: Unknown displayId=" - + displayId); - } + void moveStackToTaskDisplayArea(int stackId, TaskDisplayArea taskDisplayArea, boolean onTop) { final ActivityStack stack = getStack(stackId); if (stack == null) { - throw new IllegalArgumentException("moveStackToDisplay: Unknown stackId=" + throw new IllegalArgumentException("moveStackToTaskDisplayArea: Unknown stackId=" + stackId); } - final DisplayContent currentDisplay = stack.getDisplay(); - if (currentDisplay == null) { - throw new IllegalStateException("moveStackToDisplay: Stack with stack=" + stack - + " is not attached to any display."); + final TaskDisplayArea currentTaskDisplayArea = stack.getDisplayArea(); + if (currentTaskDisplayArea == null) { + throw new IllegalStateException("moveStackToTaskDisplayArea: stack=" + stack + + " is not attached to any task display area."); + } + + if (taskDisplayArea == null) { + throw new IllegalArgumentException( + "moveStackToTaskDisplayArea: Unknown taskDisplayArea=" + taskDisplayArea); } - if (currentDisplay.mDisplayId == displayId) { + if (currentTaskDisplayArea == taskDisplayArea) { throw new IllegalArgumentException("Trying to move stack=" + stack - + " to its current displayId=" + displayId); + + " to its current taskDisplayArea=" + taskDisplayArea); + } + stack.reparent(taskDisplayArea, onTop); + // TODO(multi-display): resize stacks properly if moved from split-screen. + } + + /** + * Move stack with all its existing content to specified display. + * @param stackId Id of stack to move. + * @param displayId Id of display to move stack to. + * @param onTop Indicates whether container should be place on top or on bottom. + */ + void moveStackToDisplay(int stackId, int displayId, boolean onTop) { + final DisplayContent displayContent = getDisplayContentOrCreate(displayId); + if (displayContent == null) { + throw new IllegalArgumentException("moveStackToDisplay: Unknown displayId=" + + displayId); } if (displayContent.isSingleTaskInstance() && displayContent.getStackCount() > 0) { // We don't allow moving stacks to single instance display that already has a child. - Slog.e(TAG, "Can not move stack=" + stack + Slog.e(TAG, "Can not move stackId=" + stackId + " to single task instance display=" + displayContent); return; } - stack.reparent(displayContent.getDefaultTaskDisplayArea(), onTop); - // TODO(multi-display): resize stacks properly if moved from split-screen. + moveStackToTaskDisplayArea(stackId, displayContent.getDefaultTaskDisplayArea(), onTop); } boolean moveTopStackActivityToPinnedStack(int stackId) { @@ -2106,43 +2147,46 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return false; } - moveActivityToPinnedStack(r, null /* sourceBounds */, 0f /* aspectRatio */, - "moveTopActivityToPinnedStack"); + moveActivityToPinnedStack(r, "moveTopActivityToPinnedStack"); return true; } - void moveActivityToPinnedStack(ActivityRecord r, Rect sourceHintBounds, float aspectRatio, - String reason) { + void moveActivityToPinnedStack(ActivityRecord r, String reason) { mService.deferWindowLayout(); final TaskDisplayArea taskDisplayArea = r.getDisplayArea(); try { final Task task = r.getTask(); - final ActivityStack pinnedStack = taskDisplayArea.getRootPinnedTask(); + // This will change the pinned stack's windowing mode to its original mode, ensuring // we only have one stack that is in pinned mode. if (pinnedStack != null) { pinnedStack.dismissPip(); } - final boolean singleActivity = task.getChildCount() == 1; + // Set a transition to ensure that we don't immediately try and update the visibility + // of the activity entering PIP + r.getDisplayContent().prepareAppTransition(TRANSIT_NONE, false); + final boolean singleActivity = task.getChildCount() == 1; final ActivityStack stack; if (singleActivity) { stack = r.getRootTask(); - stack.setWindowingMode(WINDOWING_MODE_PINNED); } else { // In the case of multiple activities, we will create a new task for it and then // move the PIP activity into the task. - stack = taskDisplayArea.createStack(WINDOWING_MODE_PINNED, r.getActivityType(), + stack = taskDisplayArea.createStack(WINDOWING_MODE_UNDEFINED, r.getActivityType(), ON_TOP, r.info, r.intent, false /* createdByOrganizer */); // There are multiple activities in the task and moving the top activity should // reveal/leave the other activities in their original task. - r.reparent(stack, MAX_VALUE, "moveActivityToStack"); + // On the other hand, ActivityRecord#onParentChanged takes care of setting the + // up-to-dated pinned stack information on this newly created stack. + r.reparent(stack, MAX_VALUE, reason); } + stack.setWindowingMode(WINDOWING_MODE_PINNED); // Reset the state that indicates it can enter PiP while pausing after we've moved it // to the pinned stack @@ -2151,11 +2195,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mService.continueWindowLayout(); } - // TODO: revisit the following statement after the animation is moved from WM to SysUI. - // Update the visibility of all activities after the they have been reparented to the new - // stack. This MUST run after the animation above is scheduled to ensure that the windows - // drawn signal is scheduled after the bounds animation start call on the bounds animator - // thread. ensureActivitiesVisible(null, 0, false /* preserveWindows */); resumeFocusedStacksTopActivities(); @@ -2216,7 +2255,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // It is possible that request to finish activity might also remove its task and // stack, so we need to be careful with indexes in the loop and check child count // every time. - for (int stackNdx = 0; stackNdx < display.getStackCount(); ++stackNdx) { + for (int stackNdx = 0; stackNdx < taskDisplayArea.getStackCount(); ++stackNdx) { final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx); final Task t = stack.finishTopCrashedActivityLocked(app, reason); if (stack == focusedStack || finishedTask == null) { @@ -2283,7 +2322,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions); } else if (targetStack == null) { result |= resumeHomeActivity(null /* prev */, "no-focusable-task", - display.mDisplayId); + display.getDefaultTaskDisplayArea()); } } } diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index b92ead1a0531..5f33ea170923 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -41,7 +41,6 @@ import android.graphics.Rect; import android.os.Trace; import android.util.Slog; import android.util.proto.ProtoOutputStream; -import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; import android.view.Surface.OutOfResourcesException; @@ -117,8 +116,9 @@ class ScreenRotationAnimation { private BlackFrame mEnteringBlackFrame; private int mWidth, mHeight; - private int mOriginalRotation; - private int mOriginalWidth, mOriginalHeight; + private final int mOriginalRotation; + private final int mOriginalWidth; + private final int mOriginalHeight; private int mCurRotation; private Rect mOriginalDisplayRect = new Rect(); @@ -140,20 +140,18 @@ class ScreenRotationAnimation { /** Intensity of light/whiteness of the layout after rotation occurs. */ private float mEndLuma; - public ScreenRotationAnimation(Context context, DisplayContent displayContent, - boolean fixedToUserRotation, boolean isSecure, WindowManagerService service) { - mService = service; - mContext = context; + ScreenRotationAnimation(DisplayContent displayContent, @Surface.Rotation int originalRotation) { + mService = displayContent.mWmService; + mContext = mService.mContext; mDisplayContent = displayContent; displayContent.getBounds(mOriginalDisplayRect); // Screenshot does NOT include rotation! - final Display display = displayContent.getDisplay(); - int originalRotation = display.getRotation(); + final DisplayInfo displayInfo = displayContent.getDisplayInfo(); + final int realOriginalRotation = displayInfo.rotation; final int originalWidth; final int originalHeight; - DisplayInfo displayInfo = displayContent.getDisplayInfo(); - if (fixedToUserRotation) { + if (displayContent.getDisplayRotation().isFixedToUserRotation()) { // Emulated orientation. mForceDefaultOrientation = true; originalWidth = displayContent.mBaseDisplayWidth; @@ -163,8 +161,8 @@ class ScreenRotationAnimation { originalWidth = displayInfo.logicalWidth; originalHeight = displayInfo.logicalHeight; } - if (originalRotation == Surface.ROTATION_90 - || originalRotation == Surface.ROTATION_270) { + if (realOriginalRotation == Surface.ROTATION_90 + || realOriginalRotation == Surface.ROTATION_270) { mWidth = originalHeight; mHeight = originalWidth; } else { @@ -173,10 +171,18 @@ class ScreenRotationAnimation { } mOriginalRotation = originalRotation; - mOriginalWidth = originalWidth; - mOriginalHeight = originalHeight; + // If the delta is not zero, the rotation of display may not change, but we still want to + // apply rotation animation because there should be a top app shown as rotated. So the + // specified original rotation customizes the direction of animation to have better look + // when restoring the rotated app to the same rotation as current display. + final int delta = DisplayContent.deltaRotation(originalRotation, realOriginalRotation); + final boolean flipped = delta == Surface.ROTATION_90 || delta == Surface.ROTATION_270; + mOriginalWidth = flipped ? originalHeight : originalWidth; + mOriginalHeight = flipped ? originalWidth : originalHeight; mSurfaceRotationAnimationController = new SurfaceRotationAnimationController(); + // Check whether the current screen contains any secure content. + final boolean isSecure = displayContent.hasSecureWindowOnScreen(); final SurfaceControl.Transaction t = mService.mTransactionFactory.get(); try { mBackColorSurface = displayContent.makeChildSurface(null) @@ -202,7 +208,7 @@ class ScreenRotationAnimation { t2.apply(true /* sync */); // Capture a screenshot into the surface we just created. - final int displayId = display.getDisplayId(); + final int displayId = displayContent.getDisplayId(); final Surface surface = mService.mSurfaceFactory.get(); surface.copyFrom(mScreenshotLayer); SurfaceControl.ScreenshotGraphicBuffer gb = @@ -242,7 +248,7 @@ class ScreenRotationAnimation { ProtoLog.i(WM_SHOW_SURFACE_ALLOC, " FREEZE %s: CREATE", mScreenshotLayer); - setRotation(t, originalRotation); + setRotation(t, realOriginalRotation); t.apply(); } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 5f3732a58824..56147f216e73 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -51,6 +51,7 @@ import android.view.IWindowId; import android.view.IWindowSession; import android.view.IWindowSessionCallback; import android.view.InputChannel; +import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.SurfaceControl; import android.view.SurfaceSession; @@ -158,10 +159,22 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, - InsetsState outInsetsState) { + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { + return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, + outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, + outInsetsState, outActiveControls, UserHandle.getUserId(mUid)); + } + + + @Override + public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs, + int viewVisibility, int displayId, int userId, Rect outFrame, + Rect outContentInsets, Rect outStableInsets, + DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, - outInsetsState); + outInsetsState, outActiveControls, userId); } @Override @@ -171,7 +184,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, new Rect() /* outFrame */, outContentInsets, outStableInsets, new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */, - outInsetsState); + outInsetsState, null, UserHandle.getUserId(mUid)); } @Override @@ -191,7 +204,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { Rect outStableInsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl, InsetsState outInsetsState, - Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) { + InsetsSourceControl[] outActiveControls, Point outSurfaceSize, + SurfaceControl outBLASTSurfaceControl) { if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from " + Binder.getCallingPid()); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag); @@ -199,8 +213,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { requestedWidth, requestedHeight, viewFlags, flags, frameNumber, outFrame, outContentInsets, outVisibleInsets, outStableInsets, outBackdropFrame, cutout, - mergedConfiguration, outSurfaceControl, outInsetsState, outSurfaceSize, - outBLASTSurfaceControl); + mergedConfiguration, outSurfaceControl, outInsetsState, outActiveControls, + outSurfaceSize, outBLASTSurfaceControl); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to " + Binder.getCallingPid()); diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java index 9732637fdd4d..701feff8c6be 100644 --- a/services/core/java/com/android/server/wm/ShellRoot.java +++ b/services/core/java/com/android/server/wm/ShellRoot.java @@ -16,12 +16,20 @@ package com.android.server.wm; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; + +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; +import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION; + import android.annotation.NonNull; +import android.graphics.Point; import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; +import android.view.DisplayInfo; import android.view.IWindow; import android.view.SurfaceControl; +import android.view.animation.Animation; /** * Represents a piece of the hierarchy under which a client Shell can manage sub-windows. @@ -70,5 +78,29 @@ public class ShellRoot { IWindow getClient() { return mClient; } + + void startAnimation(Animation anim) { + // Only do this for the divider + if (mToken.windowType != TYPE_DOCK_DIVIDER) { + return; + } + + DisplayInfo displayInfo = mToken.getFixedRotationTransformDisplayInfo(); + if (displayInfo == null) { + displayInfo = mDisplayContent.getDisplayInfo(); + } + + // Mostly copied from WindowState to enable keyguard transition animation + anim.initialize(displayInfo.logicalWidth, displayInfo.logicalHeight, + displayInfo.appWidth, displayInfo.appHeight); + anim.restrictDuration(MAX_ANIMATION_DURATION); + anim.scaleCurrentDuration(mDisplayContent.mWmService.getWindowAnimationScaleLocked()); + final AnimationAdapter adapter = new LocalAnimationAdapter( + new WindowAnimationSpec(anim, new Point(0, 0), false /* canSkipFirstFrame */, + 0 /* windowCornerRadius */), + mDisplayContent.mWmService.mSurfaceAnimationRunner); + mToken.startAnimation(mToken.getPendingTransaction(), adapter, false /* hidden */, + ANIMATION_TYPE_WINDOW_ANIMATION, null /* animationFinishedCallback */); + } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index cb897db9a2d0..ad1a205a4910 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -58,7 +58,6 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; -import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.SurfaceControl.METADATA_TASK_ID; import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE; @@ -86,6 +85,8 @@ import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; +import static com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowContainerChildProto.TASK; @@ -135,6 +136,7 @@ import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.Surface; import android.view.SurfaceControl; +import android.view.WindowManager; import android.window.ITaskOrganizer; import com.android.internal.annotations.VisibleForTesting; @@ -210,7 +212,6 @@ class Task extends WindowContainer<WindowContainer> { static final int INVALID_MIN_SIZE = -1; private float mShadowRadius = 0; private final Rect mLastSurfaceCrop = new Rect(); - private static final boolean ENABLE_FREEFORM_COMPOSITOR_SHADOWS = false; /** * The modes to control how the stack is moved to the front when calling {@link Task#reparent}. @@ -897,7 +898,7 @@ class Task extends WindowContainer<WindowContainer> { // TODO: Handle incorrect request to move before the actual move, not after. supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(), - DEFAULT_DISPLAY, toStack); + mRootWindowContainer.getDefaultTaskDisplayArea(), toStack); return (preferredStack == toStack); } @@ -1767,6 +1768,10 @@ class Task extends WindowContainer<WindowContainer> { t.updateTaskDescription(); } } + + if (isOrganized()) { + mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, true /* force */); + } } private static boolean setTaskDescriptionFromActivityAboveRoot( @@ -1962,7 +1967,7 @@ class Task extends WindowContainer<WindowContainer> { final boolean taskOrgChanged = updateTaskOrganizerState(false /* forceUpdate */); // If the task organizer has changed, then it will already be receiving taskAppeared with // the latest task-info thus the task-info won't have changed. - if (!taskOrgChanged && mTaskOrganizer != null) { + if (!taskOrgChanged && isOrganized()) { mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */); } } @@ -2334,32 +2339,30 @@ class Task extends WindowContainer<WindowContainer> { return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize); } - private void resolveOrganizedOverrideConfiguration(Configuration newParentConfig) { + @Override + void resolveOverrideConfiguration(Configuration newParentConfig) { + mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds()); super.resolveOverrideConfiguration(newParentConfig); - if (!isOrganized()) { - return; - } - final Task root = getRootTask(); - if (root == this) { - return; + // Resolve override windowing mode to fullscreen for home task (even on freeform + // display), or split-screen-secondary if in split-screen mode. + int windowingMode = + getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); + if (getActivityType() == ACTIVITY_TYPE_HOME && windowingMode == WINDOWING_MODE_UNDEFINED) { + windowingMode = inSplitScreenWindowingMode() ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY + : WINDOWING_MODE_FULLSCREEN; + getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode); } - // Ensure to have the same windowing mode for the child tasks that controlled by task org. - getResolvedOverrideConfiguration().windowConfiguration - .setWindowingMode(root.getWindowingMode()); - } - - @Override - void resolveOverrideConfiguration(Configuration newParentConfig) { - if (!isLeafTask() || mCreatedByOrganizer) { - resolveOrganizedOverrideConfiguration(newParentConfig); + if (!isLeafTask()) { + // Compute configuration overrides for tasks that created by organizer, so that + // organizer can get the correct configuration from those tasks. + if (mCreatedByOrganizer) { + computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig); + } return; } - mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds()); - resolveOrganizedOverrideConfiguration(newParentConfig); - int windowingMode = - getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); + if (windowingMode == WINDOWING_MODE_UNDEFINED) { windowingMode = newParentConfig.windowConfiguration.getWindowingMode(); } @@ -2725,10 +2728,8 @@ class Task extends WindowContainer<WindowContainer> { } private void updateSurfaceCrop() { - // TODO(b/149585281) remove when root task has the correct bounds for freeform // Only update the crop if we are drawing shadows on the task. - if (mSurfaceControl == null || !mWmService.mRenderShadowsInCompositor - || !isRootTask() || !ENABLE_FREEFORM_COMPOSITOR_SHADOWS) { + if (mSurfaceControl == null || !mWmService.mRenderShadowsInCompositor || !isRootTask()) { return; } @@ -3068,6 +3069,7 @@ class Task extends WindowContainer<WindowContainer> { mForceShowForAllUsers = forceShowForAllUsers; } + @Override public boolean isAttached() { final TaskDisplayArea taskDisplayArea = getDisplayArea(); return taskDisplayArea != null && !taskDisplayArea.isRemoved(); @@ -3348,6 +3350,21 @@ class Task extends WindowContainer<WindowContainer> { @Override Dimmer getDimmer() { + // If the window is in multi-window mode, we want to dim at the Task level to ensure the dim + // bounds match the area the app lives in + if (inMultiWindowMode()) { + return mDimmer; + } + + // If we're not at the root task level, we want to keep traversing through the parents to + // find the root. + // Once at the root task level, we want to check {@link #isTranslucent(ActivityRecord)}. + // If true, we want to get the Dimmer from the level above since we don't want to animate + // the dim with the Task. + if (!isRootTask() || isTranslucent(null)) { + return super.getDimmer(); + } + return mDimmer; } @@ -3389,6 +3406,24 @@ class Task extends WindowContainer<WindowContainer> { } @Override + protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter, + int transit, boolean isVoiceInteraction, + @Nullable OnAnimationFinishedCallback finishedCallback) { + final RecentsAnimationController control = mWmService.getRecentsAnimationController(); + if (control != null && enter + && getDisplayContent().mAppTransition.isNextAppTransitionCustomFromRecents()) { + ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, + "addTaskToRecentsAnimationIfNeeded, control: %s, task: %s, transit: %s", + control, asTask(), AppTransition.appTransitionToString(transit)); + // We let the transition to be controlled by RecentsAnimation, and callback task's + // RemoteAnimationTarget for remote runner to animate. + control.addTaskToTargets(getRootTask(), finishedCallback); + } else { + super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback); + } + } + + @Override void dump(PrintWriter pw, String prefix, boolean dumpAll) { super.dump(pw, prefix, dumpAll); final String doublePrefix = prefix + " "; @@ -4085,8 +4120,18 @@ class Task extends WindowContainer<WindowContainer> { } void setHasBeenVisible(boolean hasBeenVisible) { + final boolean prevHasBeenVisible = mHasBeenVisible; mHasBeenVisible = hasBeenVisible; if (hasBeenVisible) { + // If the task is not yet visible when it is added to the task organizer, then we should + // hide it to allow the task organizer to show it when it is properly reparented. We + // skip this for tasks created by the organizer because they can synchronously update + // the leash before new children are added to the task. + if (!mCreatedByOrganizer && mTaskOrganizer != null && !prevHasBeenVisible) { + getPendingTransaction().hide(getSurfaceControl()); + commitPendingTransaction(); + } + sendTaskAppeared(); if (!isRootTask()) { getRootTask().setHasBeenVisible(true); @@ -4106,20 +4151,18 @@ class Task extends WindowContainer<WindowContainer> { * Any time any of these conditions are updated, the updating code should call * sendTaskAppeared. */ - private boolean taskAppearedReady() { + boolean taskAppearedReady() { return mSurfaceControl != null && mTaskOrganizer != null && getHasBeenVisible(); } private void sendTaskAppeared() { - if (taskAppearedReady() && !mTaskAppearedSent) { - mTaskAppearedSent = true; + if (mTaskOrganizer != null) { mAtmService.mTaskOrganizerController.onTaskAppeared(mTaskOrganizer, this); } } private void sendTaskVanished() { - if (mTaskOrganizer != null && mTaskAppearedSent) { - mTaskAppearedSent = false; + if (mTaskOrganizer != null) { mAtmService.mTaskOrganizerController.onTaskVanished(mTaskOrganizer, this); } } @@ -4227,8 +4270,7 @@ class Task extends WindowContainer<WindowContainer> { // Get elevation for a specific windowing mode. if (inPinnedWindowingMode()) { elevation = PINNED_WINDOWING_MODE_ELEVATION_IN_DIP; - } else if (ENABLE_FREEFORM_COMPOSITOR_SHADOWS && inFreeformWindowingMode()) { - // TODO(b/149585281) remove when root task has the correct bounds for freeform + } else if (inFreeformWindowingMode()) { elevation = taskIsFocused ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; } else { @@ -4268,8 +4310,9 @@ class Task extends WindowContainer<WindowContainer> { void setPictureInPictureParams(PictureInPictureParams p) { mPictureInPictureParams.copyOnlySet(p); - mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged( - this, true /* force */); + if (isOrganized()) { + mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, true /* force */); + } } /** diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 1bc7244996ab..d71e56106e18 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -31,7 +31,6 @@ import static android.app.WindowConfiguration.isSplitScreenWindowingMode; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.window.DisplayAreaOrganizer.FEATURE_TASK_CONTAINER; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; @@ -71,7 +70,9 @@ import java.util.List; * {@link DisplayArea} that represents a section of a screen that contains app window containers. */ final class TaskDisplayArea extends DisplayArea<ActivityStack> { + DisplayContent mDisplayContent; + /** * A control placed at the appropriate level for transitions to occur. */ @@ -141,8 +142,9 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { */ private boolean mRemoved; - TaskDisplayArea(DisplayContent displayContent, WindowManagerService service) { - super(service, Type.ANY, "TaskContainers", FEATURE_TASK_CONTAINER); + TaskDisplayArea(DisplayContent displayContent, WindowManagerService service, String name, + int displayAreaFeature) { + super(service, Type.ANY, name, displayAreaFeature); mDisplayContent = displayContent; mRootWindowContainer = service.mRoot; mAtmService = service.mAtmService; @@ -877,6 +879,11 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { + windowingMode); } + if (windowingMode == WINDOWING_MODE_PINNED && getRootPinnedTask() != null) { + // Only 1 stack can be PINNED at a time, so dismiss the existing one + getRootPinnedTask().dismissPip(); + } + final int stackId = getNextStackId(); return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent, createdByOrganizer); @@ -936,9 +943,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } } else { addStack(stack, onTop ? POSITION_TOP : POSITION_BOTTOM); - stack.setWindowingMode(windowingMode, false /* animate */, false /* showRecents */, - false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */, - true /* creating */); + stack.setWindowingMode(windowingMode, true /* creating */); } return stack; } @@ -1070,7 +1075,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { /** * Find task for putting the Activity in. */ - void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay, + void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplayArea, RootWindowContainer.FindTaskResult result) { mTmpFindTaskResult.clear(); for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { @@ -1092,7 +1097,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { if (mTmpFindTaskResult.mIdealMatch) { result.setTo(mTmpFindTaskResult); return; - } else if (isPreferredDisplay) { + } else if (isPreferredDisplayArea) { // Note: since the traversing through the stacks is top down, the floating // tasks should always have lower priority than any affinity-matching tasks // in the fullscreen stacks @@ -1148,7 +1153,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { for (int i = getStackCount() - 1; i >= 0; --i) { final ActivityStack stack = getStackAt(i); // Collect the root tasks that are currently being organized. - if (stack.isOrganized()) { + if (stack.mCreatedByOrganizer) { for (int k = stack.getChildCount() - 1; k >= 0; --k) { final ActivityStack childStack = (ActivityStack) stack.getChildAt(k); if (childStack.getActivityType() == activityType) { @@ -1167,17 +1172,23 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } void onSplitScreenModeDismissed() { + onSplitScreenModeDismissed(null /* toTop */); + } + + void onSplitScreenModeDismissed(ActivityStack toTop) { mAtmService.deferWindowLayout(); try { mLaunchRootTask = null; moveSplitScreenTasksToFullScreen(); } finally { - final ActivityStack topFullscreenStack = - getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); + final ActivityStack topFullscreenStack = toTop != null + ? toTop : getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); final ActivityStack homeStack = getOrCreateRootHomeTask(); - if (topFullscreenStack != null && homeStack != null && !isTopStack(homeStack)) { + if (homeStack != null && ((topFullscreenStack != null && !isTopStack(homeStack)) + || toTop != null)) { // Whenever split-screen is dismissed we want the home stack directly behind the // current top fullscreen stack so it shows up when the top stack is finished. + // Or, if the caller specified a stack to be on top after split-screen is dismissed. // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch // once we have that. @@ -1417,8 +1428,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { ActivityStack homeTask = getRootHomeTask(); if (homeTask == null && mDisplayContent.supportsSystemDecorations() && !mDisplayContent.isUntrustedVirtualDisplay()) { - homeTask = createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, - false /* onTop */); + homeTask = createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, false /* onTop */); } return homeTask; } @@ -1614,6 +1624,11 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } } + @Override + boolean canCreateRemoteAnimationTarget() { + return true; + } + /** * Callback for when the order of the stacks in the display changes. */ diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 2bbf8dbb274c..adc50bf70446 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -25,7 +25,9 @@ import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFI import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; +import android.app.ActivityManager.TaskDescription; import android.app.WindowConfiguration; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -38,6 +40,7 @@ import android.window.ITaskOrganizer; import android.window.ITaskOrganizerController; import android.window.WindowContainerToken; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.io.PrintWriter; @@ -46,6 +49,7 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.WeakHashMap; +import java.util.function.Consumer; /** * Stores the TaskOrganizers associated with a given windowing mode and @@ -81,17 +85,105 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } } } - }; + } + + /** + * A wrapper class around ITaskOrganizer to ensure that the calls are made in the right + * lifecycle order since we may be updating the visibility of task surface controls in a pending + * transaction before they are presented to the task org. + */ + private class TaskOrganizerCallbacks { + final WindowManagerService mService; + final ITaskOrganizer mTaskOrganizer; + final Consumer<Runnable> mDeferTaskOrgCallbacksConsumer; + + TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg, + Consumer<Runnable> deferTaskOrgCallbacksConsumer) { + mService = wm; + mDeferTaskOrgCallbacksConsumer = deferTaskOrgCallbacksConsumer; + mTaskOrganizer = taskOrg; + } + + IBinder getBinder() { + return mTaskOrganizer.asBinder(); + } + + void onTaskAppeared(Task task) { + final RunningTaskInfo taskInfo = task.getTaskInfo(); + mDeferTaskOrgCallbacksConsumer.accept(() -> { + try { + mTaskOrganizer.onTaskAppeared(taskInfo); + } catch (RemoteException e) { + Slog.e(TAG, "Exception sending onTaskAppeared callback", e); + } + }); + } + + + void onTaskVanished(Task task) { + final RunningTaskInfo taskInfo = task.getTaskInfo(); + mDeferTaskOrgCallbacksConsumer.accept(() -> { + try { + mTaskOrganizer.onTaskVanished(taskInfo); + } catch (RemoteException e) { + Slog.e(TAG, "Exception sending onTaskVanished callback", e); + } + }); + } + + void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) { + if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) { + // Skip if the task has not yet received taskAppeared(), except for tasks created + // by the organizer that don't receive that signal + return; + } + mDeferTaskOrgCallbacksConsumer.accept(() -> { + if (!task.isOrganized()) { + // This is safe to ignore if the task is no longer organized + return; + } + try { + mTaskOrganizer.onTaskInfoChanged(taskInfo); + } catch (RemoteException e) { + Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e); + } + }); + } + + void onBackPressedOnTaskRoot(Task task) { + if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) { + // Skip if the task has not yet received taskAppeared(), except for tasks created + // by the organizer that don't receive that signal + return; + } + mDeferTaskOrgCallbacksConsumer.accept(() -> { + if (!task.isOrganized()) { + // This is safe to ignore if the task is no longer organized + return; + } + try { + mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo()); + } catch (Exception e) { + Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e); + } + }); + } + } private class TaskOrganizerState { - private final ITaskOrganizer mOrganizer; + private final TaskOrganizerCallbacks mOrganizer; private final DeathRecipient mDeathRecipient; private final ArrayList<Task> mOrganizedTasks = new ArrayList<>(); private final int mUid; private boolean mInterceptBackPressedOnTaskRoot; TaskOrganizerState(ITaskOrganizer organizer, int uid) { - mOrganizer = organizer; + final Consumer<Runnable> deferTaskOrgCallbacksConsumer = + mDeferTaskOrgCallbacksConsumer != null + ? mDeferTaskOrgCallbacksConsumer + : mService.mWindowManager.mAnimator::addAfterPrepareSurfacesRunnable; + mOrganizer = new TaskOrganizerCallbacks(mService.mWindowManager, organizer, + deferTaskOrgCallbacksConsumer); mDeathRecipient = new DeathRecipient(organizer); try { organizer.asBinder().linkToDeath(mDeathRecipient, 0); @@ -106,19 +198,21 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } void addTask(Task t) { - mOrganizedTasks.add(t); - try { - mOrganizer.onTaskAppeared(t.getTaskInfo()); - } catch (Exception e) { - Slog.e(TAG, "Exception sending taskAppeared callback" + e); + if (t.mTaskAppearedSent) return; + + if (!mOrganizedTasks.contains(t)) { + mOrganizedTasks.add(t); + } + if (t.taskAppearedReady()) { + t.mTaskAppearedSent = true; + mOrganizer.onTaskAppeared(t); } } void removeTask(Task t) { - try { - mOrganizer.onTaskVanished(t.getTaskInfo()); - } catch (Exception e) { - Slog.e(TAG, "Exception sending taskVanished callback" + e); + if (t.mTaskAppearedSent) { + t.mTaskAppearedSent = false; + mOrganizer.onTaskVanished(t); } mOrganizedTasks.remove(t); } @@ -126,7 +220,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { void dispose() { releaseTasks(); for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) { - mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.asBinder()); + mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.getBinder()); } } @@ -139,7 +233,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } void unlinkDeath() { - mOrganizer.asBinder().unlinkToDeath(mDeathRecipient, 0); + mOrganizer.getBinder().unlinkToDeath(mDeathRecipient, 0); } } @@ -149,9 +243,10 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>(); private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>(); - final ActivityTaskManagerService mService; + private final ActivityTaskManagerService mService; - RunningTaskInfo mTmpTaskInfo; + private RunningTaskInfo mTmpTaskInfo; + private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer; TaskOrganizerController(ActivityTaskManagerService atm) { mService = atm; @@ -163,6 +258,15 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } /** + * Specifies the consumer to run to defer the task org callbacks. Can be overridden while + * testing to allow the callbacks to be sent synchronously. + */ + @VisibleForTesting + public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) { + mDeferTaskOrgCallbacksConsumer = consumer; + } + + /** * Register a TaskOrganizer to manage tasks as they enter the given windowing mode. * If there was already a TaskOrganizer for this windowing mode it will be evicted * but will continue to organize it's existing tasks. @@ -253,7 +357,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { if (state == null) { return null; } - return state.mOrganizer; + return state.mOrganizer.mTaskOrganizer; } void onTaskAppeared(ITaskOrganizer organizer, Task task) { @@ -336,7 +440,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { boolean changed = lastInfo == null || mTmpTaskInfo.topActivityType != lastInfo.topActivityType || mTmpTaskInfo.isResizable() != lastInfo.isResizable() - || mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams; + || mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams + || !TaskDescription.equals(mTmpTaskInfo.taskDescription, lastInfo.taskDescription); if (!changed) { int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration); final int winCfgChanges = (cfgChanges & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0 @@ -358,10 +463,15 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { // change. mTmpTaskInfo = null; - if (task.mTaskOrganizer != null) { - try { - task.mTaskOrganizer.onTaskInfoChanged(newInfo); - } catch (RemoteException e) { + if (task.isOrganized()) { + // Because we defer sending taskAppeared() until the app has drawn, we may receive a + // configuration change before the state actually has the task registered. As such we + // should ignore these change events to the organizer until taskAppeared(). If the task + // was created by the organizer, then we always send the info change. + final TaskOrganizerState state = mTaskOrganizerStates.get( + task.mTaskOrganizer.asBinder()); + if (state != null) { + state.mOrganizer.onTaskInfoChanged(task, newInfo); } } } @@ -521,11 +631,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { return false; } - try { - state.mOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo()); - } catch (Exception e) { - Slog.e(TAG, "Exception sending interceptBackPressedOnTaskRoot callback" + e); - } + state.mOrganizer.onBackPressedOnTaskRoot(task); return true; } @@ -542,7 +648,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { final TaskOrganizerState state = mTaskOrganizerStates.get(taskOrgs.get(j)); final ArrayList<Task> tasks = state.mOrganizedTasks; pw.print(innerPrefix + " "); - pw.println(state.mOrganizer + " uid=" + state.mUid + ":"); + pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":"); for (int k = 0; k < tasks.size(); k++) { pw.println(innerPrefix + " " + tasks.get(k)); } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index eb005e0f7eda..14e5c6cbf28d 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -68,6 +68,7 @@ import android.util.MergedConfiguration; import android.util.Slog; import android.view.DisplayCutout; import android.view.IWindowSession; +import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.Surface; import android.view.SurfaceControl; @@ -164,6 +165,7 @@ class TaskSnapshotSurface implements StartingSurface { final Rect tmpContentInsets = new Rect(); final Rect tmpStableInsets = new Rect(); final InsetsState mTmpInsetsState = new InsetsState(); + final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0]; final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration(); final TaskDescription taskDescription = new TaskDescription(); taskDescription.setBackgroundColor(WHITE); @@ -231,8 +233,8 @@ class TaskSnapshotSurface implements StartingSurface { } try { final int res = session.addToDisplay(window, window.mSeq, layoutParams, - View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect, tmpRect, - tmpCutout, null, mTmpInsetsState); + View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect, + tmpRect, tmpCutout, null, mTmpInsetsState, mTempControls); if (res < 0) { Slog.w(TAG, "Failed to add snapshot starting window res=" + res); return null; @@ -249,7 +251,7 @@ class TaskSnapshotSurface implements StartingSurface { session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1, tmpFrame, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState, - sTmpSurfaceSize, sTmpSurfaceControl); + mTempControls, sTmpSurfaceSize, sTmpSurfaceControl); } catch (RemoteException e) { // Local call. } @@ -377,6 +379,7 @@ class TaskSnapshotSurface implements StartingSurface { frame = null; mTmpDstFrame.set(mFrame); } + mTmpDstFrame.offsetTo(0, 0); // Scale the mismatch dimensions to fill the task bounds mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight()); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 569b8f61c4f4..7219164ad2f1 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -737,6 +737,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return parent != null ? parent.getDisplayArea() : null; } + boolean isAttached() { + return getDisplayArea() != null; + } + void setWaitingForDrawnIfResizingChanged() { for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowContainer wc = mChildren.get(i); @@ -2076,8 +2080,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * @see #getAnimationAdapter */ boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, - boolean isVoiceInteraction, - @Nullable OnAnimationFinishedCallback animationFinishedCallback) { + boolean isVoiceInteraction, @Nullable OnAnimationFinishedCallback finishedCallback) { if (mWmService.mDisableTransitionAnimation) { ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: transition animation is disabled or skipped. " @@ -2092,22 +2095,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation"); if (okToAnimate()) { - final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp, - transit, enter, isVoiceInteraction); - AnimationAdapter adapter = adapters.first; - AnimationAdapter thumbnailAdapter = adapters.second; - if (adapter != null) { - startAnimation(getPendingTransaction(), adapter, !isVisible(), - ANIMATION_TYPE_APP_TRANSITION, animationFinishedCallback); - if (adapter.getShowWallpaper()) { - getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; - } - if (thumbnailAdapter != null) { - mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(), - thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION, - (type, anim) -> { }); - } - } + applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback); } else { cancelAnimation(); } @@ -2201,12 +2189,37 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return resultAdapters; } + protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter, + int transit, boolean isVoiceInteraction, + @Nullable OnAnimationFinishedCallback finishedCallback) { + final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp, + transit, enter, isVoiceInteraction); + AnimationAdapter adapter = adapters.first; + AnimationAdapter thumbnailAdapter = adapters.second; + if (adapter != null) { + startAnimation(getPendingTransaction(), adapter, !isVisible(), + ANIMATION_TYPE_APP_TRANSITION, finishedCallback); + if (adapter.getShowWallpaper()) { + getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; + } + if (thumbnailAdapter != null) { + mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(), + thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION, (type, anim) -> { }); + } + } + } + final SurfaceAnimationRunner getSurfaceAnimationRunner() { return mWmService.mSurfaceAnimationRunner; } private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction) { + if (isOrganized()) { + // Defer to the task organizer to run animations + return null; + } + final DisplayContent displayContent = getDisplayContent(); final DisplayInfo displayInfo = displayContent.getDisplayInfo(); final int width = displayInfo.appWidth; @@ -2295,6 +2308,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { mLastLayer = -1; reassignLayer(t); + + // Leash is now responsible for position, so set our position to 0. + t.setPosition(mSurfaceControl, 0, 0); + mLastSurfacePosition.set(0, 0); } @Override @@ -2302,6 +2319,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< mLastLayer = -1; mSurfaceFreezer.unfreeze(t); reassignLayer(t); + updateSurfacePosition(t); } /** @@ -2365,11 +2383,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } } - void updateSurfacePosition() { + final void updateSurfacePosition() { + updateSurfacePosition(getPendingTransaction()); + } + + void updateSurfacePosition(Transaction t) { // Avoid fighting with the organizer over Surface position. if (isOrganized()) return; - if (mSurfaceControl == null) { + if (mSurfaceControl == null || mSurfaceAnimator.hasLeash()) { return; } @@ -2378,7 +2400,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return; } - getPendingTransaction().setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y); + t.setPosition(mSurfaceControl, mTmpPos.x, mTmpPos.y); mLastSurfacePosition.set(mTmpPos.x, mTmpPos.y); } @@ -2501,9 +2523,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // We need to copy the SurfaceControl instead of returning the original // because the Parcel FLAGS PARCELABLE_WRITE_RETURN_VALUE cause SurfaceControls // to release themselves. - SurfaceControl sc = new SurfaceControl(); - sc.copyFrom(wc.getSurfaceControl()); - return sc; + return new SurfaceControl(wc.getSurfaceControl()); } WindowContainerToken toWindowContainerToken() { @@ -2570,4 +2590,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return willSync; } + + boolean useBLASTSync() { + return mUsingBLASTSyncTransaction; + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a1e0eb730ff7..a488af7cdee0 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -25,13 +25,16 @@ import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; import static android.Manifest.permission.RESTRICTED_VR_ACCESS; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; +import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.StatusBarManager.DISABLE_MASK; +import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; import static android.content.pm.PackageManager.FEATURE_PC; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Process.INVALID_UID; import static android.os.Process.SYSTEM_UID; import static android.os.Process.myPid; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; @@ -72,6 +75,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED; import static android.view.WindowManagerGlobal.ADD_OKAY; import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY; +import static android.view.WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC; import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID; @@ -227,6 +231,7 @@ import android.view.InputChannel; import android.view.InputDevice; import android.view.InputEvent; import android.view.InputWindowHandle; +import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.KeyEvent; import android.view.MagnificationSpec; @@ -1356,7 +1361,8 @@ public class WindowManagerService extends IWindowManager.Stub LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, - InsetsState outInsetsState) { + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls, + int requestUserId) { int[] appOp = new int[1]; final boolean isRoundedCornerOverlay = (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0; @@ -1425,6 +1431,20 @@ public class WindowManagerService extends IWindowManager.Stub return WindowManagerGlobal.ADD_INVALID_DISPLAY; } + int userId = UserHandle.getUserId(session.mUid); + if (requestUserId != userId) { + try { + mAmInternal.handleIncomingUser(callingPid, callingUid, requestUserId, + false /*allowAll*/, ALLOW_NON_FULL, null, null); + } catch (Exception exp) { + ProtoLog.w(WM_ERROR, "Trying to add window with invalid user=%d", + requestUserId); + return WindowManagerGlobal.ADD_INVALID_USER; + } + // It's fine to use this userId + userId = requestUserId; + } + ActivityRecord activity = null; final boolean hasParent = parentWindow != null; // Use existing parent window token for child windows since they go in the same token @@ -1513,7 +1533,7 @@ public class WindowManagerService extends IWindowManager.Stub } final WindowState win = new WindowState(this, session, client, token, parentWindow, - appOp[0], seq, attrs, viewVisibility, session.mUid, + appOp[0], seq, attrs, viewVisibility, session.mUid, userId, session.mCanAddInternalSystemWindow); if (win.mDeathRecipient == null) { // Client has apparently died, so there is no reason to @@ -1643,8 +1663,7 @@ public class WindowManagerService extends IWindowManager.Stub outStableInsets, outDisplayCutout)) { res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS; } - outInsetsState.set(win.getInsetsState(), - win.mClient instanceof IWindow.Stub /* copySource */); + outInsetsState.set(win.getInsetsState(), win.isClientLocal()); if (mInTouchMode) { res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE; @@ -1681,10 +1700,11 @@ public class WindowManagerService extends IWindowManager.Stub ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s" + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5)); - if (win.isVisibleOrAdding() && displayContent.updateOrientation()) { displayContent.sendNewConfiguration(); } + + getInsetsSourceControls(win, outActiveControls); } Binder.restoreCallingIdentity(origId); @@ -1832,8 +1852,7 @@ public class WindowManagerService extends IWindowManager.Stub if ((w.mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) { return true; } - if (DevicePolicyCache.getInstance().getScreenCaptureDisabled( - UserHandle.getUserId(w.mOwnerUid))) { + if (DevicePolicyCache.getInstance().getScreenCaptureDisabled(w.mShowUserId)) { return true; } return false; @@ -2080,7 +2099,8 @@ public class WindowManagerService extends IWindowManager.Stub Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame, DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl, InsetsState outInsetsState, - Point outSurfaceSize, SurfaceControl outBLASTSurfaceControl) { + InsetsSourceControl[] outActiveControls, Point outSurfaceSize, + SurfaceControl outBLASTSurfaceControl) { int result = 0; boolean configChanged; final int pid = Binder.getCallingPid(); @@ -2106,6 +2126,10 @@ public class WindowManagerService extends IWindowManager.Stub win.finishSeamlessRotation(false /* timeout */); } + if (win.useBLASTSync()) { + result |= RELAYOUT_RES_BLAST_SYNC; + } + int attrChanges = 0; int flagChanges = 0; int privateFlagChanges = 0; @@ -2375,8 +2399,7 @@ public class WindowManagerService extends IWindowManager.Stub outStableInsets); outCutout.set(win.getWmDisplayCutout().getDisplayCutout()); outBackdropFrame.set(win.getBackdropFrame(win.getFrameLw())); - outInsetsState.set(win.getInsetsState(), - win.mClient instanceof IWindow.Stub /* copySource */); + outInsetsState.set(win.getInsetsState(), win.isClientLocal()); if (DEBUG) { Slog.v(TAG_WM, "Relayout given client " + client.asBinder() + ", requestedWidth=" + requestedWidth @@ -2407,12 +2430,28 @@ public class WindowManagerService extends IWindowManager.Stub outSurfaceSize.set(winAnimator.mSurfaceController.getWidth(), winAnimator.mSurfaceController.getHeight()); } + getInsetsSourceControls(win, outActiveControls); } Binder.restoreCallingIdentity(origId); return result; } + private void getInsetsSourceControls(WindowState win, InsetsSourceControl[] outControls) { + if (outControls != null) { + final InsetsSourceControl[] controls = + win.getDisplayContent().getInsetsStateController().getControlsForDispatch(win); + Arrays.fill(outControls, null); + if (controls != null) { + final int length = Math.min(controls.length, outControls.length); + for (int i = 0; i < length; i++) { + outControls[i] = win.isClientLocal() + ? new InsetsSourceControl(controls[i]) : controls[i]; + } + } + } + } + private boolean tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator, boolean focusMayChange) { // Try starting an animation; if there isn't one, we @@ -2555,6 +2594,8 @@ public class WindowManagerService extends IWindowManager.Stub String packageName, boolean fromClientToken) { final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()"); + // WindowContext users usually don't hold MANAGE_APP_TOKEN permission. Check permissions + // by checkAddPermission. if (!callerCanManageAppTokens) { final int res = mPolicy.checkAddPermission(type, false /* isRoundedCornerOverlay */, packageName, new int[1]); @@ -2569,7 +2610,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { if (!callerCanManageAppTokens) { if (packageName == null || !unprivilegedAppCanCreateTokenWith( - null /* parentWindow */, callingUid, type, type, null /* tokenForLog */, + null /* parentWindow */, callingUid, type, type, binder, packageName)) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } @@ -2594,7 +2635,7 @@ public class WindowManagerService extends IWindowManager.Stub new WallpaperWindowToken(this, binder, true, dc, callerCanManageAppTokens); } else { new WindowToken(this, binder, type, true, dc, callerCanManageAppTokens, - false /* roundedCornerOverlay */, fromClientToken); + callingUid, false /* roundedCornerOverlay */, fromClientToken); } } } finally { @@ -2617,8 +2658,25 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void removeWindowToken(IBinder binder, int displayId) { - if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); + final boolean callerCanManageAppTokens = + checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()"); + final WindowToken windowToken; + synchronized (mGlobalLock) { + windowToken = mRoot.getWindowToken(binder); + } + if (windowToken == null) { + ProtoLog.w(WM_ERROR, + "removeWindowToken: Attempted to remove non-existing token: %s", binder); + return; + } + final int callingUid = Binder.getCallingUid(); + + // If MANAGE_APP_TOKEN permission is not held(usually from WindowContext), callers can only + // remove the window tokens which they added themselves. + if (!callerCanManageAppTokens && (windowToken.getOwnerUid() == INVALID_UID + || callingUid != windowToken.getOwnerUid())) { + throw new SecurityException("removeWindowToken: Requires MANAGE_APP_TOKENS permission" + + " to remove token owned by another uid"); } final long origId = Binder.clearCallingIdentity(); @@ -2631,14 +2689,7 @@ public class WindowManagerService extends IWindowManager.Stub return; } - final WindowToken token = dc.removeWindowToken(binder); - if (token == null) { - ProtoLog.w(WM_ERROR, - "removeWindowToken: Attempted to remove non-existing token: %s", - binder); - return; - } - + dc.removeWindowToken(binder); dc.getInputMonitor().updateInputWindowsLw(true /*force*/); } } finally { @@ -2890,7 +2941,7 @@ public class WindowManagerService extends IWindowManager.Stub mClientFreezingScreen = true; final long origId = Binder.clearCallingIdentity(); try { - startFreezingDisplayLocked(exitAnim, enterAnim); + startFreezingDisplay(exitAnim, enterAnim); mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT); mH.sendEmptyMessageDelayed(H.CLIENT_FREEZE_TIMEOUT, 5000); } finally { @@ -5428,13 +5479,17 @@ public class WindowManagerService extends IWindowManager.Stub return changed; } - void startFreezingDisplayLocked(int exitAnim, int enterAnim) { - startFreezingDisplayLocked(exitAnim, enterAnim, - getDefaultDisplayContentLocked()); + void startFreezingDisplay(int exitAnim, int enterAnim) { + startFreezingDisplay(exitAnim, enterAnim, getDefaultDisplayContentLocked()); } - void startFreezingDisplayLocked(int exitAnim, int enterAnim, - DisplayContent displayContent) { + void startFreezingDisplay(int exitAnim, int enterAnim, DisplayContent displayContent) { + startFreezingDisplay(exitAnim, enterAnim, displayContent, + ROTATION_UNDEFINED /* overrideOriginalRotation */); + } + + void startFreezingDisplay(int exitAnim, int enterAnim, DisplayContent displayContent, + int overrideOriginalRotation) { if (mDisplayFrozen || displayContent.getDisplayRotation().isRotatingSeamlessly()) { return; } @@ -5478,14 +5533,12 @@ public class WindowManagerService extends IWindowManager.Stub screenRotationAnimation.kill(); } - // Check whether the current screen contains any secure content. - boolean isSecure = displayContent.hasSecureWindowOnScreen(); - displayContent.updateDisplayInfo(); - screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent, - displayContent.getDisplayRotation().isFixedToUserRotation(), isSecure, - this); - displayContent.setRotationAnimation(screenRotationAnimation); + final int originalRotation = overrideOriginalRotation != ROTATION_UNDEFINED + ? overrideOriginalRotation + : displayContent.getDisplayInfo().rotation; + displayContent.setRotationAnimation(new ScreenRotationAnimation(displayContent, + originalRotation)); } void stopFreezingDisplayLocked() { @@ -6053,10 +6106,15 @@ public class WindowManagerService extends IWindowManager.Stub mRoot.forAllDisplays(dc -> { final int displayId = dc.getDisplayId(); final WindowState inputMethodTarget = dc.mInputMethodTarget; + final WindowState inputMethodInputTarget = dc.mInputMethodInputTarget; if (inputMethodTarget != null) { pw.print(" mInputMethodTarget in display# "); pw.print(displayId); pw.print(' '); pw.println(inputMethodTarget); } + if (inputMethodInputTarget != null) { + pw.print(" mInputMethodInputTarget in display# "); pw.print(displayId); + pw.print(' '); pw.println(inputMethodInputTarget); + } if (mAccessibilityController != null) { final Region magnificationRegion = new Region(); mAccessibilityController.getMagnificationRegionLocked(displayId, @@ -7308,7 +7366,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { final WindowState imeTarget = mWindowMap.get(imeTargetWindowToken); if (imeTarget != null) { - imeTarget.getDisplayContent().updateImeControlTarget(imeTarget); + imeTarget.getDisplayContent().setInputMethodInputTarget(imeTarget); } } } @@ -7371,7 +7429,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { WindowState window = mWindowMap.get(token); if (window != null) { - return UserHandle.getUserId(window.mOwnerUid); + return window.mShowUserId; } return UserHandle.USER_NULL; } @@ -7988,6 +8046,33 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** Set layer tracing flags. */ + public void setLayerTracingFlags(int flags) { + mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.DUMP, + "setLayerTracingFlags"); + long token = Binder.clearCallingIdentity(); + try { + Parcel data = null; + try { + IBinder sf = ServiceManager.getService("SurfaceFlinger"); + if (sf != null) { + data = Parcel.obtain(); + data.writeInterfaceToken("android.ui.ISurfaceComposer"); + data.writeInt(flags); + sf.transact(1033 /* LAYER_TRACE_FLAGS_CODE */, data, null, 0 /* flags */); + } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to set layer tracing flags"); + } finally { + if (data != null) { + data.recycle(); + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + @Override public boolean mirrorDisplay(int displayId, SurfaceControl outSurfaceControl) { if (!checkCallingPermission(READ_FRAME_BUFFER, "mirrorDisplay()")) { diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 3e2e9be24c4f..d9c0219c4779 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -129,6 +129,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next(); final WindowContainer wc = WindowContainer.fromBinder(entry.getKey()); + if (!wc.isAttached()) { + Slog.e(TAG, "Attempt to operate on detached container: " + wc); + continue; + } int containerEffect = applyWindowContainerChange(wc, entry.getValue()); effects |= containerEffect; @@ -146,6 +150,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub for (int i = 0, n = hops.size(); i < n; ++i) { final WindowContainerTransaction.HierarchyOp hop = hops.get(i); final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); + if (!wc.isAttached()) { + Slog.e(TAG, "Attempt to operate on detached container: " + wc); + continue; + } effects |= sanitizeAndApplyHierarchyOp(wc, hop); } if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { @@ -156,7 +164,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final PooledConsumer f = PooledLambda.obtainConsumer( ActivityRecord::ensureActivityConfiguration, PooledLambda.__(ActivityRecord.class), 0, - false /* preserveWindow */); + true /* preserveWindow */); try { for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { haveConfigChanges.valueAt(i).forAllActivities(f); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 3ebc0f410fd7..2e1b907e71bc 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -191,7 +191,6 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; -import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; import android.text.TextUtils; @@ -269,6 +268,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final int mAppOp; // UserId and appId of the owner. Don't display windows of non-current user. final int mOwnerUid; + /** + * Requested userId, if this is not equals with the userId from mOwnerUid, then this window is + * created for secondary user. + * Use this member instead of get userId from mOwnerUid while query for visibility. + */ + final int mShowUserId; /** The owner has {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} */ final boolean mOwnerCanAddInternalSystemWindow; final WindowId mWindowId; @@ -806,8 +811,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a, - int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) { - this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId, + int viewVisibility, int ownerId, int showUserId, + boolean ownerCanAddInternalSystemWindow) { + this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId, showUserId, ownerCanAddInternalSystemWindow, new PowerManagerWrapper() { @Override public void wakeUp(long time, @WakeReason int reason, String details) { @@ -823,8 +829,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a, - int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow, - PowerManagerWrapper powerManagerWrapper) { + int viewVisibility, int ownerId, int showUserId, + boolean ownerCanAddInternalSystemWindow, PowerManagerWrapper powerManagerWrapper) { super(service); mSession = s; mClient = c; @@ -832,6 +838,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mToken = token; mActivityRecord = mToken.asActivityRecord(); mOwnerUid = ownerId; + mShowUserId = showUserId; mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow; mWindowId = new WindowId(this); mAttrs.copyFrom(a); @@ -1462,6 +1469,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override void onDisplayChanged(DisplayContent dc) { + if (dc != null && mDisplayContent != null + && mDisplayContent.mInputMethodInputTarget == this) { + dc.setInputMethodInputTarget(mDisplayContent.mInputMethodInputTarget); + mDisplayContent.mInputMethodInputTarget = null; + } super.onDisplayChanged(dc); // Window was not laid out for this display yet, so make sure mLayoutSeq does not match. if (dc != null && mInputWindowHandle.displayId != dc.getDisplayId()) { @@ -3275,7 +3287,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } return win.showForAllUsers() - || mWmService.isCurrentProfile(UserHandle.getUserId(win.mOwnerUid)); + || mWmService.isCurrentProfile(win.mShowUserId); } private static void applyInsets(Region outRegion, Rect frame, Rect inset) { @@ -3479,6 +3491,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } + boolean isClientLocal() { + return mClient instanceof IWindow.Stub; + } + void updateLocationInParentDisplayIfNeeded() { final int embeddedDisplayContentsSize = mEmbeddedDisplayContents.size(); // If there is any embedded display which is re-parented to this window, we need to @@ -3791,7 +3807,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); proto.write(HASH_CODE, System.identityHashCode(this)); - proto.write(USER_ID, UserHandle.getUserId(mOwnerUid)); + proto.write(USER_ID, mShowUserId); final CharSequence title = getWindowTag(); if (title != null) { proto.write(TITLE, title.toString()); @@ -3975,7 +3991,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mLastTitle = title; mWasExiting = mAnimatingExit; mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this)) - + " u" + UserHandle.getUserId(mOwnerUid) + + " u" + mShowUserId + " " + mLastTitle + (mAnimatingExit ? " EXITING}" : "}"); } return mStringNameCache; @@ -4270,9 +4286,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP logPerformShow("performShow on "); final int drawState = mWinAnimator.mDrawState; - if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) - && mAttrs.type != TYPE_APPLICATION_STARTING && mActivityRecord != null) { - mActivityRecord.onFirstWindowDrawn(this, mWinAnimator); + if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW) && mActivityRecord != null) { + if (mAttrs.type != TYPE_APPLICATION_STARTING) { + mActivityRecord.onFirstWindowDrawn(this, mWinAnimator); + } else { + mActivityRecord.onStartingWindowDrawn(); + } } if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) { @@ -5233,23 +5252,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { super.onAnimationLeashCreated(t, leash); - - // Leash is now responsible for position, so set our position to 0. - t.setPosition(mSurfaceControl, 0, 0); - mLastSurfacePosition.set(0, 0); } @Override public void onAnimationLeashLost(Transaction t) { super.onAnimationLeashLost(t); - updateSurfacePosition(t); } @Override - void updateSurfacePosition() { - updateSurfacePosition(getPendingTransaction()); - } - @VisibleForTesting void updateSurfacePosition(Transaction t) { if (mSurfaceControl == null) { diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index f7ea953e5a01..55e6ab76188d 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -126,7 +126,7 @@ class WindowSurfaceController { if (useBLAST) { mBLASTSurfaceControl = win.makeSurface() .setParent(mSurfaceControl) - .setName("BLAST Adapter Layer") + .setName(name + "(BLAST)") .setHidden(false) .setBLASTLayer() .build(); diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 7457a1d05335..b4e770f24eaf 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.os.Process.INVALID_UID; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; @@ -44,6 +45,7 @@ import android.graphics.Rect; import android.os.Debug; import android.os.IBinder; import android.os.RemoteException; +import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; import android.view.InsetsState; @@ -106,6 +108,11 @@ class WindowToken extends WindowContainer<WindowState> { @VisibleForTesting final boolean mFromClientToken; + private DeathRecipient mDeathRecipient; + private boolean mBinderDied = false; + + private final int mOwnerUid; + /** * Used to fix the transform of the token to be rotated to a rotation different than it's * display. The window frames and surfaces corresponding to this token will be layouted and @@ -165,6 +172,30 @@ class WindowToken extends WindowContainer<WindowState> { } } + private class DeathRecipient implements IBinder.DeathRecipient { + private boolean mHasUnlinkToDeath = false; + + @Override + public void binderDied() { + synchronized (mWmService.mGlobalLock) { + mBinderDied = true; + removeImmediately(); + } + } + + void linkToDeath() throws RemoteException { + token.linkToDeath(DeathRecipient.this, 0); + } + + void unlinkToDeath() { + if (mHasUnlinkToDeath) { + return; + } + token.unlinkToDeath(DeathRecipient.this, 0); + mHasUnlinkToDeath = true; + } + } + /** * Compares two child window of this token and returns -1 if the first is lesser than the * second in terms of z-order and 1 otherwise. @@ -193,23 +224,35 @@ class WindowToken extends WindowContainer<WindowState> { WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) { - this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens, + this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens, INVALID_UID, roundedCornerOverlay, false /* fromClientToken */); } WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty, - DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay, - boolean fromClientToken) { + DisplayContent dc, boolean ownerCanManageAppTokens, int ownerUid, + boolean roundedCornerOverlay, boolean fromClientToken) { super(service); token = _token; windowType = type; mPersistOnEmpty = persistOnEmpty; mOwnerCanManageAppTokens = ownerCanManageAppTokens; + mOwnerUid = ownerUid; mRoundedCornerOverlay = roundedCornerOverlay; mFromClientToken = fromClientToken; if (dc != null) { dc.addWindowToken(token, this); } + if (shouldReportToClient()) { + try { + mDeathRecipient = new DeathRecipient(); + mDeathRecipient.linkToDeath(); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to add window token with type " + windowType + " on " + + "display " + dc.getDisplayId(), e); + mDeathRecipient = null; + return; + } + } } void removeAllWindowsIfPossible() { @@ -222,7 +265,7 @@ class WindowToken extends WindowContainer<WindowState> { } void setExiting() { - if (mChildren.size() == 0) { + if (isEmpty()) { super.removeImmediately(); return; } @@ -340,6 +383,21 @@ class WindowToken extends WindowContainer<WindowState> { // Needs to occur after the token is removed from the display above to avoid attempt at // duplicate removal of this window container from it's parent. super.removeImmediately(); + + reportWindowTokenRemovedToClient(); + } + + private void reportWindowTokenRemovedToClient() { + if (!shouldReportToClient()) { + return; + } + mDeathRecipient.unlinkToDeath(); + IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(token); + try { + windowTokenClient.onWindowTokenRemoved(); + } catch (RemoteException e) { + ProtoLog.w(WM_ERROR, "Could not report token removal to the window token client."); + } } @Override @@ -361,38 +419,43 @@ class WindowToken extends WindowContainer<WindowState> { } void reportConfigToWindowTokenClient() { - if (asActivityRecord() != null) { - // Activities are updated through ATM callbacks. + if (!shouldReportToClient()) { return; } - - // Unfortunately, this WindowToken is not from WindowContext so it cannot handle - // its own configuration changes. - if (!mFromClientToken) { - return; + if (mLastReportedConfig == null) { + mLastReportedConfig = new Configuration(); } - final Configuration config = getConfiguration(); final int displayId = getDisplayContent().getDisplayId(); - if (config.equals(mLastReportedConfig) && displayId == mLastReportedDisplay) { + if (config.diff(mLastReportedConfig) == 0 && displayId == mLastReportedDisplay) { // No changes since last reported time. return; } - mLastReportedConfig = config; + mLastReportedConfig.setTo(config); mLastReportedDisplay = displayId; IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(token); - if (windowTokenClient != null) { - try { - windowTokenClient.onConfigurationChanged(config, displayId); - } catch (RemoteException e) { - ProtoLog.w(WM_ERROR, - "Could not report config changes to the window token client."); - } + try { + windowTokenClient.onConfigurationChanged(config, displayId); + } catch (RemoteException e) { + ProtoLog.w(WM_ERROR, + "Could not report config changes to the window token client."); } } + /** + * @return {@code true} if this {@link WindowToken} is not an {@link ActivityRecord} and + * registered from client side. + */ + private boolean shouldReportToClient() { + // Only report to client for WindowToken because Activities are updated through ATM + // callbacks. + return asActivityRecord() == null + // Report to {@link android.view.WindowTokenClient} if this token was registered from it. + && mFromClientToken && !mBinderDied; + } + @Override void assignLayer(SurfaceControl.Transaction t, int layer) { if (windowType == TYPE_DOCK_DIVIDER) { @@ -494,13 +557,12 @@ class WindowToken extends WindowContainer<WindowState> { // cleared and the configuration is restored from parent. if (!changed) { clearFixedRotationTransform(null /* applyDisplayRotation */); - onConfigurationChanged(getParent().getConfiguration()); } } /** - * Clears the transform and apply display rotation if the action is given. The caller needs to - * refresh the configuration of this container after this method call. + * Clears the transform and apply display rotation if the action is given. If the display will + * not rotate, the transformed containers are restored to their original states. */ void clearFixedRotationTransform(Runnable applyDisplayRotation) { final FixedRotationTransformState state = mFixedRotationTransformState; @@ -514,6 +576,12 @@ class WindowToken extends WindowContainer<WindowState> { state.mIsTransforming = false; if (applyDisplayRotation != null) { applyDisplayRotation.run(); + } else { + // The display will not rotate to the rotation of this container, let's cancel them. + for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) { + state.mAssociatedTokens.get(i).cancelFixedRotationTransform(); + } + cancelFixedRotationTransform(); } // The state is cleared at the end, because it is used to indicate that other windows can // use seamless rotation when applying rotation to display. @@ -523,6 +591,26 @@ class WindowToken extends WindowContainer<WindowState> { mFixedRotationTransformState = null; } + /** Restores the changes that applies to this container. */ + private void cancelFixedRotationTransform() { + final WindowContainer<?> parent = getParent(); + if (parent == null) { + // The window may be detached or detaching. + return; + } + final int originalRotation = getWindowConfiguration().getRotation(); + onConfigurationChanged(parent.getConfiguration()); + onCancelFixedRotationTransform(originalRotation); + } + + /** + * It is called when the window is using fixed rotation transform, and before display applies + * the same rotation, the rotation change for display is canceled, e.g. the orientation from + * sensor is updated to previous direction. + */ + void onCancelFixedRotationTransform(int originalDisplayRotation) { + } + @Override void resolveOverrideConfiguration(Configuration newParentConfig) { super.resolveOverrideConfiguration(newParentConfig); @@ -535,8 +623,8 @@ class WindowToken extends WindowContainer<WindowState> { } @Override - void updateSurfacePosition() { - super.updateSurfacePosition(); + void updateSurfacePosition(SurfaceControl.Transaction t) { + super.updateSurfacePosition(t); if (isFixedRotationTransforming()) { // The window is layouted in a simulated rotated display but the real display hasn't // rotated, so here transforms its surface to fit in the real display. @@ -616,4 +704,8 @@ class WindowToken extends WindowContainer<WindowState> { int getWindowLayerFromType() { return mWmService.mPolicy.getWindowLayerFromTypeLw(windowType, mOwnerCanManageAppTokens); } + + int getOwnerUid() { + return mOwnerUid; + } } diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp index e99a264c42e4..76b171337bb9 100644 --- a/services/core/jni/com_android_server_SystemServer.cpp +++ b/services/core/jni/com_android_server_SystemServer.cpp @@ -135,7 +135,7 @@ static void android_server_SystemServer_spawnFdLeakCheckThread(JNIEnv*, jobject) static jlong android_server_SystemServer_startIncrementalService(JNIEnv* env, jclass klass, jobject self) { - return Incremental_IncrementalService_Start(); + return Incremental_IncrementalService_Start(env); } static void android_server_SystemServer_setIncrementalServiceSystemReady(JNIEnv* env, jclass klass, diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp index 853eba71d88a..e32a343433a8 100644 --- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp +++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp @@ -410,6 +410,8 @@ private: // Installation. bool onPrepareImage(dataloader::DataLoaderInstallationFiles addedFiles) final { + ALOGE("onPrepareImage: start."); + JNIEnv* env = GetOrAttachJNIEnvironment(mJvm); const auto& jni = jniIds(env); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index d1c47d9feed7..1da074002456 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -1836,8 +1836,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Bundle addSyntheticRestrictions(Bundle restrictions) { if (disableCamera) { restrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); - } else { - restrictions.remove(UserManager.DISALLOW_CAMERA); + } + if (requireAutoTime) { + restrictions.putBoolean(UserManager.DISALLOW_CONFIG_DATE_TIME, true); } return restrictions; } @@ -1864,7 +1865,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Bundle getEffectiveRestrictions() { return addSyntheticRestrictions( - removeDeprecatedRestrictions(ensureUserRestrictions())); + removeDeprecatedRestrictions(new Bundle(ensureUserRestrictions()))); } Bundle getLocalUserRestrictions(int adminType) { @@ -2701,10 +2702,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Slog.i(LOG_TAG, "Clearing the DO..."); final ComponentName doAdminReceiver = doAdmin.info.getComponent(); clearDeviceOwnerLocked(doAdmin, doUserId); - // TODO(b/143516163): If we have a power cut here, we might leave active admin. Consider if - // it is worth the complexity to make it more robust. Slog.i(LOG_TAG, "Removing admin artifacts..."); - // TODO(b/143516163): Clean up application restrictions in UserManager. + // TODO(b/149075700): Clean up application restrictions in UserManager. removeAdminArtifacts(doAdminReceiver, doUserId); Slog.i(LOG_TAG, "Migration complete."); @@ -2746,16 +2745,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // The following policies weren't available to PO, but will be available after migration. parentAdmin.disableCamera = doAdmin.disableCamera; - - // TODO(b/143516163): Uncomment once corresponding APIs are available via parent instance. - // parentAdmin.disableScreenCapture = doAdmin.disableScreenCapture; - // parentAdmin.accountTypesWithManagementDisabled.addAll( - // doAdmin.accountTypesWithManagementDisabled); + parentAdmin.requireAutoTime = doAdmin.requireAutoTime; + parentAdmin.disableScreenCapture = doAdmin.disableScreenCapture; + parentAdmin.accountTypesWithManagementDisabled.addAll( + doAdmin.accountTypesWithManagementDisabled); moveDoUserRestrictionsToCopeParent(doAdmin, parentAdmin); - - // TODO(b/143516163): migrate network and security logging state, currently they are - // turned off when DO is removed. } private void moveDoUserRestrictionsToCopeParent(ActiveAdmin doAdmin, ActiveAdmin parentAdmin) { @@ -2775,7 +2770,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * a managed profile. */ @GuardedBy("getLockObject()") - void applyManagedProfileRestrictionIfDeviceOwnerLocked() { + private void applyManagedProfileRestrictionIfDeviceOwnerLocked() { final int doUserId = mOwners.getDeviceOwnerUserId(); if (doUserId == UserHandle.USER_NULL) { logIfVerbose("No DO found, skipping application of restriction."); @@ -3999,11 +3994,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mOwners.systemReady(); break; case SystemService.PHASE_ACTIVITY_MANAGER_READY: - maybeStartSecurityLogMonitorOnActivityManagerReady(); synchronized (getLockObject()) { migrateToProfileOnOrganizationOwnedDeviceIfCompLocked(); applyManagedProfileRestrictionIfDeviceOwnerLocked(); } + maybeStartSecurityLogMonitorOnActivityManagerReady(); final int userId = getManagedUserId(UserHandle.USER_SYSTEM); if (userId >= 0) { updatePersonalAppSuspension(userId, false /* running */); @@ -7839,16 +7834,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } Objects.requireNonNull(who, "ComponentName is null"); final int userHandle = UserHandle.getCallingUserId(); + boolean requireAutoTimeChanged = false; synchronized (getLockObject()) { ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); if (admin.requireAutoTime != required) { admin.requireAutoTime = required; saveSettingsLocked(userHandle); + requireAutoTimeChanged = true; } } - - // TODO: (b/145604635) Add upgrade case + // requireAutoTime is now backed by DISALLOW_CONFIG_DATE_TIME restriction, so propagate + // updated restrictions to the framework. + if (requireAutoTimeChanged) { + pushUserRestrictions(userHandle); + } // Turn AUTO_TIME on in settings if it is required if (required) { mInjector.binderWithCleanCallingIdentity( @@ -12459,6 +12459,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return DevicePolicyManagerService.this.getAllCrossProfilePackages(); } + @Override + public List<String> getDefaultCrossProfilePackages() { + return DevicePolicyManagerService.this.getDefaultCrossProfilePackages(); + } + /** * Sends the {@code intent} to the packages with cross profile capabilities. * diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp index 97de1800cae2..fc8c6feac22b 100644 --- a/services/incremental/BinderIncrementalService.cpp +++ b/services/incremental/BinderIncrementalService.cpp @@ -17,6 +17,7 @@ #include "BinderIncrementalService.h" #include <android-base/logging.h> +#include <android-base/no_destructor.h> #include <binder/IResultReceiver.h> #include <binder/PermissionCache.h> #include <incfs.h> @@ -57,10 +58,10 @@ static bool incFsValid(const sp<IVold>& vold) { return true; } -BinderIncrementalService::BinderIncrementalService(const sp<IServiceManager>& sm) - : mImpl(RealServiceManager(sm), getIncrementalDir()) {} +BinderIncrementalService::BinderIncrementalService(const sp<IServiceManager>& sm, JNIEnv* env) + : mImpl(RealServiceManager(sm, env), getIncrementalDir()) {} -BinderIncrementalService* BinderIncrementalService::start() { +BinderIncrementalService* BinderIncrementalService::start(JNIEnv* env) { if (!incFsEnabled()) { return nullptr; } @@ -80,7 +81,7 @@ BinderIncrementalService* BinderIncrementalService::start() { return nullptr; } - sp<BinderIncrementalService> self(new BinderIncrementalService(sm)); + sp<BinderIncrementalService> self(new BinderIncrementalService(sm, env)); status_t ret = sm->addService(String16{getServiceName()}, self); if (ret != android::OK) { return nullptr; @@ -93,8 +94,8 @@ BinderIncrementalService* BinderIncrementalService::start() { } status_t BinderIncrementalService::dump(int fd, const Vector<String16>&) { - static const String16 kDump("android.permission.DUMP"); - if (!PermissionCache::checkCallingPermission(kDump)) { + static const android::base::NoDestructor<String16> kDump("android.permission.DUMP"); + if (!PermissionCache::checkCallingPermission(*kDump)) { return PERMISSION_DENIED; } mImpl.onDump(fd); @@ -115,11 +116,14 @@ binder::Status BinderIncrementalService::openStorage(const std::string& path, return ok(); } -binder::Status BinderIncrementalService::createStorage(const std::string& path, - const DataLoaderParamsParcel& params, - const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener, - int32_t createMode, int32_t* _aidl_return) { - *_aidl_return = mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params), listener, android::incremental::IncrementalService::CreateOptions(createMode)); +binder::Status BinderIncrementalService::createStorage( + const std::string& path, const DataLoaderParamsParcel& params, + const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener, + int32_t createMode, int32_t* _aidl_return) { + *_aidl_return = + mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params), listener, + android::incremental::IncrementalService::CreateOptions( + createMode)); return ok(); } @@ -155,11 +159,6 @@ binder::Status BinderIncrementalService::deleteStorage(int32_t storageId) { return ok(); } -binder::Status BinderIncrementalService::setStorageParams(int32_t storage, bool enableReadLogs, int32_t* _aidl_return) { - *_aidl_return = mImpl.setStorageParams(storage, enableReadLogs); - return ok(); -} - binder::Status BinderIncrementalService::makeDirectory(int32_t storageId, const std::string& path, int32_t* _aidl_return) { *_aidl_return = mImpl.makeDir(storageId, path); @@ -185,7 +184,8 @@ static std::tuple<int, incfs::FileId, incfs::NewFileParams> toMakeFileParams( if (!params.signature) { nfp.signature = {}; } else { - nfp.signature = {(const char*)params.signature->data(), (IncFsSize)params.signature->size()}; + nfp.signature = {(const char*)params.signature->data(), + (IncFsSize)params.signature->size()}; } return {0, id, nfp}; } @@ -282,10 +282,16 @@ binder::Status BinderIncrementalService::configureNativeBinaries( return ok(); } +binder::Status BinderIncrementalService::waitForNativeBinariesExtraction(int storageId, + bool* _aidl_return) { + *_aidl_return = mImpl.waitForNativeBinariesExtraction(storageId); + return ok(); +} + } // namespace android::os::incremental -jlong Incremental_IncrementalService_Start() { - return (jlong)android::os::incremental::BinderIncrementalService::start(); +jlong Incremental_IncrementalService_Start(JNIEnv* env) { + return (jlong)android::os::incremental::BinderIncrementalService::start(env); } void Incremental_IncrementalService_OnSystemReady(jlong self) { if (self) { diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h index d0357d924586..5a7d5da56f18 100644 --- a/services/incremental/BinderIncrementalService.h +++ b/services/incremental/BinderIncrementalService.h @@ -18,6 +18,7 @@ #include <binder/BinderService.h> #include <binder/IServiceManager.h> +#include <jni.h> #include "IncrementalService.h" #include "android/os/incremental/BnIncrementalService.h" @@ -28,9 +29,9 @@ namespace android::os::incremental { class BinderIncrementalService : public BnIncrementalService, public BinderService<BinderIncrementalService> { public: - BinderIncrementalService(const sp<IServiceManager>& sm); + BinderIncrementalService(const sp<IServiceManager>& sm, JNIEnv* env); - static BinderIncrementalService* start(); + static BinderIncrementalService* start(JNIEnv* env); static const char16_t* getServiceName() { return u"incremental"; } status_t dump(int fd, const Vector<String16>& args) final; @@ -38,7 +39,10 @@ public: void onInvalidStorage(int mountId); binder::Status openStorage(const std::string& path, int32_t* _aidl_return) final; - binder::Status createStorage(const ::std::string& path, const ::android::content::pm::DataLoaderParamsParcel& params, const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener, int32_t createMode, int32_t* _aidl_return) final; + binder::Status createStorage( + const ::std::string& path, const ::android::content::pm::DataLoaderParamsParcel& params, + const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener, + int32_t createMode, int32_t* _aidl_return) final; binder::Status createLinkedStorage(const std::string& path, int32_t otherStorageId, int32_t createMode, int32_t* _aidl_return) final; binder::Status makeBindMount(int32_t storageId, const std::string& sourcePath, @@ -68,10 +72,11 @@ public: std::vector<uint8_t>* _aidl_return) final; binder::Status startLoading(int32_t storageId, bool* _aidl_return) final; binder::Status deleteStorage(int32_t storageId) final; + binder::Status configureNativeBinaries(int32_t storageId, const std::string& apkFullPath, const std::string& libDirRelativePath, const std::string& abi, bool* _aidl_return) final; - binder::Status setStorageParams(int32_t storage, bool enableReadLogs, int32_t* _aidl_return) final; + binder::Status waitForNativeBinariesExtraction(int storageId, bool* _aidl_return) final; private: android::incremental::IncrementalService mImpl; diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index d36eae89c1ff..8d084cddf0de 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -20,28 +20,24 @@ #include <android-base/file.h> #include <android-base/logging.h> +#include <android-base/no_destructor.h> #include <android-base/properties.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> #include <android/content/pm/IDataLoaderStatusListener.h> #include <android/os/IVold.h> -#include <androidfw/ZipFileRO.h> -#include <androidfw/ZipUtils.h> #include <binder/BinderService.h> #include <binder/Nullable.h> #include <binder/ParcelFileDescriptor.h> #include <binder/Status.h> #include <sys/stat.h> #include <uuid/uuid.h> -#include <zlib.h> #include <charconv> #include <ctime> #include <filesystem> #include <iterator> #include <span> -#include <stack> -#include <thread> #include <type_traits> #include "Metadata.pb.h" @@ -51,7 +47,7 @@ using namespace android::content::pm; namespace fs = std::filesystem; constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS"; -constexpr const char* kOpUsage = "android:get_usage_stats"; +constexpr const char* kOpUsage = "android:loader_usage_stats"; namespace android::incremental { @@ -73,7 +69,7 @@ struct Constants { }; static const Constants& constants() { - static Constants c; + static constexpr Constants c; return c; } @@ -159,8 +155,13 @@ std::string makeBindMdName() { } } // namespace +const bool IncrementalService::sEnablePerfLogging = + android::base::GetBoolProperty("incremental.perflogging", false); + IncrementalService::IncFsMount::~IncFsMount() { - incrementalService.mDataLoaderManager->destroyDataLoader(mountId); + if (dataLoaderStub) { + dataLoaderStub->destroy(); + } LOG(INFO) << "Unmounting and cleaning up mount " << mountId << " with root '" << root << '\''; for (auto&& [target, _] : bindPoints) { LOG(INFO) << "\tbind: " << target; @@ -236,6 +237,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v mDataLoaderManager(sm.getDataLoaderManager()), mIncFs(sm.getIncFs()), mAppOpsManager(sm.getAppOpsManager()), + mJni(sm.getJni()), mIncrementalDir(rootDir) { if (!mVold) { LOG(FATAL) << "Vold service is unavailable"; @@ -246,15 +248,25 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v if (!mAppOpsManager) { LOG(FATAL) << "AppOpsManager is unavailable"; } + + mJobQueue.reserve(16); + mJobProcessor = std::thread([this]() { + mJni->initializeForCurrentThread(); + runJobProcessing(); + }); + mountExistingImages(); } -FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) { - return IncFs_FileIdFromMetadata({(const char*)metadata.data(), metadata.size()}); +IncrementalService::~IncrementalService() { + { + std::lock_guard lock(mJobMutex); + mRunning = false; + } + mJobCondition.notify_all(); + mJobProcessor.join(); } -IncrementalService::~IncrementalService() = default; - inline const char* toString(TimePoint t) { using SystemClock = std::chrono::system_clock; time_t time = SystemClock::to_time_t( @@ -285,9 +297,12 @@ void IncrementalService::onDump(int fd) { dprintf(fd, "\t\tmountId: %d\n", mnt.mountId); dprintf(fd, "\t\troot: %s\n", mnt.root.c_str()); dprintf(fd, "\t\tnextStorageDirNo: %d\n", mnt.nextStorageDirNo.load()); - dprintf(fd, "\t\tdataLoaderStatus: %d\n", mnt.dataLoaderStatus.load()); - { - const auto& params = mnt.dataLoaderParams; + if (mnt.dataLoaderStub) { + const auto& dataLoaderStub = *mnt.dataLoaderStub; + dprintf(fd, "\t\tdataLoaderStatus: %d\n", dataLoaderStub.status()); + dprintf(fd, "\t\tdataLoaderStartRequested: %s\n", + dataLoaderStub.startRequested() ? "true" : "false"); + const auto& params = dataLoaderStub.params(); dprintf(fd, "\t\tdataLoaderParams:\n"); dprintf(fd, "\t\t\ttype: %s\n", toString(params.type).c_str()); dprintf(fd, "\t\t\tpackageName: %s\n", params.packageName.c_str()); @@ -318,10 +333,9 @@ void IncrementalService::onDump(int fd) { } } -std::optional<std::future<void>> IncrementalService::onSystemReady() { - std::promise<void> threadFinished; +void IncrementalService::onSystemReady() { if (mSystemReady.exchange(true)) { - return {}; + return; } std::vector<IfsMountPtr> mounts; @@ -335,20 +349,21 @@ std::optional<std::future<void>> IncrementalService::onSystemReady() { } } + if (mounts.empty()) { + return; + } + std::thread([this, mounts = std::move(mounts)]() { - /* TODO(b/151241369): restore data loaders on reboot. + mJni->initializeForCurrentThread(); for (auto&& ifs : mounts) { - if (prepareDataLoader(*ifs)) { + if (ifs->dataLoaderStub->create()) { LOG(INFO) << "Successfully started data loader for mount " << ifs->mountId; } else { // TODO(b/133435829): handle data loader start failures LOG(WARNING) << "Failed to start data loader for mount " << ifs->mountId; } } - */ - mPrepareDataLoaders.set_value_at_thread_exit(); }).detach(); - return mPrepareDataLoaders.get_future(); } auto IncrementalService::getStorageSlotLocked() -> MountMap::iterator { @@ -465,15 +480,13 @@ StorageId IncrementalService::createStorage( return kInvalidStorageId; } - ifs->dataLoaderParams = std::move(dataLoaderParams); - { metadata::Mount m; m.mutable_storage()->set_id(ifs->mountId); - m.mutable_loader()->set_type((int)ifs->dataLoaderParams.type); - m.mutable_loader()->set_package_name(ifs->dataLoaderParams.packageName); - m.mutable_loader()->set_class_name(ifs->dataLoaderParams.className); - m.mutable_loader()->set_arguments(ifs->dataLoaderParams.arguments); + m.mutable_loader()->set_type((int)dataLoaderParams.type); + m.mutable_loader()->set_package_name(dataLoaderParams.packageName); + m.mutable_loader()->set_class_name(dataLoaderParams.className); + m.mutable_loader()->set_arguments(dataLoaderParams.arguments); const auto metadata = m.SerializeAsString(); m.mutable_loader()->release_arguments(); m.mutable_loader()->release_class_name(); @@ -501,14 +514,20 @@ StorageId IncrementalService::createStorage( // Done here as well, all data structures are in good state. secondCleanupOnFailure.release(); - if (!prepareDataLoader(*ifs, &dataLoaderStatusListener)) { - LOG(ERROR) << "prepareDataLoader() failed"; - deleteStorageLocked(*ifs, std::move(l)); - return kInvalidStorageId; - } + auto dataLoaderStub = + prepareDataLoader(*ifs, std::move(dataLoaderParams), &dataLoaderStatusListener); + CHECK(dataLoaderStub); mountIt->second = std::move(ifs); l.unlock(); + + if (mSystemReady.load(std::memory_order_relaxed) && !dataLoaderStub->create()) { + // failed to create data loader + LOG(ERROR) << "initializeDataLoader() failed"; + deleteStorage(dataLoaderStub->id()); + return kInvalidStorageId; + } + LOG(INFO) << "created storage " << mountId; return mountId; } @@ -578,13 +597,14 @@ StorageId IncrementalService::findStorageId(std::string_view path) const { int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLogs) { const auto ifs = getIfs(storageId); if (!ifs) { + LOG(ERROR) << "setStorageParams failed, invalid storageId: " << storageId; return -EINVAL; } + const auto& params = ifs->dataLoaderStub->params(); if (enableReadLogs) { - if (auto status = - mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage, - ifs->dataLoaderParams.packageName.c_str()); + if (auto status = mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage, + params.packageName.c_str()); !status.isOk()) { LOG(ERROR) << "checkPermission failed: " << status.toString8(); return fromBinderStatus(status); @@ -597,7 +617,7 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog } if (enableReadLogs) { - registerAppOpsCallback(ifs->dataLoaderParams.packageName); + registerAppOpsCallback(params.packageName); } return 0; @@ -697,8 +717,8 @@ IncrementalService::IfsMountPtr IncrementalService::getIfs(StorageId storage) co const IncrementalService::IfsMountPtr& IncrementalService::getIfsLocked(StorageId storage) const { auto it = mMounts.find(storage); if (it == mMounts.end()) { - static const IfsMountPtr kEmpty = {}; - return kEmpty; + static const android::base::NoDestructor<IfsMountPtr> kEmpty{}; + return *kEmpty; } return it->second; } @@ -719,7 +739,10 @@ int IncrementalService::bind(StorageId storage, std::string_view source, std::st if (storageInfo == ifs->storages.end()) { return -EINVAL; } - std::string normSource = normalizePathToStorage(ifs, storage, source); + std::string normSource = normalizePathToStorageLocked(storageInfo, source); + if (normSource.empty()) { + return -EINVAL; + } l.unlock(); std::unique_lock l2(mLock, std::defer_lock); return addBindMount(*ifs, storage, storageInfo->second.name, std::move(normSource), @@ -768,22 +791,28 @@ int IncrementalService::unbind(StorageId storage, std::string_view target) { return 0; } -std::string IncrementalService::normalizePathToStorage(const IncrementalService::IfsMountPtr ifs, - StorageId storage, std::string_view path) { - const auto storageInfo = ifs->storages.find(storage); - if (storageInfo == ifs->storages.end()) { - return {}; - } +std::string IncrementalService::normalizePathToStorageLocked( + IncFsMount::StorageMap::iterator storageIt, std::string_view path) { std::string normPath; if (path::isAbsolute(path)) { normPath = path::normalize(path); + if (!path::startsWith(normPath, storageIt->second.name)) { + return {}; + } } else { - normPath = path::normalize(path::join(storageInfo->second.name, path)); + normPath = path::normalize(path::join(storageIt->second.name, path)); } - if (!path::startsWith(normPath, storageInfo->second.name)) { + return normPath; +} + +std::string IncrementalService::normalizePathToStorage(const IncrementalService::IfsMountPtr& ifs, + StorageId storage, std::string_view path) { + std::unique_lock l(ifs->lock); + const auto storageInfo = ifs->storages.find(storage); + if (storageInfo == ifs->storages.end()) { return {}; } - return normPath; + return normalizePathToStorageLocked(storageInfo, path); } int IncrementalService::makeFile(StorageId storage, std::string_view path, int mode, FileId id, @@ -791,7 +820,8 @@ int IncrementalService::makeFile(StorageId storage, std::string_view path, int m if (auto ifs = getIfs(storage)) { std::string normPath = normalizePathToStorage(ifs, storage, path); if (normPath.empty()) { - LOG(ERROR) << "Internal error: storageId " << storage << " failed to normalize: " << path; + LOG(ERROR) << "Internal error: storageId " << storage + << " failed to normalize: " << path; return -EINVAL; } auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params); @@ -799,10 +829,6 @@ int IncrementalService::makeFile(StorageId storage, std::string_view path, int m LOG(ERROR) << "Internal error: storageId " << storage << " failed to makeFile: " << err; return err; } - std::vector<uint8_t> metadataBytes; - if (params.metadata.data && params.metadata.size > 0) { - metadataBytes.assign(params.metadata.data, params.metadata.data + params.metadata.size); - } return 0; } return -EINVAL; @@ -842,8 +868,9 @@ int IncrementalService::makeDirs(StorageId storageId, std::string_view path, int int IncrementalService::link(StorageId sourceStorageId, std::string_view oldPath, StorageId destStorageId, std::string_view newPath) { - if (auto ifsSrc = getIfs(sourceStorageId), ifsDest = getIfs(destStorageId); - ifsSrc && ifsSrc == ifsDest) { + auto ifsSrc = getIfs(sourceStorageId); + auto ifsDest = sourceStorageId == destStorageId ? ifsSrc : getIfs(destStorageId); + if (ifsSrc && ifsSrc == ifsDest) { std::string normOldPath = normalizePathToStorage(ifsSrc, sourceStorageId, oldPath); std::string normNewPath = normalizePathToStorage(ifsDest, destStorageId, newPath); if (normOldPath.empty() || normNewPath.empty()) { @@ -973,34 +1000,19 @@ std::vector<std::string> IncrementalService::listFiles(StorageId storage) const } bool IncrementalService::startLoading(StorageId storage) const { + DataLoaderStubPtr dataLoaderStub; { std::unique_lock l(mLock); const auto& ifs = getIfsLocked(storage); if (!ifs) { return false; } - if (ifs->dataLoaderStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) { - ifs->dataLoaderStartRequested = true; - return true; + dataLoaderStub = ifs->dataLoaderStub; + if (!dataLoaderStub) { + return false; } } - return startDataLoader(storage); -} - -bool IncrementalService::startDataLoader(MountId mountId) const { - sp<IDataLoader> dataloader; - auto status = mDataLoaderManager->getDataLoader(mountId, &dataloader); - if (!status.isOk()) { - return false; - } - if (!dataloader) { - return false; - } - status = dataloader->start(mountId); - if (!status.isOk()) { - return false; - } - return true; + return dataLoaderStub->requestStart(); } void IncrementalService::mountExistingImages() { @@ -1046,15 +1058,18 @@ bool IncrementalService::mountExistingImage(std::string_view root) { mNextId = std::max(mNextId, ifs->mountId + 1); // DataLoader params + DataLoaderParamsParcel dataLoaderParams; { - auto& dlp = ifs->dataLoaderParams; const auto& loader = mount.loader(); - dlp.type = (android::content::pm::DataLoaderType)loader.type(); - dlp.packageName = loader.package_name(); - dlp.className = loader.class_name(); - dlp.arguments = loader.arguments(); + dataLoaderParams.type = (android::content::pm::DataLoaderType)loader.type(); + dataLoaderParams.packageName = loader.package_name(); + dataLoaderParams.className = loader.class_name(); + dataLoaderParams.arguments = loader.arguments(); } + prepareDataLoader(*ifs, std::move(dataLoaderParams), nullptr); + CHECK(ifs->dataLoaderStub); + std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints; auto d = openDir(path::c_str(mountTarget)); while (auto e = ::readdir(d.get())) { @@ -1124,17 +1139,13 @@ bool IncrementalService::mountExistingImage(std::string_view root) { return true; } -bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, - const DataLoaderStatusListener* externalListener) { - if (!mSystemReady.load(std::memory_order_relaxed)) { - std::unique_lock l(ifs.lock); - return true; // eventually... - } - +IncrementalService::DataLoaderStubPtr IncrementalService::prepareDataLoader( + IncrementalService::IncFsMount& ifs, DataLoaderParamsParcel&& params, + const DataLoaderStatusListener* externalListener) { std::unique_lock l(ifs.lock); - if (ifs.dataLoaderStatus != -1) { + if (ifs.dataLoaderStub) { LOG(INFO) << "Skipped data loader preparation because it already exists"; - return true; + return ifs.dataLoaderStub; } FileSystemControlParcel fsControlParcel; @@ -1143,24 +1154,30 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, fsControlParcel.incremental->pendingReads.reset( base::unique_fd(::dup(ifs.control.pendingReads()))); fsControlParcel.incremental->log.reset(base::unique_fd(::dup(ifs.control.logs()))); - sp<IncrementalDataLoaderListener> listener = - new IncrementalDataLoaderListener(*this, - externalListener ? *externalListener - : DataLoaderStatusListener()); - bool created = false; - auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, ifs.dataLoaderParams, fsControlParcel, listener, &created); - if (!status.isOk() || !created) { - LOG(ERROR) << "Failed to create a data loader for mount " << ifs.mountId; - return false; - } - return true; + fsControlParcel.service = new IncrementalServiceConnector(*this, ifs.mountId); + + ifs.dataLoaderStub = new DataLoaderStub(*this, ifs.mountId, std::move(params), + std::move(fsControlParcel), externalListener); + return ifs.dataLoaderStub; +} + +template <class Duration> +static long elapsedMcs(Duration start, Duration end) { + return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count(); } -// Extract lib filse from zip, create new files in incfs and write data to them +// Extract lib files from zip, create new files in incfs and write data to them bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath, std::string_view libDirRelativePath, std::string_view abi) { + auto start = Clock::now(); + const auto ifs = getIfs(storage); + if (!ifs) { + LOG(ERROR) << "Invalid storage " << storage; + return false; + } + // First prepare target directories if they don't exist yet if (auto res = makeDirs(storage, libDirRelativePath, 0755)) { LOG(ERROR) << "Failed to prepare target lib directory " << libDirRelativePath @@ -1168,112 +1185,237 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_ return false; } - std::unique_ptr<ZipFileRO> zipFile(ZipFileRO::open(apkFullPath.data())); - if (!zipFile) { + auto mkDirsTs = Clock::now(); + ZipArchiveHandle zipFileHandle; + if (OpenArchive(path::c_str(apkFullPath), &zipFileHandle)) { LOG(ERROR) << "Failed to open zip file at " << apkFullPath; return false; } + + // Need a shared pointer: will be passing it into all unpacking jobs. + std::shared_ptr<ZipArchive> zipFile(zipFileHandle, [](ZipArchiveHandle h) { CloseArchive(h); }); void* cookie = nullptr; const auto libFilePrefix = path::join(constants().libDir, abi); - if (!zipFile.get()->startIteration(&cookie, libFilePrefix.c_str() /* prefix */, - constants().libSuffix.data() /* suffix */)) { + if (StartIteration(zipFile.get(), &cookie, libFilePrefix, constants().libSuffix)) { LOG(ERROR) << "Failed to start zip iteration for " << apkFullPath; return false; } - ZipEntryRO entry = nullptr; - bool success = true; - while ((entry = zipFile.get()->nextEntry(cookie)) != nullptr) { - char fileName[PATH_MAX]; - if (zipFile.get()->getEntryFileName(entry, fileName, sizeof(fileName))) { + auto endIteration = [](void* cookie) { EndIteration(cookie); }; + auto iterationCleaner = std::unique_ptr<void, decltype(endIteration)>(cookie, endIteration); + + auto openZipTs = Clock::now(); + + std::vector<Job> jobQueue; + ZipEntry entry; + std::string_view fileName; + while (!Next(cookie, &entry, &fileName)) { + if (fileName.empty()) { continue; } + + auto startFileTs = Clock::now(); + const auto libName = path::basename(fileName); const auto targetLibPath = path::join(libDirRelativePath, libName); const auto targetLibPathAbsolute = normalizePathToStorage(ifs, storage, targetLibPath); // If the extract file already exists, skip - struct stat st; - if (stat(targetLibPathAbsolute.c_str(), &st) == 0) { - LOG(INFO) << "Native lib file already exists: " << targetLibPath - << "; skipping extraction"; + if (access(targetLibPathAbsolute.c_str(), F_OK) == 0) { + if (sEnablePerfLogging) { + LOG(INFO) << "incfs: Native lib file already exists: " << targetLibPath + << "; skipping extraction, spent " + << elapsedMcs(startFileTs, Clock::now()) << "mcs"; + } continue; } - uint32_t uncompressedLen; - if (!zipFile.get()->getEntryInfo(entry, nullptr, &uncompressedLen, nullptr, nullptr, - nullptr, nullptr)) { - LOG(ERROR) << "Failed to read native lib entry: " << fileName; - success = false; - break; - } - // Create new lib file without signature info - incfs::NewFileParams libFileParams{}; - libFileParams.size = uncompressedLen; - libFileParams.signature = {}; - // Metadata of the new lib file is its relative path - IncFsSpan libFileMetadata; - libFileMetadata.data = targetLibPath.c_str(); - libFileMetadata.size = targetLibPath.size(); - libFileParams.metadata = libFileMetadata; + incfs::NewFileParams libFileParams = { + .size = entry.uncompressed_length, + .signature = {}, + // Metadata of the new lib file is its relative path + .metadata = {targetLibPath.c_str(), (IncFsSize)targetLibPath.size()}, + }; incfs::FileId libFileId = idFromMetadata(targetLibPath); - if (auto res = makeFile(storage, targetLibPath, 0777, libFileId, libFileParams)) { + if (auto res = mIncFs->makeFile(ifs->control, targetLibPathAbsolute, 0777, libFileId, + libFileParams)) { LOG(ERROR) << "Failed to make file for: " << targetLibPath << " errno: " << res; - success = false; // If one lib file fails to be created, abort others as well - break; + return false; } + + auto makeFileTs = Clock::now(); + // If it is a zero-byte file, skip data writing - if (uncompressedLen == 0) { + if (entry.uncompressed_length == 0) { + if (sEnablePerfLogging) { + LOG(INFO) << "incfs: Extracted " << libName + << "(0 bytes): " << elapsedMcs(startFileTs, makeFileTs) << "mcs"; + } continue; } - // Write extracted data to new file - std::vector<uint8_t> libData(uncompressedLen); - if (!zipFile.get()->uncompressEntry(entry, &libData[0], uncompressedLen)) { - LOG(ERROR) << "Failed to extract native lib zip entry: " << fileName; - success = false; - break; - } - const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId); - if (!writeFd.ok()) { - LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd; - success = false; - break; + jobQueue.emplace_back([this, zipFile, entry, ifs = std::weak_ptr<IncFsMount>(ifs), + libFileId, libPath = std::move(targetLibPath), + makeFileTs]() mutable { + extractZipFile(ifs.lock(), zipFile.get(), entry, libFileId, libPath, makeFileTs); + }); + + if (sEnablePerfLogging) { + auto prepareJobTs = Clock::now(); + LOG(INFO) << "incfs: Processed " << libName << ": " + << elapsedMcs(startFileTs, prepareJobTs) + << "mcs, make file: " << elapsedMcs(startFileTs, makeFileTs) + << " prepare job: " << elapsedMcs(makeFileTs, prepareJobTs); } - const int numBlocks = uncompressedLen / constants().blockSize + 1; - std::vector<IncFsDataBlock> instructions; - auto remainingData = std::span(libData); - for (int i = 0; i < numBlocks - 1; i++) { - auto inst = IncFsDataBlock{ - .fileFd = writeFd, - .pageIndex = static_cast<IncFsBlockIndex>(i), - .compression = INCFS_COMPRESSION_KIND_NONE, - .kind = INCFS_BLOCK_KIND_DATA, - .dataSize = static_cast<uint16_t>(constants().blockSize), - .data = reinterpret_cast<const char*>(remainingData.data()), - }; - instructions.push_back(inst); - remainingData = remainingData.subspan(constants().blockSize); + } + + auto processedTs = Clock::now(); + + if (!jobQueue.empty()) { + { + std::lock_guard lock(mJobMutex); + if (mRunning) { + auto& existingJobs = mJobQueue[ifs->mountId]; + if (existingJobs.empty()) { + existingJobs = std::move(jobQueue); + } else { + existingJobs.insert(existingJobs.end(), std::move_iterator(jobQueue.begin()), + std::move_iterator(jobQueue.end())); + } + } } - // Last block - auto inst = IncFsDataBlock{ - .fileFd = writeFd, - .pageIndex = static_cast<IncFsBlockIndex>(numBlocks - 1), + mJobCondition.notify_all(); + } + + if (sEnablePerfLogging) { + auto end = Clock::now(); + LOG(INFO) << "incfs: configureNativeBinaries complete in " << elapsedMcs(start, end) + << "mcs, make dirs: " << elapsedMcs(start, mkDirsTs) + << " open zip: " << elapsedMcs(mkDirsTs, openZipTs) + << " make files: " << elapsedMcs(openZipTs, processedTs) + << " schedule jobs: " << elapsedMcs(processedTs, end); + } + + return true; +} + +void IncrementalService::extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile, + ZipEntry& entry, const incfs::FileId& libFileId, + std::string_view targetLibPath, + Clock::time_point scheduledTs) { + if (!ifs) { + LOG(INFO) << "Skipping zip file " << targetLibPath << " extraction for an expired mount"; + return; + } + + auto libName = path::basename(targetLibPath); + auto startedTs = Clock::now(); + + // Write extracted data to new file + // NOTE: don't zero-initialize memory, it may take a while for nothing + auto libData = std::unique_ptr<uint8_t[]>(new uint8_t[entry.uncompressed_length]); + if (ExtractToMemory(zipFile, &entry, libData.get(), entry.uncompressed_length)) { + LOG(ERROR) << "Failed to extract native lib zip entry: " << libName; + return; + } + + auto extractFileTs = Clock::now(); + + const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId); + if (!writeFd.ok()) { + LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd; + return; + } + + auto openFileTs = Clock::now(); + const int numBlocks = + (entry.uncompressed_length + constants().blockSize - 1) / constants().blockSize; + std::vector<IncFsDataBlock> instructions(numBlocks); + auto remainingData = std::span(libData.get(), entry.uncompressed_length); + for (int i = 0; i < numBlocks; i++) { + const auto blockSize = std::min<uint16_t>(constants().blockSize, remainingData.size()); + instructions[i] = IncFsDataBlock{ + .fileFd = writeFd.get(), + .pageIndex = static_cast<IncFsBlockIndex>(i), .compression = INCFS_COMPRESSION_KIND_NONE, .kind = INCFS_BLOCK_KIND_DATA, - .dataSize = static_cast<uint16_t>(remainingData.size()), + .dataSize = blockSize, .data = reinterpret_cast<const char*>(remainingData.data()), }; - instructions.push_back(inst); - size_t res = mIncFs->writeBlocks(instructions); - if (res != instructions.size()) { - LOG(ERROR) << "Failed to write data into: " << targetLibPath; - success = false; + remainingData = remainingData.subspan(blockSize); + } + auto prepareInstsTs = Clock::now(); + + size_t res = mIncFs->writeBlocks(instructions); + if (res != instructions.size()) { + LOG(ERROR) << "Failed to write data into: " << targetLibPath; + return; + } + + if (sEnablePerfLogging) { + auto endFileTs = Clock::now(); + LOG(INFO) << "incfs: Extracted " << libName << "(" << entry.compressed_length << " -> " + << entry.uncompressed_length << " bytes): " << elapsedMcs(startedTs, endFileTs) + << "mcs, scheduling delay: " << elapsedMcs(scheduledTs, startedTs) + << " extract: " << elapsedMcs(startedTs, extractFileTs) + << " open: " << elapsedMcs(extractFileTs, openFileTs) + << " prepare: " << elapsedMcs(openFileTs, prepareInstsTs) + << " write: " << elapsedMcs(prepareInstsTs, endFileTs); + } +} + +bool IncrementalService::waitForNativeBinariesExtraction(StorageId storage) { + struct WaitPrinter { + const Clock::time_point startTs = Clock::now(); + ~WaitPrinter() noexcept { + if (sEnablePerfLogging) { + const auto endTs = Clock::now(); + LOG(INFO) << "incfs: waitForNativeBinariesExtraction() complete in " + << elapsedMcs(startTs, endTs) << "mcs"; + } + } + } waitPrinter; + + MountId mount; + { + auto ifs = getIfs(storage); + if (!ifs) { + return true; } - instructions.clear(); + mount = ifs->mountId; + } + + std::unique_lock lock(mJobMutex); + mJobCondition.wait(lock, [this, mount] { + return !mRunning || + (mPendingJobsMount != mount && mJobQueue.find(mount) == mJobQueue.end()); + }); + return mRunning; +} + +void IncrementalService::runJobProcessing() { + for (;;) { + std::unique_lock lock(mJobMutex); + mJobCondition.wait(lock, [this]() { return !mRunning || !mJobQueue.empty(); }); + if (!mRunning) { + return; + } + + auto it = mJobQueue.begin(); + mPendingJobsMount = it->first; + auto queue = std::move(it->second); + mJobQueue.erase(it); + lock.unlock(); + + for (auto&& job : queue) { + job(); + } + + lock.lock(); + mPendingJobsMount = kInvalidStorageId; + lock.unlock(); + mJobCondition.notify_all(); } - zipFile.get()->endIteration(cookie); - return success; } void IncrementalService::registerAppOpsCallback(const std::string& packageName) { @@ -1288,7 +1430,8 @@ void IncrementalService::registerAppOpsCallback(const std::string& packageName) listener = cb; } - mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, String16(packageName.c_str()), listener); + mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, + String16(packageName.c_str()), listener); } bool IncrementalService::unregisterAppOpsCallback(const std::string& packageName) { @@ -1317,7 +1460,7 @@ void IncrementalService::onAppOpChanged(const std::string& packageName) { std::lock_guard l(mLock); affected.reserve(mMounts.size()); for (auto&& [id, ifs] : mMounts) { - if (ifs->mountId == id && ifs->dataLoaderParams.packageName == packageName) { + if (ifs->mountId == id && ifs->dataLoaderStub->params().packageName == packageName) { affected.push_back(ifs); } } @@ -1327,41 +1470,107 @@ void IncrementalService::onAppOpChanged(const std::string& packageName) { } } -binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId, - int newStatus) { - if (externalListener) { - // Give an external listener a chance to act before we destroy something. - externalListener->onStatusChanged(mountId, newStatus); +IncrementalService::DataLoaderStub::~DataLoaderStub() { + waitForDestroy(); +} + +bool IncrementalService::DataLoaderStub::create() { + { + std::unique_lock lock(mStatusMutex); + mStartRequested = false; + mDestroyRequested = false; + } + bool created = false; + auto status = mService.mDataLoaderManager->initializeDataLoader(mId, mParams, mControl, this, + &created); + if (!status.isOk() || !created) { + LOG(ERROR) << "Failed to create a data loader for mount " << mId; + return false; } + return true; +} - bool startRequested = false; +bool IncrementalService::DataLoaderStub::requestStart() { { - std::unique_lock l(incrementalService.mLock); - const auto& ifs = incrementalService.getIfsLocked(mountId); - if (!ifs) { - LOG(WARNING) << "Received data loader status " << int(newStatus) - << " for unknown mount " << mountId; - return binder::Status::ok(); + std::unique_lock lock(mStatusMutex); + mStartRequested = true; + if (mStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) { + return true; } - ifs->dataLoaderStatus = newStatus; + } + return start(); +} + +bool IncrementalService::DataLoaderStub::start() { + sp<IDataLoader> dataloader; + auto status = mService.mDataLoaderManager->getDataLoader(mId, &dataloader); + if (!status.isOk()) { + return false; + } + if (!dataloader) { + return false; + } + status = dataloader->start(mId); + if (!status.isOk()) { + return false; + } + return true; +} + +void IncrementalService::DataLoaderStub::destroy() { + { + std::unique_lock lock(mStatusMutex); + mDestroyRequested = true; + } + mService.mDataLoaderManager->destroyDataLoader(mId); + + waitForDestroy(); +} + +bool IncrementalService::DataLoaderStub::waitForDestroy() { + auto now = std::chrono::steady_clock::now(); + std::unique_lock lock(mStatusMutex); + return mStatusCondition.wait_until(lock, now + 60s, [this] { + return mStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED; + }); +} - if (newStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED) { - ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STOPPED; - incrementalService.deleteStorageLocked(*ifs, std::move(l)); +binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mountId, int newStatus) { + if (mStatus == newStatus) { + return binder::Status::ok(); + } + + if (mListener) { + mListener->onStatusChanged(mountId, newStatus); + } + + bool startRequested; + bool destroyRequested; + { + std::unique_lock lock(mStatusMutex); + if (mStatus == newStatus) { return binder::Status::ok(); } - startRequested = ifs->dataLoaderStartRequested; + startRequested = mStartRequested; + destroyRequested = mDestroyRequested; + + mStatus = newStatus; } switch (newStatus) { case IDataLoaderStatusListener::DATA_LOADER_CREATED: { if (startRequested) { - incrementalService.startDataLoader(mountId); + LOG(WARNING) << "Start was requested, triggering, for mount: " << mountId; + start(); } break; } case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: { + if (!destroyRequested) { + LOG(WARNING) << "DataLoader destroyed, reconnecting, for mount: " << mountId; + create(); + } break; } case IDataLoaderStatusListener::DATA_LOADER_STARTED: { @@ -1394,4 +1603,14 @@ void IncrementalService::AppOpsListener::opChanged(int32_t, const String16&) { incrementalService.onAppOpChanged(packageName); } +binder::Status IncrementalService::IncrementalServiceConnector::setStorageParams( + bool enableReadLogs, int32_t* _aidl_return) { + *_aidl_return = incrementalService.setStorageParams(storage, enableReadLogs); + return binder::Status::ok(); +} + +FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) { + return IncFs_FileIdFromMetadata({(const char*)metadata.data(), metadata.size()}); +} + } // namespace android::incremental diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index 58002974e180..8c79d7725dcf 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -23,22 +23,26 @@ #include <utils/String16.h> #include <utils/StrongPointer.h> #include <utils/Vector.h> +#include <ziparchive/zip_archive.h> #include <atomic> #include <chrono> -#include <future> +#include <condition_variable> +#include <functional> #include <limits> #include <map> #include <mutex> #include <span> #include <string> #include <string_view> +#include <thread> #include <unordered_map> #include <utility> #include <vector> #include "ServiceWrappers.h" #include "android/content/pm/BnDataLoaderStatusListener.h" +#include "android/os/incremental/BnIncrementalServiceConnector.h" #include "incfs.h" #include "path.h" @@ -59,7 +63,8 @@ using Clock = std::chrono::steady_clock; using TimePoint = std::chrono::time_point<Clock>; using Seconds = std::chrono::seconds; -using DataLoaderStatusListener = ::android::sp<::android::content::pm::IDataLoaderStatusListener>; +using IDataLoaderStatusListener = ::android::content::pm::IDataLoaderStatusListener; +using DataLoaderStatusListener = ::android::sp<IDataLoaderStatusListener>; class IncrementalService final { public: @@ -94,7 +99,7 @@ public: void onDump(int fd); - std::optional<std::future<void>> onSystemReady(); + void onSystemReady(); StorageId createStorage(std::string_view mountPoint, DataLoaderParamsParcel&& dataLoaderParams, const DataLoaderStatusListener& dataLoaderStatusListener, @@ -130,33 +135,80 @@ public: std::vector<std::string> listFiles(StorageId storage) const; bool startLoading(StorageId storage) const; + bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath, std::string_view libDirRelativePath, std::string_view abi); + bool waitForNativeBinariesExtraction(StorageId storage); - class IncrementalDataLoaderListener : public android::content::pm::BnDataLoaderStatusListener { + class AppOpsListener : public android::BnAppOpsCallback { public: - IncrementalDataLoaderListener(IncrementalService& incrementalService, - DataLoaderStatusListener externalListener) - : incrementalService(incrementalService), externalListener(externalListener) {} - // Callbacks interface - binder::Status onStatusChanged(MountId mount, int newStatus) override; + AppOpsListener(IncrementalService& incrementalService, std::string packageName) + : incrementalService(incrementalService), packageName(std::move(packageName)) {} + void opChanged(int32_t op, const String16& packageName) final; private: IncrementalService& incrementalService; - DataLoaderStatusListener externalListener; + const std::string packageName; }; - class AppOpsListener : public android::BnAppOpsCallback { + class IncrementalServiceConnector : public BnIncrementalServiceConnector { public: - AppOpsListener(IncrementalService& incrementalService, std::string packageName) : incrementalService(incrementalService), packageName(std::move(packageName)) {} - void opChanged(int32_t op, const String16& packageName) override; + IncrementalServiceConnector(IncrementalService& incrementalService, int32_t storage) + : incrementalService(incrementalService), storage(storage) {} + binder::Status setStorageParams(bool enableReadLogs, int32_t* _aidl_return) final; private: IncrementalService& incrementalService; - const std::string packageName; + int32_t const storage; }; private: + static const bool sEnablePerfLogging; + + struct IncFsMount; + + class DataLoaderStub : public android::content::pm::BnDataLoaderStatusListener { + public: + DataLoaderStub(IncrementalService& service, MountId id, DataLoaderParamsParcel&& params, + FileSystemControlParcel&& control, + const DataLoaderStatusListener* externalListener) + : mService(service), + mId(id), + mParams(std::move(params)), + mControl(std::move(control)), + mListener(externalListener ? *externalListener : DataLoaderStatusListener()) {} + ~DataLoaderStub(); + + bool create(); + bool requestStart(); + void destroy(); + + // accessors + MountId id() const { return mId; } + const DataLoaderParamsParcel& params() const { return mParams; } + int status() const { return mStatus; } + bool startRequested() const { return mStartRequested; } + + private: + binder::Status onStatusChanged(MountId mount, int newStatus) final; + + bool start(); + bool waitForDestroy(); + + IncrementalService& mService; + MountId const mId; + DataLoaderParamsParcel const mParams; + FileSystemControlParcel const mControl; + DataLoaderStatusListener const mListener; + + std::mutex mStatusMutex; + std::condition_variable mStatusCondition; + int mStatus = IDataLoaderStatusListener::DATA_LOADER_DESTROYED; + bool mStartRequested = false; + bool mDestroyRequested = true; + }; + using DataLoaderStubPtr = sp<DataLoaderStub>; + struct IncFsMount { struct Bind { StorageId storage; @@ -180,10 +232,8 @@ private: /*const*/ MountId mountId; StorageMap storages; BindMap bindPoints; - DataLoaderParamsParcel dataLoaderParams; + DataLoaderStubPtr dataLoaderStub; std::atomic<int> nextStorageDirNo{0}; - std::atomic<int> dataLoaderStatus = -1; - bool dataLoaderStartRequested = false; const IncrementalService& incrementalService; IncFsMount(std::string root, MountId mountId, Control control, @@ -218,8 +268,8 @@ private: std::string&& source, std::string&& target, BindKind kind, std::unique_lock<std::mutex>& mainLock); - bool prepareDataLoader(IncFsMount& ifs, const DataLoaderStatusListener* externalListener = nullptr); - bool startDataLoader(MountId mountId) const; + DataLoaderStubPtr prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel&& params, + const DataLoaderStatusListener* externalListener = nullptr); BindPathMap::const_iterator findStorageLocked(std::string_view path) const; StorageId findStorageId(std::string_view path) const; @@ -227,8 +277,10 @@ private: void deleteStorage(IncFsMount& ifs); void deleteStorageLocked(IncFsMount& ifs, std::unique_lock<std::mutex>&& ifsLock); MountMap::iterator getStorageSlotLocked(); - std::string normalizePathToStorage(const IfsMountPtr incfs, StorageId storage, + std::string normalizePathToStorage(const IfsMountPtr& incfs, StorageId storage, std::string_view path); + std::string normalizePathToStorageLocked(IncFsMount::StorageMap::iterator storageIt, + std::string_view path); binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs); @@ -236,11 +288,17 @@ private: bool unregisterAppOpsCallback(const std::string& packageName); void onAppOpChanged(const std::string& packageName); - // Member variables - std::unique_ptr<VoldServiceWrapper> const mVold; - std::unique_ptr<DataLoaderManagerWrapper> const mDataLoaderManager; - std::unique_ptr<IncFsWrapper> const mIncFs; - std::unique_ptr<AppOpsManagerWrapper> const mAppOpsManager; + void runJobProcessing(); + void extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile, ZipEntry& entry, + const incfs::FileId& libFileId, std::string_view targetLibPath, + Clock::time_point scheduledTs); + +private: + const std::unique_ptr<VoldServiceWrapper> mVold; + const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager; + const std::unique_ptr<IncFsWrapper> mIncFs; + const std::unique_ptr<AppOpsManagerWrapper> mAppOpsManager; + const std::unique_ptr<JniWrapper> mJni; const std::string mIncrementalDir; mutable std::mutex mLock; @@ -253,7 +311,14 @@ private: std::atomic_bool mSystemReady = false; StorageId mNextId = 0; - std::promise<void> mPrepareDataLoaders; + + using Job = std::function<void()>; + std::unordered_map<MountId, std::vector<Job>> mJobQueue; + MountId mPendingJobsMount = kInvalidStorageId; + std::condition_variable mJobCondition; + std::mutex mJobMutex; + std::thread mJobProcessor; + bool mRunning = true; }; } // namespace android::incremental diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp index 9f4192fbf531..bf8e696a264c 100644 --- a/services/incremental/ServiceWrappers.cpp +++ b/services/incremental/ServiceWrappers.cpp @@ -14,8 +14,11 @@ * limitations under the License. */ +#define LOG_TAG "IncrementalService" + #include "ServiceWrappers.h" +#include <android-base/logging.h> #include <utils/String16.h> using namespace std::literals; @@ -25,8 +28,123 @@ namespace android::os::incremental { static constexpr auto kVoldServiceName = "vold"sv; static constexpr auto kDataLoaderManagerName = "dataloader_manager"sv; -RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager) - : mServiceManager(std::move(serviceManager)) {} +class RealVoldService : public VoldServiceWrapper { +public: + RealVoldService(const sp<os::IVold> vold) : mInterface(std::move(vold)) {} + ~RealVoldService() = default; + binder::Status mountIncFs(const std::string& backingPath, const std::string& targetDir, + int32_t flags, + IncrementalFileSystemControlParcel* _aidl_return) const final { + return mInterface->mountIncFs(backingPath, targetDir, flags, _aidl_return); + } + binder::Status unmountIncFs(const std::string& dir) const final { + return mInterface->unmountIncFs(dir); + } + binder::Status bindMount(const std::string& sourceDir, + const std::string& targetDir) const final { + return mInterface->bindMount(sourceDir, targetDir); + } + binder::Status setIncFsMountOptions( + const ::android::os::incremental::IncrementalFileSystemControlParcel& control, + bool enableReadLogs) const final { + return mInterface->setIncFsMountOptions(control, enableReadLogs); + } + +private: + sp<os::IVold> mInterface; +}; + +class RealDataLoaderManager : public DataLoaderManagerWrapper { +public: + RealDataLoaderManager(const sp<content::pm::IDataLoaderManager> manager) + : mInterface(manager) {} + ~RealDataLoaderManager() = default; + binder::Status initializeDataLoader(MountId mountId, const DataLoaderParamsParcel& params, + const FileSystemControlParcel& control, + const sp<IDataLoaderStatusListener>& listener, + bool* _aidl_return) const final { + return mInterface->initializeDataLoader(mountId, params, control, listener, _aidl_return); + } + binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const final { + return mInterface->getDataLoader(mountId, _aidl_return); + } + binder::Status destroyDataLoader(MountId mountId) const final { + return mInterface->destroyDataLoader(mountId); + } + +private: + sp<content::pm::IDataLoaderManager> mInterface; +}; + +class RealAppOpsManager : public AppOpsManagerWrapper { +public: + ~RealAppOpsManager() = default; + binder::Status checkPermission(const char* permission, const char* operation, + const char* package) const final { + return android::incremental::CheckPermissionForDataDelivery(permission, operation, package); + } + void startWatchingMode(int32_t op, const String16& packageName, + const sp<IAppOpsCallback>& callback) final { + mAppOpsManager.startWatchingMode(op, packageName, callback); + } + void stopWatchingMode(const sp<IAppOpsCallback>& callback) final { + mAppOpsManager.stopWatchingMode(callback); + } + +private: + android::AppOpsManager mAppOpsManager; +}; + +class RealJniWrapper final : public JniWrapper { +public: + RealJniWrapper(JavaVM* jvm); + void initializeForCurrentThread() const final; + + static JavaVM* getJvm(JNIEnv* env); + +private: + JavaVM* const mJvm; +}; + +class RealIncFs : public IncFsWrapper { +public: + RealIncFs() = default; + ~RealIncFs() = default; + Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) const final { + return incfs::createControl(cmd, pendingReads, logs); + } + ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId id, + NewFileParams params) const final { + return incfs::makeFile(control, path, mode, id, params); + } + ErrorCode makeDir(const Control& control, std::string_view path, int mode) const final { + return incfs::makeDir(control, path, mode); + } + RawMetadata getMetadata(const Control& control, FileId fileid) const final { + return incfs::getMetadata(control, fileid); + } + RawMetadata getMetadata(const Control& control, std::string_view path) const final { + return incfs::getMetadata(control, path); + } + FileId getFileId(const Control& control, std::string_view path) const final { + return incfs::getFileId(control, path); + } + ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final { + return incfs::link(control, from, to); + } + ErrorCode unlink(const Control& control, std::string_view path) const final { + return incfs::unlink(control, path); + } + base::unique_fd openForSpecialOps(const Control& control, FileId id) const final { + return base::unique_fd{incfs::openForSpecialOps(control, id).release()}; + } + ErrorCode writeBlocks(Span<const DataBlock> blocks) const final { + return incfs::writeBlocks(blocks); + } +}; + +RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env) + : mServiceManager(std::move(serviceManager)), mJvm(RealJniWrapper::getJvm(env)) {} template <class INTERFACE> sp<INTERFACE> RealServiceManager::getRealService(std::string_view serviceName) const { @@ -63,4 +181,62 @@ std::unique_ptr<AppOpsManagerWrapper> RealServiceManager::getAppOpsManager() { return std::make_unique<RealAppOpsManager>(); } +std::unique_ptr<JniWrapper> RealServiceManager::getJni() { + return std::make_unique<RealJniWrapper>(mJvm); +} + +static JavaVM* getJavaVm(JNIEnv* env) { + CHECK(env); + JavaVM* jvm = nullptr; + env->GetJavaVM(&jvm); + CHECK(jvm); + return jvm; +} + +static JNIEnv* getJniEnv(JavaVM* vm) { + JNIEnv* env; + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + return nullptr; + } + return env; +} + +static JNIEnv* getOrAttachJniEnv(JavaVM* jvm) { + if (!jvm) { + LOG(ERROR) << "No JVM instance"; + return nullptr; + } + + JNIEnv* env = getJniEnv(jvm); + if (!env) { + int result = jvm->AttachCurrentThread(&env, nullptr); + if (result != JNI_OK) { + LOG(ERROR) << "JVM thread attach failed: " << result; + return nullptr; + } + struct VmDetacher { + VmDetacher(JavaVM* vm) : mVm(vm) {} + ~VmDetacher() { mVm->DetachCurrentThread(); } + + private: + JavaVM* const mVm; + }; + static thread_local VmDetacher detacher(jvm); + } + + return env; +} + +RealJniWrapper::RealJniWrapper(JavaVM* jvm) : mJvm(jvm) { + CHECK(!!mJvm) << "JVM is unavailable"; +} + +void RealJniWrapper::initializeForCurrentThread() const { + (void)getOrAttachJniEnv(mJvm); +} + +JavaVM* RealJniWrapper::getJvm(JNIEnv* env) { + return getJavaVm(env); +} + } // namespace android::os::incremental diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h index 84bf1ffaf45c..142bf2ef32f3 100644 --- a/services/incremental/ServiceWrappers.h +++ b/services/incremental/ServiceWrappers.h @@ -29,6 +29,7 @@ #include <binder/AppOpsManager.h> #include <binder/IServiceManager.h> #include <incfs.h> +#include <jni.h> #include <memory> #include <string> @@ -93,6 +94,12 @@ public: virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0; }; +class JniWrapper { +public: + virtual ~JniWrapper() = default; + virtual void initializeForCurrentThread() const = 0; +}; + class ServiceManagerWrapper { public: virtual ~ServiceManagerWrapper() = default; @@ -100,127 +107,26 @@ public: virtual std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() = 0; virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0; virtual std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() = 0; + virtual std::unique_ptr<JniWrapper> getJni() = 0; }; // --- Real stuff --- -class RealVoldService : public VoldServiceWrapper { -public: - RealVoldService(const sp<os::IVold> vold) : mInterface(std::move(vold)) {} - ~RealVoldService() = default; - binder::Status mountIncFs(const std::string& backingPath, const std::string& targetDir, - int32_t flags, - IncrementalFileSystemControlParcel* _aidl_return) const final { - return mInterface->mountIncFs(backingPath, targetDir, flags, _aidl_return); - } - binder::Status unmountIncFs(const std::string& dir) const final { - return mInterface->unmountIncFs(dir); - } - binder::Status bindMount(const std::string& sourceDir, - const std::string& targetDir) const final { - return mInterface->bindMount(sourceDir, targetDir); - } - binder::Status setIncFsMountOptions( - const ::android::os::incremental::IncrementalFileSystemControlParcel& control, - bool enableReadLogs) const final { - return mInterface->setIncFsMountOptions(control, enableReadLogs); - } - -private: - sp<os::IVold> mInterface; -}; - -class RealDataLoaderManager : public DataLoaderManagerWrapper { -public: - RealDataLoaderManager(const sp<content::pm::IDataLoaderManager> manager) - : mInterface(manager) {} - ~RealDataLoaderManager() = default; - binder::Status initializeDataLoader(MountId mountId, const DataLoaderParamsParcel& params, - const FileSystemControlParcel& control, - const sp<IDataLoaderStatusListener>& listener, - bool* _aidl_return) const final { - return mInterface->initializeDataLoader(mountId, params, control, listener, _aidl_return); - } - binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const final { - return mInterface->getDataLoader(mountId, _aidl_return); - } - binder::Status destroyDataLoader(MountId mountId) const final { - return mInterface->destroyDataLoader(mountId); - } - -private: - sp<content::pm::IDataLoaderManager> mInterface; -}; - -class RealAppOpsManager : public AppOpsManagerWrapper { -public: - ~RealAppOpsManager() = default; - binder::Status checkPermission(const char* permission, const char* operation, - const char* package) const final { - return android::incremental::CheckPermissionForDataDelivery(permission, operation, package); - } - void startWatchingMode(int32_t op, const String16& packageName, - const sp<IAppOpsCallback>& callback) final { - mAppOpsManager.startWatchingMode(op, packageName, callback); - } - void stopWatchingMode(const sp<IAppOpsCallback>& callback) final { - mAppOpsManager.stopWatchingMode(callback); - } - -private: - android::AppOpsManager mAppOpsManager; -}; - class RealServiceManager : public ServiceManagerWrapper { public: - RealServiceManager(sp<IServiceManager> serviceManager); + RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env); ~RealServiceManager() = default; std::unique_ptr<VoldServiceWrapper> getVoldService() final; std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final; std::unique_ptr<IncFsWrapper> getIncFs() final; std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final; + std::unique_ptr<JniWrapper> getJni() final; private: template <class INTERFACE> sp<INTERFACE> getRealService(std::string_view serviceName) const; sp<android::IServiceManager> mServiceManager; -}; - -class RealIncFs : public IncFsWrapper { -public: - RealIncFs() = default; - ~RealIncFs() = default; - Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) const final { - return incfs::createControl(cmd, pendingReads, logs); - } - ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId id, - NewFileParams params) const final { - return incfs::makeFile(control, path, mode, id, params); - } - ErrorCode makeDir(const Control& control, std::string_view path, int mode) const final { - return incfs::makeDir(control, path, mode); - } - RawMetadata getMetadata(const Control& control, FileId fileid) const final { - return incfs::getMetadata(control, fileid); - } - RawMetadata getMetadata(const Control& control, std::string_view path) const final { - return incfs::getMetadata(control, path); - } - FileId getFileId(const Control& control, std::string_view path) const final { - return incfs::getFileId(control, path); - } - ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final { - return incfs::link(control, from, to); - } - ErrorCode unlink(const Control& control, std::string_view path) const final { - return incfs::unlink(control, path); - } - base::unique_fd openForSpecialOps(const Control& control, FileId id) const final { - return base::unique_fd{incfs::openForSpecialOps(control, id).release()}; - } - ErrorCode writeBlocks(Span<const DataBlock> blocks) const final { - return incfs::writeBlocks(blocks); - } + JavaVM* const mJvm; }; } // namespace android::os::incremental diff --git a/services/incremental/include/incremental_service.h b/services/incremental/include/incremental_service.h index 4a34b11261b9..321387531694 100644 --- a/services/incremental/include/incremental_service.h +++ b/services/incremental/include/incremental_service.h @@ -24,7 +24,7 @@ __BEGIN_DECLS #define INCREMENTAL_LIBRARY_NAME "service.incremental.so" -jlong Incremental_IncrementalService_Start(); +jlong Incremental_IncrementalService_Start(JNIEnv* env); void Incremental_IncrementalService_OnSystemReady(jlong self); void Incremental_IncrementalService_OnDump(jlong self, jint fd); diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp index 0635ae169281..f9737fee450d 100644 --- a/services/incremental/test/IncrementalServiceTest.cpp +++ b/services/incremental/test/IncrementalServiceTest.cpp @@ -103,25 +103,34 @@ private: TemporaryFile logFile; }; -class FakeDataLoader : public IDataLoader { +class MockDataLoader : public IDataLoader { public: - IBinder* onAsBinder() override { return nullptr; } - binder::Status create(int32_t, const DataLoaderParamsParcel&, const FileSystemControlParcel&, - const sp<IDataLoaderStatusListener>&) override { - return binder::Status::ok(); - } - binder::Status start(int32_t) override { return binder::Status::ok(); } - binder::Status stop(int32_t) override { return binder::Status::ok(); } - binder::Status destroy(int32_t) override { return binder::Status::ok(); } - binder::Status prepareImage(int32_t, - const std::vector<InstallationFileParcel>&, - const std::vector<std::string>&) override { - return binder::Status::ok(); + MockDataLoader() { + ON_CALL(*this, create(_, _, _, _)).WillByDefault(Return((binder::Status::ok()))); + ON_CALL(*this, start(_)).WillByDefault(Return((binder::Status::ok()))); + ON_CALL(*this, stop(_)).WillByDefault(Return((binder::Status::ok()))); + ON_CALL(*this, destroy(_)).WillByDefault(Return((binder::Status::ok()))); + ON_CALL(*this, prepareImage(_, _, _)).WillByDefault(Return((binder::Status::ok()))); } + IBinder* onAsBinder() override { return nullptr; } + MOCK_METHOD4(create, + binder::Status(int32_t id, const DataLoaderParamsParcel& params, + const FileSystemControlParcel& control, + const sp<IDataLoaderStatusListener>& listener)); + MOCK_METHOD1(start, binder::Status(int32_t id)); + MOCK_METHOD1(stop, binder::Status(int32_t id)); + MOCK_METHOD1(destroy, binder::Status(int32_t id)); + MOCK_METHOD3(prepareImage, + binder::Status(int32_t id, const std::vector<InstallationFileParcel>& addedFiles, + const std::vector<std::string>& removedFiles)); }; class MockDataLoaderManager : public DataLoaderManagerWrapper { public: + MockDataLoaderManager(sp<IDataLoader> dataLoader) : mDataLoaderHolder(std::move(dataLoader)) { + EXPECT_TRUE(mDataLoaderHolder != nullptr); + } + MOCK_CONST_METHOD5(initializeDataLoader, binder::Status(int32_t mountId, const DataLoaderParamsParcel& params, const FileSystemControlParcel& control, @@ -131,45 +140,72 @@ public: binder::Status(int32_t mountId, sp<IDataLoader>* _aidl_return)); MOCK_CONST_METHOD1(destroyDataLoader, binder::Status(int32_t mountId)); + void initializeDataLoaderSuccess() { + ON_CALL(*this, initializeDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(this, &MockDataLoaderManager::initializeDataLoaderOk)); + } + void initializeDataLoaderFails() { + ON_CALL(*this, initializeDataLoader(_, _, _, _, _)) + .WillByDefault(Return( + (binder::Status::fromExceptionCode(1, String8("failed to prepare"))))); + } + void getDataLoaderSuccess() { + ON_CALL(*this, getDataLoader(_, _)) + .WillByDefault(Invoke(this, &MockDataLoaderManager::getDataLoaderOk)); + } + void destroyDataLoaderSuccess() { + ON_CALL(*this, destroyDataLoader(_)) + .WillByDefault(Invoke(this, &MockDataLoaderManager::destroyDataLoaderOk)); + } binder::Status initializeDataLoaderOk(int32_t mountId, const DataLoaderParamsParcel& params, const FileSystemControlParcel& control, const sp<IDataLoaderStatusListener>& listener, bool* _aidl_return) { mId = mountId; mListener = listener; + mServiceConnector = control.service; + mDataLoader = mDataLoaderHolder; *_aidl_return = true; - return binder::Status::ok(); + return mDataLoader->create(mountId, params, control, listener); } - binder::Status getDataLoaderOk(int32_t mountId, sp<IDataLoader>* _aidl_return) { *_aidl_return = mDataLoader; return binder::Status::ok(); } - - void initializeDataLoaderFails() { - ON_CALL(*this, initializeDataLoader(_, _, _, _, _)) - .WillByDefault(Return( - (binder::Status::fromExceptionCode(1, String8("failed to prepare"))))); - } - void initializeDataLoaderSuccess() { - ON_CALL(*this, initializeDataLoader(_, _, _, _, _)) - .WillByDefault(Invoke(this, &MockDataLoaderManager::initializeDataLoaderOk)); + void setDataLoaderStatusCreated() { + mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_CREATED); } - void getDataLoaderSuccess() { - ON_CALL(*this, getDataLoader(_, _)) - .WillByDefault(Invoke(this, &MockDataLoaderManager::getDataLoaderOk)); + void setDataLoaderStatusStarted() { + mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_STARTED); } - void setDataLoaderStatusNotReady() { + void setDataLoaderStatusDestroyed() { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); } - void setDataLoaderStatusReady() { - mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_CREATED); + binder::Status destroyDataLoaderOk(int32_t id) { + if (mDataLoader) { + if (auto status = mDataLoader->destroy(id); !status.isOk()) { + return status; + } + mDataLoader = nullptr; + } + if (mListener) { + mListener->onStatusChanged(id, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); + } + return binder::Status::ok(); + } + int32_t setStorageParams(bool enableReadLogs) { + int32_t result = -1; + EXPECT_NE(mServiceConnector.get(), nullptr); + EXPECT_TRUE(mServiceConnector->setStorageParams(enableReadLogs, &result).isOk()); + return result; } private: int mId; sp<IDataLoaderStatusListener> mListener; - sp<IDataLoader> mDataLoader = sp<IDataLoader>(new FakeDataLoader()); + sp<IIncrementalServiceConnector> mServiceConnector; + sp<IDataLoader> mDataLoader; + sp<IDataLoader> mDataLoaderHolder; }; class MockIncFs : public IncFsWrapper { @@ -245,28 +281,39 @@ public: sp<IAppOpsCallback> mStoredCallback; }; +class MockJniWrapper : public JniWrapper { +public: + MOCK_CONST_METHOD0(initializeForCurrentThread, void()); + + MockJniWrapper() { EXPECT_CALL(*this, initializeForCurrentThread()).Times(1); } +}; + class MockServiceManager : public ServiceManagerWrapper { public: MockServiceManager(std::unique_ptr<MockVoldService> vold, - std::unique_ptr<MockDataLoaderManager> manager, + std::unique_ptr<MockDataLoaderManager> dataLoaderManager, std::unique_ptr<MockIncFs> incfs, - std::unique_ptr<MockAppOpsManager> appOpsManager) + std::unique_ptr<MockAppOpsManager> appOpsManager, + std::unique_ptr<MockJniWrapper> jni) : mVold(std::move(vold)), - mDataLoaderManager(std::move(manager)), + mDataLoaderManager(std::move(dataLoaderManager)), mIncFs(std::move(incfs)), - mAppOpsManager(std::move(appOpsManager)) {} + mAppOpsManager(std::move(appOpsManager)), + mJni(std::move(jni)) {} std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); } std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final { return std::move(mDataLoaderManager); } std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); } std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); } + std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); } private: std::unique_ptr<MockVoldService> mVold; std::unique_ptr<MockDataLoaderManager> mDataLoaderManager; std::unique_ptr<MockIncFs> mIncFs; std::unique_ptr<MockAppOpsManager> mAppOpsManager; + std::unique_ptr<MockJniWrapper> mJni; }; // --- IncrementalServiceTest --- @@ -276,20 +323,27 @@ public: void SetUp() override { auto vold = std::make_unique<NiceMock<MockVoldService>>(); mVold = vold.get(); - auto dataloaderManager = std::make_unique<NiceMock<MockDataLoaderManager>>(); + sp<NiceMock<MockDataLoader>> dataLoader{new NiceMock<MockDataLoader>}; + mDataLoader = dataLoader.get(); + auto dataloaderManager = std::make_unique<NiceMock<MockDataLoaderManager>>(dataLoader); mDataLoaderManager = dataloaderManager.get(); auto incFs = std::make_unique<NiceMock<MockIncFs>>(); mIncFs = incFs.get(); auto appOps = std::make_unique<NiceMock<MockAppOpsManager>>(); mAppOpsManager = appOps.get(); + auto jni = std::make_unique<NiceMock<MockJniWrapper>>(); + mJni = jni.get(); mIncrementalService = std::make_unique<IncrementalService>(MockServiceManager(std::move(vold), - std::move(dataloaderManager), + std::move( + dataloaderManager), std::move(incFs), - std::move(appOps)), + std::move(appOps), + std::move(jni)), mRootDir.path); mDataLoaderParcel.packageName = "com.test"; mDataLoaderParcel.arguments = "uri"; + mDataLoaderManager->destroyDataLoaderSuccess(); mIncrementalService->onSystemReady(); } @@ -319,6 +373,8 @@ protected: NiceMock<MockIncFs>* mIncFs; NiceMock<MockDataLoaderManager>* mDataLoaderManager; NiceMock<MockAppOpsManager>* mAppOpsManager; + NiceMock<MockJniWrapper>* mJni; + NiceMock<MockDataLoader>* mDataLoader; std::unique_ptr<IncrementalService> mIncrementalService; TemporaryDir mRootDir; DataLoaderParamsParcel mDataLoaderParcel; @@ -337,6 +393,7 @@ TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsFails) { TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsInvalidControlParcel) { mVold->mountIncFsInvalidControlParcel(); EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(0); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(0); TemporaryDir tempDir; int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, @@ -348,7 +405,7 @@ TEST_F(IncrementalServiceTest, testCreateStorageMakeFileFails) { mVold->mountIncFsSuccess(); mIncFs->makeFileFails(); EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(0); - EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(0); EXPECT_CALL(*mVold, unmountIncFs(_)); TemporaryDir tempDir; int storageId = @@ -362,7 +419,7 @@ TEST_F(IncrementalServiceTest, testCreateStorageBindMountFails) { mIncFs->makeFileSuccess(); mVold->bindMountFails(); EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(0); - EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(0); EXPECT_CALL(*mVold, unmountIncFs(_)); TemporaryDir tempDir; int storageId = @@ -376,7 +433,11 @@ TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) { mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderFails(); - EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(1); + EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(0); + EXPECT_CALL(*mDataLoader, start(_)).Times(0); + EXPECT_CALL(*mDataLoader, destroy(_)).Times(0); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; int storageId = @@ -390,46 +451,84 @@ TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) { mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); - EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(1); + EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1); + EXPECT_CALL(*mDataLoader, start(_)).Times(0); + EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); + mDataLoaderManager->setDataLoaderStatusCreated(); mIncrementalService->deleteStorage(storageId); } -TEST_F(IncrementalServiceTest, testOnStatusNotReady) { +TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) { mVold->mountIncFsSuccess(); mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); - EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + mDataLoaderManager->getDataLoaderSuccess(); + EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(2); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(1); + EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(2); + EXPECT_CALL(*mDataLoader, start(_)).Times(0); + EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); - mDataLoaderManager->setDataLoaderStatusNotReady(); + mDataLoaderManager->setDataLoaderStatusCreated(); + // Simulated crash/other connection breakage. + mDataLoaderManager->setDataLoaderStatusDestroyed(); } -TEST_F(IncrementalServiceTest, testStartDataLoaderSuccess) { +TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) { mVold->mountIncFsSuccess(); mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); mDataLoaderManager->getDataLoaderSuccess(); - EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(1); + EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1); + EXPECT_CALL(*mDataLoader, start(_)).Times(1); + EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); + EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); + TemporaryDir tempDir; + int storageId = + mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, + IncrementalService::CreateOptions::CreateNew); + ASSERT_GE(storageId, 0); + mDataLoaderManager->setDataLoaderStatusCreated(); + ASSERT_TRUE(mIncrementalService->startLoading(storageId)); + mDataLoaderManager->setDataLoaderStatusStarted(); +} + +TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) { + mVold->mountIncFsSuccess(); + mIncFs->makeFileSuccess(); + mVold->bindMountSuccess(); + mDataLoaderManager->initializeDataLoaderSuccess(); + mDataLoaderManager->getDataLoaderSuccess(); + EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(1); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(1); + EXPECT_CALL(*mDataLoader, create(_, _, _, _)).Times(1); + EXPECT_CALL(*mDataLoader, start(_)).Times(1); + EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); - mDataLoaderManager->setDataLoaderStatusReady(); ASSERT_TRUE(mIncrementalService->startLoading(storageId)); + mDataLoaderManager->setDataLoaderStatusCreated(); } TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) { @@ -453,7 +552,7 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) { mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); - ASSERT_GE(mIncrementalService->setStorageParams(storageId, true), 0); + ASSERT_GE(mDataLoaderManager->setStorageParams(true), 0); } TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) { @@ -480,7 +579,7 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChang mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); - ASSERT_GE(mIncrementalService->setStorageParams(storageId, true), 0); + ASSERT_GE(mDataLoaderManager->setStorageParams(true), 0); ASSERT_NE(nullptr, mAppOpsManager->mStoredCallback.get()); mAppOpsManager->mStoredCallback->opChanged(0, {}); } @@ -503,7 +602,7 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) { mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); - ASSERT_LT(mIncrementalService->setStorageParams(storageId, true), 0); + ASSERT_LT(mDataLoaderManager->setStorageParams(true), 0); } TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) { @@ -526,7 +625,7 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) { mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, IncrementalService::CreateOptions::CreateNew); ASSERT_GE(storageId, 0); - ASSERT_LT(mIncrementalService->setStorageParams(storageId, true), 0); + ASSERT_LT(mDataLoaderManager->setStorageParams(true), 0); } TEST_F(IncrementalServiceTest, testMakeDirectory) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 2a914ecf4db6..2c3e3df46e7c 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -112,6 +112,7 @@ import com.android.server.inputmethod.InputMethodSystemProperty; import com.android.server.inputmethod.MultiClientInputMethodManagerService; import com.android.server.integrity.AppIntegrityManagerService; import com.android.server.lights.LightsService; +import com.android.server.location.LocationManagerService; import com.android.server.media.MediaResourceMonitorService; import com.android.server.media.MediaRouterService; import com.android.server.media.MediaSessionService; @@ -136,6 +137,7 @@ import com.android.server.pm.OtaDexoptService; import com.android.server.pm.PackageManagerService; import com.android.server.pm.ShortcutService; import com.android.server.pm.UserManagerService; +import com.android.server.pm.dex.SystemServerDexLoadReporter; import com.android.server.policy.PermissionPolicyService; import com.android.server.policy.PhoneWindowManager; import com.android.server.policy.role.LegacyRoleResolutionPolicy; @@ -519,10 +521,8 @@ public final class SystemServer { // Initialize native services. System.loadLibrary("android_servers"); - // Debug builds - allow heap profiling. - if (Build.IS_DEBUGGABLE) { - initZygoteChildHeapProfiling(); - } + // Allow heap / perf profiling. + initZygoteChildHeapProfiling(); // Debug builds - spawn a thread to monitor for fd leaks. if (Build.IS_DEBUGGABLE) { @@ -839,6 +839,11 @@ public final class SystemServer { Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain"); } + // Now that the package manager has started, register the dex load reporter to capture any + // dex files loaded by system server. + // These dex files will be optimized by the BackgroundDexOptService. + SystemServerDexLoadReporter.configureSystemServerDexReporter(mPackageManagerService); + mFirstBoot = mPackageManagerService.isFirstBoot(); mPackageManager = mSystemContext.getPackageManager(); t.traceEnd(); diff --git a/services/net/Android.bp b/services/net/Android.bp index c54102fb1d3d..9f2979906d42 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -12,8 +12,8 @@ java_library_static { ":services.net-sources", ], static_libs: [ - "dnsresolver_aidl_interface-V2-java", - "netd_aidl_interface-unstable-java", + "dnsresolver_aidl_interface-V4-java", + "netd_aidl_interface-V3-java", "netlink-client", "networkstack-client", "net-utils-services-common", @@ -44,7 +44,7 @@ java_library { ], static_libs: [ "dnsresolver_aidl_interface-V2-java", - "netd_aidl_interface-unstable-java", + "netd_aidl_interface-V3-java", "netlink-client", "networkstack-client", "net-utils-services-common", diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java index 138f9829c088..f8d197acf883 100644 --- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java +++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java @@ -199,6 +199,12 @@ public class CrossProfileAppsServiceImplRoboTest { CROSS_PROFILE_APP_PACKAGE_NAME, PERSONAL_PROFILE_UID, PERSONAL_PROFILE_USER_ID); ShadowApplicationPackageManager.setPackageUidAsUser( CROSS_PROFILE_APP_PACKAGE_NAME, WORK_PROFILE_UID, WORK_PROFILE_USER_ID); + when(mPackageManagerInternal.getPackageUidInternal( + CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, PERSONAL_PROFILE_USER_ID)) + .thenReturn(PERSONAL_PROFILE_UID); + when(mPackageManagerInternal.getPackageUidInternal( + CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, WORK_PROFILE_USER_ID)) + .thenReturn(WORK_PROFILE_UID); } @Before @@ -456,6 +462,19 @@ public class CrossProfileAppsServiceImplRoboTest { } @Test + public void canUserAttemptToConfigureInteractAcrossProfiles_platformSignedAppWithAutomaticPermission_returnsFalse() { + mockCrossProfileAppNotWhitelistedByOem(); + shadowOf(mContext).grantPermissions( + Process.myPid(), + PERSONAL_PROFILE_UID, + Manifest.permission.INTERACT_ACROSS_PROFILES); + + assertThat(mCrossProfileAppsServiceImpl + .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) + .isFalse(); + } + + @Test public void canUserAttemptToConfigureInteractAcrossProfiles_returnsTrue() { assertThat(mCrossProfileAppsServiceImpl .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME)) @@ -528,6 +547,11 @@ public class CrossProfileAppsServiceImplRoboTest { .thenReturn(new ArrayList<>()); } + private void mockCrossProfileAppNotWhitelistedByOem() { + when(mDevicePolicyManagerInternal.getDefaultCrossProfilePackages()) + .thenReturn(new ArrayList<>()); + } + private boolean receivedManifestCanInteractAcrossProfilesChangedBroadcast() { final UserHandle userHandle = UserHandle.of(PERSONAL_PROFILE_USER_ID); if (!mSentUserBroadcasts.containsKey(userHandle)) { diff --git a/services/systemcaptions/java/com/android/server/systemcaptions/RemoteSystemCaptionsManagerService.java b/services/systemcaptions/java/com/android/server/systemcaptions/RemoteSystemCaptionsManagerService.java index c225d3feb063..1aab6722dfee 100644 --- a/services/systemcaptions/java/com/android/server/systemcaptions/RemoteSystemCaptionsManagerService.java +++ b/services/systemcaptions/java/com/android/server/systemcaptions/RemoteSystemCaptionsManagerService.java @@ -16,6 +16,8 @@ package com.android.server.systemcaptions; +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; @@ -37,6 +39,8 @@ final class RemoteSystemCaptionsManagerService { private static final String SERVICE_INTERFACE = "android.service.systemcaptions.SystemCaptionsManagerService"; + private static final int MSG_BIND = 1; + private final Object mLock = new Object(); private final Context mContext; @@ -71,18 +75,26 @@ final class RemoteSystemCaptionsManagerService { if (mVerbose) { Slog.v(TAG, "initialize()"); } - ensureBound(); + scheduleBind(); + } + + /** + * Destroys this service. + */ + public void destroy() { + mHandler.sendMessage( + obtainMessage(RemoteSystemCaptionsManagerService::handleDestroy, this)); } - void destroy() { + void handleDestroy() { if (mVerbose) { - Slog.v(TAG, "destroy()"); + Slog.v(TAG, "handleDestroy()"); } synchronized (mLock) { if (mDestroyed) { if (mVerbose) { - Slog.v(TAG, "destroy(): Already destroyed"); + Slog.v(TAG, "handleDestroy(): Already destroyed"); } return; } @@ -97,14 +109,24 @@ final class RemoteSystemCaptionsManagerService { } } - private void ensureBound() { + private void scheduleBind() { + if (mHandler.hasMessages(MSG_BIND)) { + if (mVerbose) Slog.v(TAG, "scheduleBind(): already scheduled"); + return; + } + mHandler.sendMessage( + obtainMessage(RemoteSystemCaptionsManagerService::handleEnsureBound, this) + .setWhat(MSG_BIND)); + } + + private void handleEnsureBound() { synchronized (mLock) { if (mService != null || mBinding) { return; } if (mVerbose) { - Slog.v(TAG, "ensureBound(): binding"); + Slog.v(TAG, "handleEnsureBound(): binding"); } mBinding = true; diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java index f4d7b8bd5b1a..d338b587e059 100644 --- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java @@ -382,6 +382,7 @@ public class BlobStoreManagerServiceTest { doReturn(hasLeases).when(blobMetadata).hasLeases(); doReturn(blobHandle).when(blobMetadata).getBlobHandle(); doCallRealMethod().when(blobMetadata).shouldBeDeleted(anyBoolean()); + doReturn(true).when(blobMetadata).hasLeaseWaitTimeElapsedForAll(); return blobMetadata; } diff --git a/services/tests/servicestests/res/raw/comp_policies_primary.xml b/services/tests/servicestests/res/raw/comp_policies_primary.xml index d30f479195e3..395b8ab4ba75 100644 --- a/services/tests/servicestests/res/raw/comp_policies_primary.xml +++ b/services/tests/servicestests/res/raw/comp_policies_primary.xml @@ -3,6 +3,11 @@ <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"> <policies flags="991"/> <password-history-length value="33" /> + <require_auto_time value="true" /> <user-restrictions no_bluetooth="true" /> + <disable-screen-capture value="true" /> + <disable-account-management> + <account-type value="com.google-primary" /> + </disable-account-management> </admin> </policies> diff --git a/services/tests/servicestests/res/raw/comp_policies_profile_same_package.xml b/services/tests/servicestests/res/raw/comp_policies_profile_same_package.xml index c874dcca2c73..c65d05693f10 100644 --- a/services/tests/servicestests/res/raw/comp_policies_profile_same_package.xml +++ b/services/tests/servicestests/res/raw/comp_policies_profile_same_package.xml @@ -2,5 +2,8 @@ <policies setup-complete="true" provisioning-state="3"> <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"> <policies flags="991"/> + <disable-account-management> + <account-type value="com.google-profile" /> + </disable-account-management> </admin> </policies> diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java index de2addffa2c5..74e7f8c44d1a 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -19,6 +19,7 @@ import static android.os.UserHandle.USER_SYSTEM; import static com.android.server.devicepolicy.DpmTestUtils.writeInputStreamToFile; +import static org.junit.Assert.assertArrayEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; @@ -378,6 +379,15 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { 33, dpm.getParentProfileInstance(admin1).getPasswordHistoryLength(admin1)); assertEquals("Password history policy was put into non-parent PO instance", 0, dpm.getPasswordHistoryLength(admin1)); + assertTrue("Screen capture restriction wasn't migrated to PO parent instance", + dpm.getParentProfileInstance(admin1).getScreenCaptureDisabled(admin1)); + + assertArrayEquals("Accounts with management disabled weren't migrated to PO parent", + new String[] {"com.google-primary"}, + dpm.getParentProfileInstance(admin1).getAccountTypesWithManagementDisabled()); + assertArrayEquals("Accounts with management disabled for profile were lost", + new String[] {"com.google-profile"}, + dpm.getAccountTypesWithManagementDisabled()); assertTrue("User restriction wasn't migrated to PO parent instance", dpm.getParentProfileInstance(admin1).getUserRestrictions(admin1) @@ -385,7 +395,15 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { assertFalse("User restriction was put into non-parent PO instance", dpm.getUserRestrictions(admin1).containsKey(UserManager.DISALLOW_BLUETOOTH)); - // TODO(b/143516163): verify more policies. + assertTrue("User restriction wasn't migrated to PO parent instance", + dpms.getProfileOwnerAdminLocked(COPE_PROFILE_USER_ID) + .getParentActiveAdmin() + .getEffectiveRestrictions() + .containsKey(UserManager.DISALLOW_CONFIG_DATE_TIME)); + assertFalse("User restriction was put into non-parent PO instance", + dpms.getProfileOwnerAdminLocked(COPE_PROFILE_USER_ID) + .getEffectiveRestrictions() + .containsKey(UserManager.DISALLOW_CONFIG_DATE_TIME)); }); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index d780370b9849..fe224ce058f4 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -2032,13 +2032,17 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(false)); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(UserManager.DISALLOW_CAMERA), - parentDpm.getUserRestrictions(admin1) + dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) + .getParentActiveAdmin() + .getEffectiveRestrictions() ); parentDpm.setCameraDisabled(admin1, false); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(), - parentDpm.getUserRestrictions(admin1) + dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) + .getParentActiveAdmin() + .getEffectiveRestrictions() ); reset(getServices().userManagerInternal); } @@ -2053,7 +2057,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { parentDpm.clearUserRestriction(admin1, restriction); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(), - parentDpm.getUserRestrictions(admin1) + dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) + .getParentActiveAdmin() + .getEffectiveRestrictions() ); } @@ -2088,11 +2094,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { private void assertNoDeviceOwnerRestrictions() { DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(), - getDeviceOwner().ensureUserRestrictions() - ); - DpmTestUtils.assertRestrictions( - DpmTestUtils.newRestrictions(), - dpm.getUserRestrictions(admin1) + getDeviceOwner().getEffectiveRestrictions() ); } diff --git a/services/tests/servicestests/src/com/android/server/display/color/AppSaturationControllerTest.java b/services/tests/servicestests/src/com/android/server/display/color/AppSaturationControllerTest.java index 7c9a81d2e094..a525814435ea 100644 --- a/services/tests/servicestests/src/com/android/server/display/color/AppSaturationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/color/AppSaturationControllerTest.java @@ -43,7 +43,9 @@ import java.lang.ref.WeakReference; @RunWith(AndroidJUnit4.class) public class AppSaturationControllerTest { - private static final String TEST_PACKAGE_NAME = "com.android.test"; + private static final String TEST_CALLER_PACKAGE_NAME = "com.android.test.caller"; + private static final String TEST_CALLER_PACKAGE_NAME_TWO = "com.android.test.caller.two"; + private static final String TEST_AFFECTED_PACKAGE_NAME = "com.android.test.affected"; private int mUserId; private AppSaturationController mAppSaturationController; @@ -70,8 +72,11 @@ public class AppSaturationControllerTest { public void addColorTransformController_appliesExistingSaturation() { final WeakReference<ColorTransformController> ref = new WeakReference<>( mColorTransformController); - mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 30); - mAppSaturationController.addColorTransformController(TEST_PACKAGE_NAME, mUserId, ref); + mAppSaturationController + .setSaturationLevel(TEST_CALLER_PACKAGE_NAME, TEST_AFFECTED_PACKAGE_NAME, mUserId, + 30); + mAppSaturationController + .addColorTransformController(TEST_AFFECTED_PACKAGE_NAME, mUserId, ref); AppSaturationController.computeGrayscaleTransformMatrix(.3f, mMatrix); verify(mColorTransformController).applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR)); } @@ -80,14 +85,19 @@ public class AppSaturationControllerTest { public void setSaturationLevel_resetToDefault() { final WeakReference<ColorTransformController> ref = new WeakReference<>( mColorTransformController); - mAppSaturationController.addColorTransformController(TEST_PACKAGE_NAME, mUserId, ref); + mAppSaturationController + .addColorTransformController(TEST_AFFECTED_PACKAGE_NAME, mUserId, ref); verify(mColorTransformController, never()) .applyAppSaturation(any(), eq(TRANSLATION_VECTOR)); - mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 30); + mAppSaturationController + .setSaturationLevel(TEST_CALLER_PACKAGE_NAME, TEST_AFFECTED_PACKAGE_NAME, mUserId, + 30); AppSaturationController.computeGrayscaleTransformMatrix(.3f, mMatrix); verify(mColorTransformController, times(1)) .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR)); - mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 100); + mAppSaturationController + .setSaturationLevel(TEST_CALLER_PACKAGE_NAME, TEST_AFFECTED_PACKAGE_NAME, mUserId, + 100); AppSaturationController.computeGrayscaleTransformMatrix(1.0f, mMatrix); verify(mColorTransformController, times(2)) .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR)); @@ -97,19 +107,76 @@ public class AppSaturationControllerTest { public void setSaturationLevel_updateLevel() { final WeakReference<ColorTransformController> ref = new WeakReference<>( mColorTransformController); - mAppSaturationController.addColorTransformController(TEST_PACKAGE_NAME, mUserId, ref); + mAppSaturationController + .addColorTransformController(TEST_AFFECTED_PACKAGE_NAME, mUserId, ref); verify(mColorTransformController, never()) .applyAppSaturation(any(), eq(TRANSLATION_VECTOR)); - mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 30); + mAppSaturationController + .setSaturationLevel(TEST_CALLER_PACKAGE_NAME, TEST_AFFECTED_PACKAGE_NAME, mUserId, + 30); AppSaturationController.computeGrayscaleTransformMatrix(.3f, mMatrix); verify(mColorTransformController).applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR)); - mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 70); + mAppSaturationController + .setSaturationLevel(TEST_CALLER_PACKAGE_NAME, TEST_AFFECTED_PACKAGE_NAME, mUserId, + 70); AppSaturationController.computeGrayscaleTransformMatrix(.7f, mMatrix); verify(mColorTransformController, times(2)) .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR)); - mAppSaturationController.setSaturationLevel(TEST_PACKAGE_NAME, mUserId, 100); + mAppSaturationController + .setSaturationLevel(TEST_CALLER_PACKAGE_NAME, TEST_AFFECTED_PACKAGE_NAME, mUserId, + 100); AppSaturationController.computeGrayscaleTransformMatrix(1.0f, mMatrix); verify(mColorTransformController, times(3)) .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR)); } + + @Test + public void setSaturationLevel_multipleCallers_appliesStrongest() { + final WeakReference<ColorTransformController> ref = new WeakReference<>( + mColorTransformController); + mAppSaturationController + .addColorTransformController(TEST_AFFECTED_PACKAGE_NAME, mUserId, ref); + verify(mColorTransformController, never()) + .applyAppSaturation(any(), eq(TRANSLATION_VECTOR)); + mAppSaturationController + .setSaturationLevel(TEST_CALLER_PACKAGE_NAME, TEST_AFFECTED_PACKAGE_NAME, mUserId, + 30); + AppSaturationController.computeGrayscaleTransformMatrix(0.3f, mMatrix); + verify(mColorTransformController, times(1)) + .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR)); + mAppSaturationController + .setSaturationLevel(TEST_CALLER_PACKAGE_NAME_TWO, TEST_AFFECTED_PACKAGE_NAME, + mUserId, + 70); + verify(mColorTransformController, times(2)) + .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR)); + } + + @Test + public void setSaturationLevel_multipleCallers_removingOneDoesNotAffectTheOther() { + final WeakReference<ColorTransformController> ref = new WeakReference<>( + mColorTransformController); + mAppSaturationController + .addColorTransformController(TEST_AFFECTED_PACKAGE_NAME, mUserId, ref); + verify(mColorTransformController, never()) + .applyAppSaturation(any(), eq(TRANSLATION_VECTOR)); + mAppSaturationController + .setSaturationLevel(TEST_CALLER_PACKAGE_NAME, TEST_AFFECTED_PACKAGE_NAME, mUserId, + 70); + AppSaturationController.computeGrayscaleTransformMatrix(0.7f, mMatrix); + verify(mColorTransformController, times(1)) + .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR)); + mAppSaturationController + .setSaturationLevel(TEST_CALLER_PACKAGE_NAME_TWO, TEST_AFFECTED_PACKAGE_NAME, + mUserId, + 30); + AppSaturationController.computeGrayscaleTransformMatrix(0.3f, mMatrix); + verify(mColorTransformController, times(2)) + .applyAppSaturation(eq(mMatrix), eq(TRANSLATION_VECTOR)); + mAppSaturationController + .setSaturationLevel(TEST_CALLER_PACKAGE_NAME_TWO, TEST_AFFECTED_PACKAGE_NAME, + mUserId, + 100); + AppSaturationController.computeGrayscaleTransformMatrix(0.7f, mMatrix); + } } diff --git a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java index ccbaee41af7c..aa923e22444d 100644 --- a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java @@ -63,6 +63,16 @@ public class LightsServiceTest { fakeHwLight(105, LightsManager.LIGHT_TYPE_MICROPHONE, 2) }; } + + @Override + public int getInterfaceVersion() { + return this.VERSION; + } + + @Override + public String getInterfaceHash() { + return this.HASH; + } }; private static HwLight fakeHwLight(int id, int type, int ordinal) { diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java index 820e61cb0a08..9eda718ed922 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java @@ -377,8 +377,7 @@ class OverlayManagerServiceImplTestsBase { return false; } final String key = createKey(overlayPackage.packageName, userId); - mIdmapFiles.add(key); - return true; + return mIdmapFiles.add(key); } @Override diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index b60e99363706..f205fde88c0d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -117,6 +117,16 @@ public class AppsFilterTest { } private static ParsingPackage pkg(String packageName, IntentFilter... filters) { + ParsedActivity activity = createActivity(packageName, filters); + return pkg(packageName).addActivity(activity); + } + + private static ParsingPackage pkgWithReceiver(String packageName, IntentFilter... filters) { + ParsedActivity receiver = createActivity(packageName, filters); + return pkg(packageName).addReceiver(receiver); + } + + private static ParsedActivity createActivity(String packageName, IntentFilter[] filters) { ParsedActivity activity = new ParsedActivity(); activity.setPackageName(packageName); for (IntentFilter filter : filters) { @@ -136,9 +146,7 @@ public class AppsFilterTest { activity.addIntent(info); activity.setExported(true); } - - return pkg(packageName) - .addActivity(activity); + return activity; } private static ParsingPackage pkgWithInstrumentation( @@ -176,9 +184,10 @@ public class AppsFilterTest { } @Test - public void testQueriesAction_FilterMatches() { + public void testQueriesAction_FilterMatches() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -190,9 +199,46 @@ public class AppsFilterTest { } @Test - public void testQueriesProvider_FilterMatches() { + public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception { + final AppsFilter appsFilter = + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + final Signature frameworkSignature = Mockito.mock(Signature.class); + final PackageParser.SigningDetails frameworkSigningDetails = + new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1); + final ParsingPackage android = pkg("android"); + android.addProtectedBroadcast("TEST_ACTION"); + simulateAddPackage(appsFilter, android, 1000, + b -> b.setSigningDetails(frameworkSigningDetails)); + appsFilter.onSystemReady(); + + final int activityUid = DUMMY_TARGET_UID; + PackageSetting targetActivity = simulateAddPackage(appsFilter, + pkg("com.target.activity", new IntentFilter("TEST_ACTION")), activityUid); + final int receiverUid = DUMMY_TARGET_UID + 1; + PackageSetting targetReceiver = simulateAddPackage(appsFilter, + pkgWithReceiver("com.target.receiver", new IntentFilter("TEST_ACTION")), + receiverUid); + final int callingUid = DUMMY_CALLING_UID; + PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.calling.action", new Intent("TEST_ACTION")), callingUid); + final int wildcardUid = DUMMY_CALLING_UID + 1; + PackageSetting callingWildCard = simulateAddPackage(appsFilter, + pkg("com.calling.wildcard", new Intent("*")), wildcardUid); + + assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity, 0)); + assertTrue(appsFilter.shouldFilterApplication(callingUid, calling, targetReceiver, 0)); + + assertFalse(appsFilter.shouldFilterApplication( + wildcardUid, callingWildCard, targetActivity, 0)); + assertTrue(appsFilter.shouldFilterApplication( + wildcardUid, callingWildCard, targetReceiver, 0)); + } + + @Test + public void testQueriesProvider_FilterMatches() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -205,9 +251,10 @@ public class AppsFilterTest { } @Test - public void testQueriesDifferentProvider_Filters() { + public void testQueriesDifferentProvider_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -220,9 +267,10 @@ public class AppsFilterTest { } @Test - public void testQueriesProviderWithSemiColon_FilterMatches() { + public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -236,9 +284,10 @@ public class AppsFilterTest { } @Test - public void testQueriesAction_NoMatchingAction_Filters() { + public void testQueriesAction_NoMatchingAction_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -250,9 +299,10 @@ public class AppsFilterTest { } @Test - public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() { + public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -269,9 +319,10 @@ public class AppsFilterTest { } @Test - public void testNoQueries_Filters() { + public void testNoQueries_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -283,9 +334,10 @@ public class AppsFilterTest { } @Test - public void testForceQueryable_DoesntFilter() { + public void testForceQueryable_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -297,9 +349,10 @@ public class AppsFilterTest { } @Test - public void testForceQueryableByDevice_SystemCaller_DoesntFilter() { + public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -340,9 +393,10 @@ public class AppsFilterTest { } @Test - public void testForceQueryableByDevice_NonSystemCaller_Filters() { + public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -355,10 +409,11 @@ public class AppsFilterTest { @Test - public void testSystemQueryable_DoesntFilter() { + public void testSystemQueryable_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, true /* system force queryable */, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -371,9 +426,10 @@ public class AppsFilterTest { } @Test - public void testQueriesPackage_DoesntFilter() { + public void testQueriesPackage_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -385,11 +441,12 @@ public class AppsFilterTest { } @Test - public void testNoQueries_FeatureOff_DoesntFilter() { + public void testNoQueries_FeatureOff_DoesntFilter() throws Exception { when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) .thenReturn(false); final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage( @@ -401,9 +458,10 @@ public class AppsFilterTest { } @Test - public void testSystemUid_DoesntFilter() { + public void testSystemUid_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -415,9 +473,10 @@ public class AppsFilterTest { } @Test - public void testNonSystemUid_NoCallingSetting_Filters() { + public void testNonSystemUid_NoCallingSetting_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, @@ -427,9 +486,10 @@ public class AppsFilterTest { } @Test - public void testNoTargetPackage_filters() { + public void testNoTargetPackage_filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = new PackageSettingBuilder() @@ -445,7 +505,7 @@ public class AppsFilterTest { } @Test - public void testActsOnTargetOfOverlay() { + public void testActsOnTargetOfOverlay() throws Exception { final String actorName = "overlay://test/actorName"; ParsingPackage target = pkg("com.some.package.target") @@ -481,6 +541,7 @@ public class AppsFilterTest { return Collections.emptyMap(); } }); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID); @@ -507,7 +568,7 @@ public class AppsFilterTest { } @Test - public void testActsOnTargetOfOverlayThroughSharedUser() { + public void testActsOnTargetOfOverlayThroughSharedUser() throws Exception { final String actorName = "overlay://test/actorName"; ParsingPackage target = pkg("com.some.package.target") @@ -545,6 +606,7 @@ public class AppsFilterTest { return Collections.emptyMap(); } }); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID); @@ -566,9 +628,10 @@ public class AppsFilterTest { } @Test - public void testInitiatingApp_DoesntFilter() { + public void testInitiatingApp_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), @@ -580,9 +643,10 @@ public class AppsFilterTest { } @Test - public void testUninstalledInitiatingApp_Filters() { + public void testUninstalledInitiatingApp_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), @@ -594,9 +658,10 @@ public class AppsFilterTest { } @Test - public void testOriginatingApp_Filters() { + public void testOriginatingApp_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), @@ -608,9 +673,10 @@ public class AppsFilterTest { } @Test - public void testInstallingApp_DoesntFilter() { + public void testInstallingApp_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), @@ -622,9 +688,10 @@ public class AppsFilterTest { } @Test - public void testInstrumentation_DoesntFilter() { + public void testInstrumentation_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -644,6 +711,7 @@ public class AppsFilterTest { public void testWhoCanSee() throws Exception { final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); final int systemAppId = Process.FIRST_APPLICATION_UID - 1; @@ -700,6 +768,15 @@ public class AppsFilterTest { PackageSettingBuilder withBuilder(PackageSettingBuilder builder); } + private void simulateAddBasicAndroid(AppsFilter appsFilter) throws Exception { + final Signature frameworkSignature = Mockito.mock(Signature.class); + final PackageParser.SigningDetails frameworkSigningDetails = + new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1); + final ParsingPackage android = pkg("android"); + simulateAddPackage(appsFilter, android, 1000, + b -> b.setSigningDetails(frameworkSigningDetails)); + } + private PackageSetting simulateAddPackage(AppsFilter filter, ParsingPackage newPkgBuilder, int appId) { return simulateAddPackage(filter, newPkgBuilder, appId, null); diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java index d69e1b8786b4..8398585ca74a 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java @@ -85,6 +85,9 @@ public class DexManagerTests { private TestData mBarUser0UnsupportedClassLoader; private TestData mBarUser0DelegateLastClassLoader; + private TestData mSystemServerJar; + private TestData mSystemServerJarInvalid; + private int mUser0; private int mUser1; @@ -108,6 +111,9 @@ public class DexManagerTests { mBarUser0DelegateLastClassLoader = new TestData(bar, isa, mUser0, DELEGATE_LAST_CLASS_LOADER_NAME); + mSystemServerJar = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME); + mSystemServerJarInvalid = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME); + mDexManager = new DexManager(/*Context*/ null, mPM, /*PackageDexOptimizer*/ null, mInstaller, mInstallLock); @@ -587,6 +593,25 @@ public class DexManagerTests { assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries); } + + @Test + public void testNotifySystemServerUse() { + List<String> dexFiles = new ArrayList<String>(); + dexFiles.add("/system/framework/foo"); + notifyDexLoad(mSystemServerJar, dexFiles, mUser0); + PackageUseInfo pui = getPackageUseInfo(mSystemServerJar); + assertIsUsedByOtherApps(mSystemServerJar, pui, false); + } + + @Test + public void testNotifySystemServerInvalidUse() { + List<String> dexFiles = new ArrayList<String>(); + dexFiles.add("/data/foo"); + notifyDexLoad(mSystemServerJarInvalid, dexFiles, mUser0); + assertNoUseInfo(mSystemServerJarInvalid); + assertNoDclInfo(mSystemServerJarInvalid); + } + private void assertSecondaryUse(TestData testData, PackageUseInfo pui, List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId, String[] expectedContexts) { diff --git a/services/tests/servicestests/src/com/android/server/stats/pull/SettingsStatsUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/pull/SettingsStatsUtilTest.java new file mode 100644 index 000000000000..cfeadc6893db --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/stats/pull/SettingsStatsUtilTest.java @@ -0,0 +1,109 @@ +/* + * 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.server.stats.pull; + +import static android.os.UserHandle.USER_SYSTEM; + +import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import android.content.Context; +import android.provider.DeviceConfig; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Build/Install/Run: + * atest FrameworksServicesTests:SettingsStatsUtilTest + */ +@RunWith(AndroidJUnit4.class) +public class SettingsStatsUtilTest { + private static final String[] KEYS = new String[]{ + "screen_auto_brightness_adj", + "font_scale" + }; + private static final String ENCODED = "ChpzY3JlZW5fYXV0b19icmlnaHRuZXNzX2FkagoKZm9udF9zY2FsZQ"; + private static final String FLAG = "testflag"; + private Context mContext; + + @Before + public void setUp() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + FLAG, + "", + false /* makeDefault*/); + mContext = InstrumentationRegistry.getInstrumentation().getContext(); + } + + @Test + public void getList_emptyString_nullValue() { + assertNull(SettingsStatsUtil.getList(FLAG)); + } + + @Test + public void getList_notValidString_nullValue() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, FLAG, "abcd", false); + + assertNull(SettingsStatsUtil.getList(FLAG)); + } + + @Test + public void getList_validString_correctValue() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, FLAG, ENCODED, false); + + assertArrayEquals(KEYS, SettingsStatsUtil.getList(FLAG).element); + } + + @Test + public void logGlobalSettings_noWhitelist_correctSize() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__boolean_whitelist", "", false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__integer_whitelist", "", false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__float_whitelist", "", false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__string_whitelist", "", false); + + assertEquals(0, SettingsStatsUtil.logGlobalSettings(mContext, SETTING_SNAPSHOT, + USER_SYSTEM).size()); + } + + @Test + public void logGlobalSettings_correctSize() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__boolean_whitelist", ENCODED, false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__integer_whitelist", ENCODED, false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__float_whitelist", ENCODED, false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__string_whitelist", ENCODED, false); + + assertEquals(KEYS.length * 4, + SettingsStatsUtil.logGlobalSettings(mContext, SETTING_SNAPSHOT, + USER_SYSTEM).size()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/textclassifier/IconsContentProviderTest.java b/services/tests/servicestests/src/com/android/server/textclassifier/IconsContentProviderTest.java new file mode 100644 index 000000000000..72580a3b98c2 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/textclassifier/IconsContentProviderTest.java @@ -0,0 +1,70 @@ +/* + * 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.server.textclassifier; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; +import android.net.Uri; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Sanity test for {@link IconsContentProvider}. + */ +@RunWith(AndroidJUnit4.class) +public final class IconsContentProviderTest { + + @Test + public void testLoadResource() { + final Context context = ApplicationProvider.getApplicationContext(); + // Testing with the android package name because this is the only package name + // that returns the same uri across multiple classloaders. + final String packageName = "android"; + final int resId = android.R.drawable.btn_star; + final Uri uri = IconsUriHelper.getInstance().getContentUri(packageName, resId); + + final Drawable expected = Icon.createWithResource(packageName, resId).loadDrawable(context); + // Ensure we are testing with a non-empty image. + assertThat(expected.getIntrinsicWidth()).isGreaterThan(0); + assertThat(expected.getIntrinsicHeight()).isGreaterThan(0); + + final Drawable actual = Icon.createWithContentUri(uri).loadDrawable(context); + assertThat(actual).isNotNull(); + assertThat(IconsContentProvider.getBitmapData(actual)) + .isEqualTo(IconsContentProvider.getBitmapData(expected)); + } + + @Test + public void testLoadResource_badUri() { + final Uri badUri = new Uri.Builder() + .scheme("content") + .authority(IconsUriHelper.AUTHORITY) + .path("badPackageId") + .appendPath("1234") + .build(); + + final Context context = ApplicationProvider.getApplicationContext(); + assertThat(Icon.createWithContentUri(badUri).loadDrawable(context)).isNull(); + } +} + diff --git a/services/tests/servicestests/src/com/android/server/textclassifier/IconsUriHelperTest.java b/services/tests/servicestests/src/com/android/server/textclassifier/IconsUriHelperTest.java new file mode 100644 index 000000000000..96f09d965b13 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/textclassifier/IconsUriHelperTest.java @@ -0,0 +1,134 @@ +/* + * 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.server.textclassifier; + +import static com.google.common.truth.Truth.assertThat; + +import android.net.Uri; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.textclassifier.IconsUriHelper.ResourceInfo; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link IconsUriHelper}. + */ +@RunWith(AndroidJUnit4.class) +public final class IconsUriHelperTest { + + private IconsUriHelper mIconsUriHelper; + + @Before + public void setUp() { + mIconsUriHelper = IconsUriHelper.newInstanceForTesting(null); + } + + @Test + public void testGetContentUri() { + final IconsUriHelper iconsUriHelper = IconsUriHelper.newInstanceForTesting(() -> "pkgId"); + final Uri expected = new Uri.Builder() + .scheme("content") + .authority(IconsUriHelper.AUTHORITY) + .path("pkgId") + .appendPath("1234") + .build(); + + final Uri actual = iconsUriHelper.getContentUri("com.package.name", 1234); + assertThat(actual).isEqualTo(expected); + } + + @Test + public void testGetContentUri_multiplePackages() { + final Uri uri1 = mIconsUriHelper.getContentUri("com.package.name1", 1234); + final Uri uri2 = mIconsUriHelper.getContentUri("com.package.name2", 5678); + + assertThat(uri1.getScheme()).isEqualTo("content"); + assertThat(uri2.getScheme()).isEqualTo("content"); + + assertThat(uri1.getAuthority()).isEqualTo(IconsUriHelper.AUTHORITY); + assertThat(uri2.getAuthority()).isEqualTo(IconsUriHelper.AUTHORITY); + + assertThat(uri1.getPathSegments().get(1)).isEqualTo("1234"); + assertThat(uri2.getPathSegments().get(1)).isEqualTo("5678"); + } + + @Test + public void testGetContentUri_samePackageIdForSamePackageName() { + final String packageName = "com.package.name"; + final Uri uri1 = mIconsUriHelper.getContentUri(packageName, 1234); + final Uri uri2 = mIconsUriHelper.getContentUri(packageName, 5678); + + final String id1 = uri1.getPathSegments().get(0); + final String id2 = uri2.getPathSegments().get(0); + + assertThat(id1).isEqualTo(id2); + } + + @Test + public void testGetResourceInfo() { + mIconsUriHelper.getContentUri("com.package.name1", 123); + final Uri uri = mIconsUriHelper.getContentUri("com.package.name2", 456); + mIconsUriHelper.getContentUri("com.package.name3", 789); + + final ResourceInfo res = mIconsUriHelper.getResourceInfo(uri); + assertThat(res.packageName).isEqualTo("com.package.name2"); + assertThat(res.id).isEqualTo(456); + } + + @Test + public void testGetResourceInfo_unrecognizedUri() { + final Uri uri = new Uri.Builder() + .scheme("content") + .authority(IconsUriHelper.AUTHORITY) + .path("unrecognized") + .appendPath("1234") + .build(); + assertThat(mIconsUriHelper.getResourceInfo(uri)).isNull(); + } + + @Test + public void testGetResourceInfo_invalidScheme() { + final IconsUriHelper iconsUriHelper = IconsUriHelper.newInstanceForTesting(() -> "pkgId"); + iconsUriHelper.getContentUri("com.package.name", 1234); + + final Uri uri = new Uri.Builder() + .scheme("file") + .authority(IconsUriHelper.AUTHORITY) + .path("pkgId") + .appendPath("1234") + .build(); + assertThat(iconsUriHelper.getResourceInfo(uri)).isNull(); + } + + @Test + public void testGetResourceInfo_invalidAuthority() { + final IconsUriHelper iconsUriHelper = IconsUriHelper.newInstanceForTesting(() -> "pkgId"); + iconsUriHelper.getContentUri("com.package.name", 1234); + + final Uri uri = new Uri.Builder() + .scheme("content") + .authority("invalid.authority") + .path("pkgId") + .appendPath("1234") + .build(); + assertThat(iconsUriHelper.getResourceInfo(uri)).isNull(); + } +} + diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index 327cfc74dac5..39062f017a73 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -818,6 +818,69 @@ public class AppStandbyControllerTests { assertBucket(STANDBY_BUCKET_RESTRICTED); } + /** + * Test that an app is "timed out" into the RESTRICTED bucket if prediction tries to put it into + * a low bucket after the RESTRICTED timeout. + */ + @Test + public void testRestrictedTimeoutOverridesRestoredLowBucketPrediction() { + reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); + assertBucket(STANDBY_BUCKET_ACTIVE); + + // Predict to RARE Not long enough to time out into RESTRICTED. + mInjector.mElapsedRealtime += RARE_THRESHOLD; + mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, + REASON_MAIN_PREDICTED); + assertBucket(STANDBY_BUCKET_RARE); + + // Add a short timeout event + mInjector.mElapsedRealtime += 1000; + reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); + assertBucket(STANDBY_BUCKET_ACTIVE); + mInjector.mElapsedRealtime += 1000; + mController.checkIdleStates(USER_ID); + assertBucket(STANDBY_BUCKET_ACTIVE); + + // Long enough that it could have timed out into RESTRICTED. Instead of reverting to + // predicted RARE, should go into RESTRICTED + mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; + mController.checkIdleStates(USER_ID); + assertBucket(STANDBY_BUCKET_RESTRICTED); + + // Ensure that prediction can still raise it out despite this override. + mInjector.mElapsedRealtime += 1; + mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, + REASON_MAIN_PREDICTED); + assertBucket(STANDBY_BUCKET_ACTIVE); + } + + /** + * Test that an app is "timed out" into the RESTRICTED bucket if prediction tries to put it into + * a low bucket after the RESTRICTED timeout. + */ + @Test + public void testRestrictedTimeoutOverridesPredictionLowBucket() { + reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); + + // Not long enough to time out into RESTRICTED. + mInjector.mElapsedRealtime += RARE_THRESHOLD; + mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, + REASON_MAIN_PREDICTED); + assertBucket(STANDBY_BUCKET_RARE); + + mInjector.mElapsedRealtime += 1; + reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); + + // Long enough that it could have timed out into RESTRICTED. + mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4; + mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE, + REASON_MAIN_PREDICTED); + assertBucket(STANDBY_BUCKET_ACTIVE); + mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, + REASON_MAIN_PREDICTED); + assertBucket(STANDBY_BUCKET_RESTRICTED); + } + @Test public void testPredictionRaiseFromRestrictedTimeout_highBucket() { reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1); diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java index 2077ecb2799e..96c69af036b6 100644 --- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java +++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java @@ -197,7 +197,8 @@ public class ShortcutManagerTestUtils { final String PREFIX = "Launcher: ComponentInfo{"; final String POSTFIX = "}"; final List<String> result = runShortcutCommandForSuccess( - instrumentation, "get-default-launcher"); + instrumentation, "get-default-launcher --user " + + instrumentation.getContext().getUserId()); for (String s : result) { if (s.startsWith(PREFIX) && s.endsWith(POSTFIX)) { return s.substring(PREFIX.length(), s.length() - POSTFIX.length()); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BubbleCheckerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BubbleCheckerTest.java deleted file mode 100644 index 2578ca892520..000000000000 --- a/services/tests/uiservicestests/src/com/android/server/notification/BubbleCheckerTest.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.notification; - -import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; -import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; - -import static junit.framework.Assert.assertTrue; - -import static org.junit.Assert.assertFalse; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import android.app.ActivityManager; -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.PendingIntent; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.ShortcutInfo; -import android.os.UserHandle; -import android.service.notification.StatusBarNotification; -import android.test.suitebuilder.annotation.SmallTest; - -import androidx.test.runner.AndroidJUnit4; - -import com.android.server.UiServiceTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@SmallTest -@RunWith(AndroidJUnit4.class) -public class BubbleCheckerTest extends UiServiceTestCase { - - private static final String SHORTCUT_ID = "shortcut"; - private static final String PKG = "pkg"; - private static final String KEY = "key"; - private static final int USER_ID = 1; - - @Mock - ActivityManager mActivityManager; - @Mock - RankingConfig mRankingConfig; - @Mock - ShortcutHelper mShortcutHelper; - - @Mock - NotificationRecord mNr; - @Mock - UserHandle mUserHandle; - @Mock - Notification mNotif; - @Mock - StatusBarNotification mSbn; - @Mock - NotificationChannel mChannel; - @Mock - Notification.BubbleMetadata mBubbleMetadata; - @Mock - PendingIntent mPendingIntent; - @Mock - Intent mIntent; - - BubbleExtractor.BubbleChecker mBubbleChecker; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - when(mNr.getKey()).thenReturn(KEY); - when(mNr.getSbn()).thenReturn(mSbn); - when(mNr.getUser()).thenReturn(mUserHandle); - when(mUserHandle.getIdentifier()).thenReturn(USER_ID); - when(mNr.getChannel()).thenReturn(mChannel); - when(mSbn.getPackageName()).thenReturn(PKG); - when(mSbn.getUser()).thenReturn(mUserHandle); - when(mNr.getNotification()).thenReturn(mNotif); - when(mNotif.getBubbleMetadata()).thenReturn(mBubbleMetadata); - - mBubbleChecker = new BubbleExtractor.BubbleChecker(mContext, - mShortcutHelper, - mRankingConfig, - mActivityManager); - } - - void setUpIntentBubble() { - when(mPendingIntent.getIntent()).thenReturn(mIntent); - when(mBubbleMetadata.getIntent()).thenReturn(mPendingIntent); - when(mBubbleMetadata.getShortcutId()).thenReturn(null); - } - - void setUpShortcutBubble(boolean isValid) { - when(mBubbleMetadata.getShortcutId()).thenReturn(SHORTCUT_ID); - ShortcutInfo info = mock(ShortcutInfo.class); - when(info.getId()).thenReturn(SHORTCUT_ID); - when(mShortcutHelper.getValidShortcutInfo(SHORTCUT_ID, PKG, mUserHandle)) - .thenReturn(isValid ? info : null); - when(mBubbleMetadata.getIntent()).thenReturn(null); - } - - void setUpBubblesEnabled(boolean feature, boolean app, boolean channel) { - when(mRankingConfig.bubblesEnabled()).thenReturn(feature); - when(mRankingConfig.areBubblesAllowed(PKG, USER_ID)).thenReturn(app); - when(mChannel.canBubble()).thenReturn(channel); - } - - void setUpActivityIntent(boolean isResizable) { - when(mPendingIntent.getIntent()).thenReturn(mIntent); - ActivityInfo info = new ActivityInfo(); - info.resizeMode = isResizable - ? RESIZE_MODE_RESIZEABLE - : RESIZE_MODE_UNRESIZEABLE; - when(mIntent.resolveActivityInfo(any(), anyInt())).thenReturn(info); - } - - // - // canBubble - // - - @Test - public void testCanBubble_true_intentBubble() { - setUpBubblesEnabled(true /* feature */, true /* app */, true /* channel */); - setUpIntentBubble(); - setUpActivityIntent(true /* isResizable */); - when(mActivityManager.isLowRamDevice()).thenReturn(false); - assertTrue(mBubbleChecker.canBubble(mNr, PKG, USER_ID)); - } - - @Test - public void testCanBubble_true_shortcutBubble() { - setUpBubblesEnabled(true /* feature */, true /* app */, true /* channel */); - setUpShortcutBubble(true /* isValid */); - assertTrue(mBubbleChecker.canBubble(mNr, PKG, USER_ID)); - } - - @Test - public void testCanBubble_false_noIntentInvalidShortcut() { - setUpBubblesEnabled(true /* feature */, true /* app */, true /* channel */); - setUpShortcutBubble(false /* isValid */); - assertFalse(mBubbleChecker.canBubble(mNr, PKG, USER_ID)); - } - - @Test - public void testCanBubble_false_noIntentNoShortcut() { - setUpBubblesEnabled(true /* feature */, true /* app */, true /* channel */); - when(mBubbleMetadata.getIntent()).thenReturn(null); - when(mBubbleMetadata.getShortcutId()).thenReturn(null); - assertFalse(mBubbleChecker.canBubble(mNr, PKG, USER_ID)); - } - - @Test - public void testCanBubbble_false_noMetadata() { - setUpBubblesEnabled(true/* feature */, true /* app */, true /* channel */); - when(mNotif.getBubbleMetadata()).thenReturn(null); - assertFalse(mBubbleChecker.canBubble(mNr, PKG, USER_ID)); - } - - @Test - public void testCanBubble_false_bubblesNotEnabled() { - setUpBubblesEnabled(false /* feature */, true /* app */, true /* channel */); - assertFalse(mBubbleChecker.canBubble(mNr, PKG, USER_ID)); - } - - @Test - public void testCanBubble_false_packageNotAllowed() { - setUpBubblesEnabled(true /* feature */, false /* app */, true /* channel */); - assertFalse(mBubbleChecker.canBubble(mNr, PKG, USER_ID)); - } - - @Test - public void testCanBubble_false_channelNotAllowed() { - setUpBubblesEnabled(true /* feature */, true /* app */, false /* channel */); - assertFalse(mBubbleChecker.canBubble(mNr, PKG, USER_ID)); - } - - // - // canLaunchInActivityView - // - - @Test - public void testCanLaunchInActivityView_true() { - setUpActivityIntent(true /* resizable */); - assertTrue(mBubbleChecker.canLaunchInActivityView(mContext, mPendingIntent, PKG)); - } - - @Test - public void testCanLaunchInActivityView_false_noIntent() { - when(mPendingIntent.getIntent()).thenReturn(null); - assertFalse(mBubbleChecker.canLaunchInActivityView(mContext, mPendingIntent, PKG)); - } - - @Test - public void testCanLaunchInActivityView_false_noInfo() { - when(mPendingIntent.getIntent()).thenReturn(mIntent); - when(mIntent.resolveActivityInfo(any(), anyInt())).thenReturn(null); - assertFalse(mBubbleChecker.canLaunchInActivityView(mContext, mPendingIntent, PKG)); - } - - @Test - public void testCanLaunchInActivityView_false_notResizable() { - setUpActivityIntent(false /* resizable */); - assertFalse(mBubbleChecker.canLaunchInActivityView(mContext, mPendingIntent, PKG)); - } - - // - // isNotificationAppropriateToBubble - // - - @Test - public void testIsNotifAppropriateToBubble_true() { - setUpBubblesEnabled(true /* feature */, true /* app */, true /* channel */); - setUpIntentBubble(); - when(mActivityManager.isLowRamDevice()).thenReturn(false); - setUpActivityIntent(true /* resizable */); - doReturn(Notification.MessagingStyle.class).when(mNotif).getNotificationStyle(); - - assertTrue(mBubbleChecker.isNotificationAppropriateToBubble(mNr)); - } - - @Test - public void testIsNotifAppropriateToBubble_false_lowRam() { - setUpBubblesEnabled(true /* feature */, true /* app */, true /* channel */); - when(mActivityManager.isLowRamDevice()).thenReturn(true); - setUpActivityIntent(true /* resizable */); - doReturn(Notification.MessagingStyle.class).when(mNotif).getNotificationStyle(); - - assertFalse(mBubbleChecker.isNotificationAppropriateToBubble(mNr)); - } - - @Test - public void testIsNotifAppropriateToBubble_false_notMessageStyle() { - setUpBubblesEnabled(true /* feature */, true /* app */, true /* channel */); - when(mActivityManager.isLowRamDevice()).thenReturn(false); - setUpActivityIntent(true /* resizable */); - doReturn(Notification.BigPictureStyle.class).when(mNotif).getNotificationStyle(); - - assertFalse(mBubbleChecker.isNotificationAppropriateToBubble(mNr)); - } - -} diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java index 0dbbbaa9cdd6..3c376c9972ac 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java @@ -15,12 +15,19 @@ */ package com.android.server.notification; -import static android.app.NotificationManager.IMPORTANCE_HIGH; -import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; +import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -28,6 +35,12 @@ import android.app.ActivityManager; import android.app.Notification; import android.app.Notification.Builder; import android.app.NotificationChannel; +import android.app.PendingIntent; +import android.app.Person; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ShortcutInfo; +import android.os.SystemClock; import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; @@ -46,16 +59,32 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class BubbleExtractorTest extends UiServiceTestCase { - @Mock RankingConfig mConfig; - @Mock BubbleExtractor.BubbleChecker mBubbleChecker; + private static final String SHORTCUT_ID = "shortcut"; + private static final String PKG = "com.android.server.notification"; + private static final String TAG = null; + private static final int ID = 1001; + private static final int UID = 1000; + private static final int PID = 2000; + UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser()); + BubbleExtractor mBubbleExtractor; - private String mPkg = "com.android.server.notification"; - private int mId = 1001; - private String mTag = null; - private int mUid = 1000; - private int mPid = 2000; - private UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser()); + @Mock + RankingConfig mConfig; + @Mock + NotificationChannel mChannel; + @Mock + Notification.BubbleMetadata mBubbleMetadata; + @Mock + PendingIntent mPendingIntent; + @Mock + Intent mIntent; + @Mock + ShortcutInfo mShortcutInfo; + @Mock + ShortcutHelper mShortcutHelper; + @Mock + ActivityManager mActivityManager; @Before public void setUp() { @@ -63,58 +92,103 @@ public class BubbleExtractorTest extends UiServiceTestCase { mBubbleExtractor = new BubbleExtractor(); mBubbleExtractor.initialize(mContext, mock(NotificationUsageStats.class)); mBubbleExtractor.setConfig(mConfig); - mBubbleExtractor.setShortcutHelper(mock(ShortcutHelper.class)); - } + mBubbleExtractor.setShortcutHelper(mShortcutHelper); + mBubbleExtractor.setActivityManager(mActivityManager); - private NotificationRecord getNotificationRecord(boolean allow, int importanceHigh) { - NotificationChannel channel = new NotificationChannel("a", "a", importanceHigh); - channel.setAllowBubbles(allow); - when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel); + when(mConfig.getNotificationChannel(PKG, UID, "a", false)).thenReturn(mChannel); + when(mShortcutInfo.getId()).thenReturn(SHORTCUT_ID); + } + /* NotificationRecord that fulfills conversation requirements (message style + shortcut) */ + private NotificationRecord getNotificationRecord(boolean addBubble) { final Builder builder = new Builder(getContext()) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setPriority(Notification.PRIORITY_HIGH) .setDefaults(Notification.DEFAULT_SOUND); - + Person person = new Person.Builder() + .setName("bubblebot") + .build(); + builder.setShortcutId(SHORTCUT_ID); + builder.setStyle(new Notification.MessagingStyle(person) + .setConversationTitle("Bubble Chat") + .addMessage("Hello?", + SystemClock.currentThreadTimeMillis() - 300000, person) + .addMessage("Is it me you're looking for?", + SystemClock.currentThreadTimeMillis(), person)); Notification n = builder.build(); - StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid, - mPid, n, mUser, null, System.currentTimeMillis()); - NotificationRecord r = new NotificationRecord(getContext(), sbn, channel); + if (addBubble) { + n.setBubbleMetadata(mBubbleMetadata); + } + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, ID, TAG, UID, + PID, n, mUser, null, System.currentTimeMillis()); + NotificationRecord r = new NotificationRecord(getContext(), sbn, mChannel); + r.setShortcutInfo(mShortcutInfo); return r; } + void setUpIntentBubble(boolean isValid) { + when(mPendingIntent.getIntent()).thenReturn(mIntent); + when(mBubbleMetadata.getIntent()).thenReturn(mPendingIntent); + when(mBubbleMetadata.getShortcutId()).thenReturn(null); + + when(mPendingIntent.getIntent()).thenReturn(mIntent); + ActivityInfo info = new ActivityInfo(); + info.resizeMode = isValid + ? RESIZE_MODE_RESIZEABLE + : RESIZE_MODE_UNRESIZEABLE; + when(mIntent.resolveActivityInfo(any(), anyInt())).thenReturn(info); + } + + void setUpShortcutBubble(boolean isValid) { + when(mBubbleMetadata.getShortcutId()).thenReturn(SHORTCUT_ID); + when(mBubbleMetadata.getIntent()).thenReturn(null); + ShortcutInfo answer = isValid ? mShortcutInfo : null; + when(mShortcutHelper.getValidShortcutInfo(SHORTCUT_ID, PKG, mUser)).thenReturn(answer); + } + + void setUpBubblesEnabled(boolean feature, int app, boolean channel) { + when(mConfig.bubblesEnabled()).thenReturn(feature); + when(mConfig.getBubblePreference(anyString(), anyInt())).thenReturn(app); + when(mChannel.canBubble()).thenReturn(channel); + } + // - // Tests + // Tests for the record being allowed to bubble. // @Test public void testAppYesChannelNo() { - when(mConfig.bubblesEnabled()).thenReturn(true); - when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true); - NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED); - + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + false /* channel */); + NotificationRecord r = getNotificationRecord(true /* bubble */); + when(mChannel.getUserLockedFields()).thenReturn(USER_LOCKED_ALLOW_BUBBLE); mBubbleExtractor.process(r); assertFalse(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); } @Test public void testAppNoChannelYes() throws Exception { - when(mConfig.bubblesEnabled()).thenReturn(true); - when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(false); - NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH); + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_NONE /* app */, + true /* channel */); + NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); assertFalse(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); } @Test public void testAppYesChannelYes() { - when(mConfig.bubblesEnabled()).thenReturn(true); - when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true); - NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED); + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); @@ -123,49 +197,228 @@ public class BubbleExtractorTest extends UiServiceTestCase { @Test public void testAppNoChannelNo() { - when(mConfig.bubblesEnabled()).thenReturn(true); - when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(false); - NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED); + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_NONE /* app */, + false /* channel */); + NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); assertFalse(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); } @Test public void testAppYesChannelYesUserNo() { - when(mConfig.bubblesEnabled()).thenReturn(false); - when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true); - NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH); + setUpBubblesEnabled(false /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + NotificationRecord r = getNotificationRecord(true /* bubble */); + + mBubbleExtractor.process(r); + + assertFalse(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); + } + + @Test + public void testAppSelectedChannelNo() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_SELECTED /* app */, + false /* channel */); + NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); assertFalse(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); } @Test - public void testFlagBubble_true() { - when(mConfig.bubblesEnabled()).thenReturn(true); - when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true); - NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED); + public void testAppSeletedChannelYes() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_SELECTED /* app */, + true /* channel */); + NotificationRecord r = getNotificationRecord(true /* bubble */); + when(mChannel.getUserLockedFields()).thenReturn(USER_LOCKED_ALLOW_BUBBLE); - mBubbleExtractor.setBubbleChecker(mBubbleChecker); - when(mBubbleChecker.isNotificationAppropriateToBubble(r)).thenReturn(true); mBubbleExtractor.process(r); assertTrue(r.canBubble()); - assertTrue(r.getNotification().isBubbleNotification()); } + // + // Tests for flagging it as a bubble. + // + @Test - public void testFlagBubble_noFlag_previouslyRemoved() { - when(mConfig.bubblesEnabled()).thenReturn(true); - when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true); - NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED); + public void testFlagBubble_false_previouslyRemoved() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + + NotificationRecord r = getNotificationRecord(true /* bubble */); r.setFlagBubbleRemoved(true); - mBubbleExtractor.setBubbleChecker(mBubbleChecker); - when(mBubbleChecker.isNotificationAppropriateToBubble(r)).thenReturn(true); + mBubbleExtractor.process(r); + + assertTrue(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); + } + + @Test + public void testFlagBubble_true_shortcutBubble() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(true /* isValid */); + + NotificationRecord r = getNotificationRecord(true /* bubble */); + mBubbleExtractor.process(r); + + assertTrue(r.canBubble()); + assertTrue(r.getNotification().isBubbleNotification()); + } + + @Test + public void testFlagBubble_true_intentBubble() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpIntentBubble(true /* isValid */); + + NotificationRecord r = getNotificationRecord(true /* bubble */); + mBubbleExtractor.process(r); + + assertTrue(r.canBubble()); + assertTrue(r.getNotification().isBubbleNotification()); + } + + @Test + public void testFlagBubble_false_noIntentInvalidShortcut() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(false /* isValid */); + + NotificationRecord r = getNotificationRecord(true /* bubble */); + r.setShortcutInfo(null); + mBubbleExtractor.process(r); + + assertTrue(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); + } + + @Test + public void testFlagBubble_false_invalidIntentNoShortcut() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpIntentBubble(false /* isValid */); + + NotificationRecord r = getNotificationRecord(true /* bubble */); + r.setShortcutInfo(null); + mBubbleExtractor.process(r); + + assertTrue(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); + } + + @Test + public void testFlagBubble_false_noIntentNoShortcut() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + + // Shortcut here is for the notification not the bubble + NotificationRecord r = getNotificationRecord(true /* bubble */); + mBubbleExtractor.process(r); + + assertTrue(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); + } + + @Test + public void testFlagBubble_false_noMetadata() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + + NotificationRecord r = getNotificationRecord(false /* bubble */); + mBubbleExtractor.process(r); + + assertTrue(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); + } + + @Test + public void testFlagBubble_false_notConversation() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpIntentBubble(true /* isValid */); + + NotificationRecord r = getNotificationRecord(true /* bubble */); + // No longer a conversation: + r.setShortcutInfo(null); + r.getNotification().extras.putString(Notification.EXTRA_TEMPLATE, null); + + mBubbleExtractor.process(r); + + assertTrue(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); + } + + @Test + public void testFlagBubble_false_lowRamDevice() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(true); + setUpIntentBubble(true /* isValid */); + + NotificationRecord r = getNotificationRecord(true /* bubble */); + mBubbleExtractor.process(r); + + assertTrue(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); + } + + @Test + public void testFlagBubble_false_noIntent() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(true); + setUpIntentBubble(true /* isValid */); + when(mPendingIntent.getIntent()).thenReturn(null); + + NotificationRecord r = getNotificationRecord(true /* bubble */); + mBubbleExtractor.process(r); + + assertTrue(r.canBubble()); + assertFalse(r.getNotification().isBubbleNotification()); + } + + @Test + public void testFlagBubble_false_noActivityInfo() { + setUpBubblesEnabled(true /* feature */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(true); + setUpIntentBubble(true /* isValid */); + when(mPendingIntent.getIntent()).thenReturn(mIntent); + when(mIntent.resolveActivityInfo(any(), anyInt())).thenReturn(null); + + NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); assertTrue(r.canBubble()); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 15220e1ff54a..3cd0e92964ec 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -21,6 +21,10 @@ import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIB import static android.app.Notification.FLAG_AUTO_CANCEL; import static android.app.Notification.FLAG_BUBBLE; import static android.app.Notification.FLAG_FOREGROUND_SERVICE; +import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; import static android.app.NotificationManager.EXTRA_BLOCKED_STATE; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_HIGH; @@ -39,6 +43,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -101,6 +106,7 @@ import android.content.ComponentName; import android.content.ContentUris; import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; @@ -204,7 +210,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { private TestableNotificationManagerService mService; private INotificationManager mBinderService; private NotificationManagerInternal mInternalService; - private TestableBubbleChecker mTestableBubbleChecker; private ShortcutHelper mShortcutHelper; @Mock private IPackageManager mPackageManager; @@ -347,21 +352,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } } - private class TestableBubbleChecker extends BubbleExtractor.BubbleChecker { - - TestableBubbleChecker(Context context, ShortcutHelper helper, RankingConfig config, - ActivityManager manager) { - super(context, helper, config, manager); - } - - @Override - protected boolean canLaunchInActivityView(Context context, PendingIntent pendingIntent, - String packageName) { - // Tests for this not being true are in CTS NotificationManagerTest - return true; - } - } - private class TestableToastCallback extends ITransientNotification.Stub { @Override public void show(IBinder windowToken) { @@ -480,9 +470,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Set the testable bubble extractor RankingHelper rankingHelper = mService.getRankingHelper(); BubbleExtractor extractor = rankingHelper.findExtractor(BubbleExtractor.class); - mTestableBubbleChecker = new TestableBubbleChecker(mContext, mShortcutHelper, - mService.mPreferencesHelper, mActivityManager); - extractor.setBubbleChecker(mTestableBubbleChecker); + extractor.setActivityManager(mActivityManager); // Tests call directly into the Binder. mBinderService = mService.getBinderService(); @@ -544,13 +532,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } private void setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled, - boolean pkgEnabled, boolean channelEnabled) { + int pkgPref, boolean channelEnabled) { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.NOTIFICATION_BUBBLES, globalEnabled ? 1 : 0); mService.mPreferencesHelper.updateBubblesEnabled(); assertEquals(globalEnabled, mService.mPreferencesHelper.bubblesEnabled()); try { - mBinderService.setBubblesAllowed(pkg, uid, pkgEnabled); + mBinderService.setBubblesAllowed(pkg, uid, pkgPref); } catch (RemoteException e) { e.printStackTrace(); } @@ -687,19 +675,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { false); } - private Notification.BubbleMetadata.Builder getBubbleMetadataBuilder() { - PendingIntent pi = PendingIntent.getActivity(mContext, 0, new Intent(), 0); - return new Notification.BubbleMetadata.Builder(pi, - Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon)); - } - private Notification.Builder getMessageStyleNotifBuilder(boolean addBubbleMetadata, String groupKey, boolean isSummary) { // Give it a person Person person = new Person.Builder() .setName("bubblebot") .build(); - // It needs remote input to be bubble-able RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0); Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); @@ -724,11 +705,26 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { nb.setGroup(groupKey); } if (addBubbleMetadata) { - nb.setBubbleMetadata(getBubbleMetadataBuilder().build()); + nb.setBubbleMetadata(getBubbleMetadata()); } return nb; } + private Notification.BubbleMetadata getBubbleMetadata() { + PendingIntent pendingIntent = mock(PendingIntent.class); + Intent intent = mock(Intent.class); + when(pendingIntent.getIntent()).thenReturn(intent); + + ActivityInfo info = new ActivityInfo(); + info.resizeMode = RESIZE_MODE_RESIZEABLE; + when(intent.resolveActivityInfo(any(), anyInt())).thenReturn(info); + + return new Notification.BubbleMetadata.Builder( + pendingIntent, + Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon)) + .build(); + } + private NotificationRecord addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel) throws RemoteException { @@ -4483,24 +4479,31 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testBubble() throws Exception { - mBinderService.setBubblesAllowed(PKG, mUid, false); - assertFalse(mBinderService.areBubblesAllowedForPackage(PKG, mUid)); + mBinderService.setBubblesAllowed(PKG, mUid, BUBBLE_PREFERENCE_NONE); + assertFalse(mBinderService.areBubblesAllowed(PKG)); + assertEquals(mBinderService.getBubblePreferenceForPackage(PKG, mUid), + BUBBLE_PREFERENCE_NONE); + } + + @Test + public void testUserApprovedBubblesForPackageSelected() throws Exception { + mBinderService.setBubblesAllowed(PKG, mUid, BUBBLE_PREFERENCE_SELECTED); + assertEquals(mBinderService.getBubblePreferenceForPackage(PKG, mUid), + BUBBLE_PREFERENCE_SELECTED); } @Test - public void testUserApprovedBubblesForPackage() throws Exception { - assertFalse(mBinderService.hasUserApprovedBubblesForPackage(PKG, mUid)); - mBinderService.setBubblesAllowed(PKG, mUid, true); - assertTrue(mBinderService.hasUserApprovedBubblesForPackage(PKG, mUid)); - assertTrue(mBinderService.areBubblesAllowedForPackage(PKG, mUid)); + public void testUserApprovedBubblesForPackageAll() throws Exception { + mBinderService.setBubblesAllowed(PKG, mUid, BUBBLE_PREFERENCE_ALL); + assertTrue(mBinderService.areBubblesAllowed(PKG)); + assertEquals(mBinderService.getBubblePreferenceForPackage(PKG, mUid), + BUBBLE_PREFERENCE_ALL); } @Test public void testUserRejectsBubblesForPackage() throws Exception { - assertFalse(mBinderService.hasUserApprovedBubblesForPackage(PKG, mUid)); - mBinderService.setBubblesAllowed(PKG, mUid, false); - assertTrue(mBinderService.hasUserApprovedBubblesForPackage(PKG, mUid)); - assertFalse(mBinderService.areBubblesAllowedForPackage(PKG, mUid)); + mBinderService.setBubblesAllowed(PKG, mUid, BUBBLE_PREFERENCE_NONE); + assertFalse(mBinderService.areBubblesAllowed(PKG)); } @Test @@ -5166,8 +5169,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testFlagBubble() throws RemoteException { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "testFlagBubble"); @@ -5185,8 +5190,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testFlagBubble_noFlag_appNotAllowed() throws RemoteException { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, false /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_NONE /* app */, + true /* channel */); NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "testFlagBubble_noFlag_appNotAllowed"); @@ -5204,15 +5211,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testFlagBubbleNotifs_noFlag_whenAppForeground() throws RemoteException { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); // Notif with bubble metadata but not our other misc requirements Notification.Builder nb = new Notification.Builder(mContext, mTestNotificationChannel.getId()) .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon) - .setBubbleMetadata(getBubbleMetadataBuilder().build()); + .setBubbleMetadata(getBubbleMetadata()); StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); @@ -5232,8 +5241,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testFlagBubbleNotifs_flag_messaging() throws RemoteException { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "testFlagBubbleNotifs_flag_messaging"); @@ -5249,8 +5260,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testFlagBubbleNotifs_noFlag_messaging_appNotAllowed() throws RemoteException { - // Bubbles are NOT allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, false /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_NONE /* app */, + true /* channel */); NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "testFlagBubbleNotifs_noFlag_messaging_appNotAllowed"); @@ -5267,8 +5280,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testFlagBubbleNotifs_noFlag_notBubble() throws RemoteException { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); // Messaging notif WITHOUT bubble metadata Notification.Builder nb = getMessageStyleNotifBuilder(false /* addBubbleMetadata */, @@ -5291,11 +5306,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed() throws RemoteException { - // Bubbles are allowed except on this channel - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, false /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + false /* channel */); NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed"); + nr.getChannel().lockFields(USER_LOCKED_ALLOW_BUBBLE); // Post the notification mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(), @@ -5488,7 +5506,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testAreBubblesAllowedForPackage_crossUser() throws Exception { try { - mBinderService.areBubblesAllowedForPackage(mContext.getPackageName(), + mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(), mUid + UserHandle.PER_USER_RANGE); fail("Cannot call cross user without permission"); } catch (SecurityException e) { @@ -5497,7 +5515,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // cross user, with permission, no problem enableInteractAcrossUsers(); - mBinderService.areBubblesAllowedForPackage(mContext.getPackageName(), + mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(), mUid + UserHandle.PER_USER_RANGE); } @@ -5508,8 +5526,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbleChanged_false() throws Exception { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); // Notif with bubble metadata NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, @@ -5528,7 +5548,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertTrue((notifsBefore[0].getNotification().flags & FLAG_BUBBLE) != 0); // Notify we're not a bubble - mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false); + mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); waitForIdle(); // Make sure we are not a bubble @@ -5539,8 +5559,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbleChanged_true() throws Exception { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); // Notif that is not a bubble NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, @@ -5565,7 +5587,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { reset(mListeners); // Notify we are now a bubble - mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true); + mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); waitForIdle(); // Make sure we are a bubble @@ -5576,8 +5598,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbleChanged_true_notAllowed() throws Exception { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); // Notif that is not a bubble NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); @@ -5594,7 +5618,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0); // Notify we are now a bubble - mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true); + mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); waitForIdle(); // We still wouldn't be a bubble because the notification didn't meet requirements @@ -5605,8 +5629,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbleIsFlagRemoved_resetOnUpdate() throws Exception { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + // Notif with bubble metadata NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "testNotificationBubbleIsFlagRemoved_resetOnUpdate"); @@ -5619,7 +5646,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertFalse(recordToCheck.isFlagBubbleRemoved()); // Notify we're not a bubble - mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false); + mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); waitForIdle(); // Flag should be modified recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); @@ -5637,8 +5664,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbleIsFlagRemoved_resetOnBubbleChangedTrue() throws Exception { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + // Notif with bubble metadata NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "testNotificationBubbleIsFlagRemoved_trueOnBubbleChangedTrue"); @@ -5651,14 +5681,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertFalse(recordToCheck.isFlagBubbleRemoved()); // Notify we're not a bubble - mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false); + mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); waitForIdle(); // Flag should be modified recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); assertTrue(recordToCheck.isFlagBubbleRemoved()); // Notify we are a bubble - mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true); + mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); waitForIdle(); // And the flag is reset assertFalse(recordToCheck.isFlagBubbleRemoved()); @@ -5666,16 +5696,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testOnBubbleNotificationSuppressionChanged() throws Exception { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); // Bubble notification NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag"); - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, nr.getSbn().getUserId(), true /* global */, - true /* app */, true /* channel */); - mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); waitForIdle(); @@ -5888,8 +5916,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbles_disabled_lowRamDevice() throws Exception { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); // And we are low ram when(mActivityManager.isLowRamDevice()).thenReturn(true); @@ -5972,8 +6002,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbles_flagAutoExpandForeground_fails_notForeground() throws Exception { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "testNotificationBubbles_flagAutoExpandForeground_fails_notForeground"); @@ -6002,8 +6034,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground() throws RemoteException { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground"); @@ -6032,8 +6066,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbles_flagRemoved_whenShortcutRemoved() throws RemoteException { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback = ArgumentCaptor.forClass(LauncherApps.Callback.class); @@ -6090,8 +6126,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbles_shortcut_stopListeningWhenNotifRemoved() throws RemoteException { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback = ArgumentCaptor.forClass(LauncherApps.Callback.class); @@ -6141,8 +6179,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryDismissed() throws Exception { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded( true /* summaryAutoCancel */); @@ -6165,8 +6205,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryClicked() throws Exception { - // Bubbles are allowed! - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded( true /* summaryAutoCancel */); @@ -6197,8 +6239,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testNotificationBubbles_bubbleStays_whenClicked() throws Exception { + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble - setUpPrefsForBubbles(PKG, mUid, true /* global */, true /* app */, true /* channel */); final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL; mService.addNotification(nr); @@ -6332,7 +6378,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals("friend", friendChannel.getConversationId()); assertEquals(null, original.getConversationId()); assertEquals(original.canShowBadge(), friendChannel.canShowBadge()); - assertEquals(original.canBubble(), friendChannel.canBubble()); + assertFalse(friendChannel.canBubble()); // can't be modified by app assertFalse(original.getId().equals(friendChannel.getId())); assertNotNull(friendChannel.getId()); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index ed5ec6ac785b..427237c4be0f 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -16,6 +16,9 @@ package com.android.server.notification; import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_LOW; @@ -23,6 +26,7 @@ import static android.app.NotificationManager.IMPORTANCE_MAX; import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; +import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE; import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT; import static com.google.common.truth.Truth.assertThat; @@ -1094,7 +1098,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { .getUserLockedFields()); final NotificationChannel update = getChannel(); - update.setAllowBubbles(false); + update.setAllowBubbles(true); mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true); assertEquals(NotificationChannel.USER_LOCKED_ALLOW_BUBBLE, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update.getId(), false) @@ -1734,14 +1738,14 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, pkgPair); mHelper.setNotificationDelegate(PKG_O, UID_O, "", 1); mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_NONE); - mHelper.setBubblesAllowed(PKG_O, UID_O, false); + mHelper.setBubblesAllowed(PKG_O, UID_O, DEFAULT_BUBBLE_PREFERENCE); mHelper.setShowBadge(PKG_O, UID_O, false); mHelper.setAppImportanceLocked(PKG_O, UID_O); mHelper.clearData(PKG_O, UID_O); assertEquals(IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_O, UID_O)); - assertTrue(mHelper.areBubblesAllowed(PKG_O, UID_O)); + assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), DEFAULT_BUBBLE_PREFERENCE); assertTrue(mHelper.canShowBadge(PKG_O, UID_O)); assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O)); assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O)); @@ -2412,21 +2416,21 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test - public void testAllowBubbles_defaults() throws Exception { - assertTrue(mHelper.areBubblesAllowed(PKG_O, UID_O)); + public void testBubblePreference_defaults() throws Exception { + assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); loadStreamXml(baos, false, UserHandle.USER_ALL); - assertTrue(mHelper.areBubblesAllowed(PKG_O, UID_O)); + assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O)); } @Test - public void testAllowBubbles_xml() throws Exception { - mHelper.setBubblesAllowed(PKG_O, UID_O, false); - assertFalse(mHelper.areBubblesAllowed(PKG_O, UID_O)); + public void testBubblePreference_xml() throws Exception { + mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE); + assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE, mHelper.getAppLockedFields(PKG_O, UID_O)); @@ -2434,7 +2438,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); loadStreamXml(baos, false, UserHandle.USER_ALL); - assertFalse(mHelper.areBubblesAllowed(PKG_O, UID_O)); + assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE, mHelper.getAppLockedFields(PKG_O, UID_O)); } @@ -2766,9 +2770,29 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test - public void testSetBubblesAllowed_false() { - mHelper.setBubblesAllowed(PKG_O, UID_O, false); - assertFalse(mHelper.areBubblesAllowed(PKG_O, UID_O)); + public void testSetBubblesAllowed_none() { + // Change it to non-default first + mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_ALL); + assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_ALL); + verify(mHandler, times(1)).requestSort(); + reset(mHandler); + // Now test + mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE); + assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); + verify(mHandler, times(1)).requestSort(); + } + + @Test + public void testSetBubblesAllowed_all() { + mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_ALL); + assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_ALL); + verify(mHandler, times(1)).requestSort(); + } + + @Test + public void testSetBubblesAllowed_selected() { + mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_SELECTED); + assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_SELECTED); verify(mHandler, times(1)).requestSort(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 08f6409cb902..bc66fa7ff48d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -32,6 +32,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; @@ -63,6 +64,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.never; @@ -1024,6 +1026,38 @@ public class ActivityRecordTests extends ActivityTestsBase { } /** + * Verify that complete finish request for a show-when-locked activity must ensure the + * keyguard occluded state being updated. + */ + @Test + public void testCompleteFinishing_showWhenLocked() { + // Make keyguard locked and set the top activity show-when-locked. + KeyguardController keyguardController = mActivity.mStackSupervisor.getKeyguardController(); + doReturn(true).when(keyguardController).isKeyguardLocked(); + final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); + topActivity.mVisibleRequested = true; + topActivity.nowVisible = true; + topActivity.setState(RESUMED, "true"); + doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible( + any() /* starting */, anyInt() /* configChanges */, + anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */); + topActivity.setShowWhenLocked(true); + + // Verify the stack-top activity is occluded keyguard. + assertEquals(topActivity, mStack.topRunningActivity()); + assertTrue(mStack.topActivityOccludesKeyguard()); + + // Finish the top activity + topActivity.setState(PAUSED, "true"); + topActivity.finishing = true; + topActivity.completeFinishing("test"); + + // Verify new top activity does not occlude keyguard. + assertEquals(mActivity, mStack.topRunningActivity()); + assertFalse(mStack.topActivityOccludesKeyguard()); + } + + /** * Verify destroy activity request completes successfully. */ @Test @@ -1273,6 +1307,48 @@ public class ActivityRecordTests extends ActivityTestsBase { } @Test + public void testActivityOnCancelFixedRotationTransform() { + mService.mWindowManager.mIsFixedRotationTransformEnabled = true; + final DisplayRotation displayRotation = mActivity.mDisplayContent.getDisplayRotation(); + spyOn(displayRotation); + + final DisplayContent display = mActivity.mDisplayContent; + final int originalRotation = display.getRotation(); + + // Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately. + doReturn(true).when(displayRotation).isWaitingForRemoteRotation(); + doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation( + anyInt() /* orientation */, anyInt() /* lastRotation */); + // Set to visible so the activity can freeze the screen. + mActivity.setVisibility(true); + + display.rotateInDifferentOrientationIfNeeded(mActivity); + display.mFixedRotationLaunchingApp = mActivity; + displayRotation.updateRotationUnchecked(false /* forceUpdate */); + + assertTrue(displayRotation.isRotatingSeamlessly()); + + // Simulate the rotation has been updated to previous one, e.g. sensor updates before the + // remote rotation is completed. + doReturn(originalRotation).when(displayRotation).rotationForOrientation( + anyInt() /* orientation */, anyInt() /* lastRotation */); + display.updateOrientation(); + + final DisplayInfo rotatedInfo = mActivity.getFixedRotationTransformDisplayInfo(); + mActivity.finishFixedRotationTransform(); + final ScreenRotationAnimation rotationAnim = display.getRotationAnimation(); + rotationAnim.setRotation(display.getPendingTransaction(), originalRotation); + + // Because the display doesn't rotate, the rotated activity needs to cancel the fixed + // rotation. There should be a rotation animation to cover the change of activity. + verify(mActivity).onCancelFixedRotationTransform(rotatedInfo.rotation); + assertTrue(mActivity.isFreezingScreen()); + assertFalse(displayRotation.isRotatingSeamlessly()); + assertNotNull(rotationAnim); + assertTrue(rotationAnim.isRotating()); + } + + @Test public void testActivityOnDifferentDisplayUpdatesProcessOverride() { final ActivityRecord secondaryDisplayActivity = createActivityOnDisplay(false /* defaultDisplay */, null /* process */); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java index 22d7fcbb4162..5c6906cfa942 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java @@ -125,7 +125,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { spyOn(taskChangeNotifier); mSupervisor.handleNonResizableTaskIfNeeded(task, newDisplay.getWindowingMode(), - newDisplay.mDisplayId, stack); + newDisplay.getDefaultTaskDisplayArea(), stack); // The top activity is unresizable, so it should notify the activity is forced resizing. verify(taskChangeNotifier).notifyActivityForcedResizable(eq(task.mTaskId), eq(FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY), @@ -138,7 +138,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { resizableActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; mSupervisor.handleNonResizableTaskIfNeeded(task, newDisplay.getWindowingMode(), - newDisplay.mDisplayId, stack); + newDisplay.getDefaultTaskDisplayArea(), stack); // For the resizable activity, it is no need to force resizing or dismiss the docked stack. verify(taskChangeNotifier, never()).notifyActivityForcedResizable(anyInt() /* taskId */, anyInt() /* reason */, anyString() /* packageName */); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index 3d15401cdfb9..3bed05f383a8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -46,6 +46,7 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_F import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.wm.TaskDisplayArea.getStackAbove; +import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.google.common.truth.Truth.assertThat; @@ -140,9 +141,12 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testPrimarySplitScreenRestoresWhenMovedToBack() { - // Create primary splitscreen stack. This will create secondary stacks and places the - // existing fullscreen stack on the bottom. + public void testPrimarySplitScreenMoveToBack() { + TestSplitOrganizer organizer = new TestSplitOrganizer(mService); + // We're testing an edge case here where we have primary + fullscreen rather than secondary. + organizer.setMoveToSecondaryOnEnter(false); + + // Create primary splitscreen stack. final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -165,12 +169,14 @@ public class ActivityStackTests extends ActivityTestsBase { } @Test - public void testPrimarySplitScreenRestoresPreviousWhenMovedToBack() { + public void testMoveToPrimarySplitScreenThenMoveToBack() { + TestSplitOrganizer organizer = new TestSplitOrganizer(mService); // This time, start with a fullscreen activitystack final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); - primarySplitScreen.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + primarySplitScreen.reparent((ActivityStack) organizer.mPrimary, POSITION_TOP, + false /*moveParents*/, "test"); // Assert windowing mode. assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, primarySplitScreen.getWindowingMode()); @@ -180,14 +186,52 @@ public class ActivityStackTests extends ActivityTestsBase { null /* task */); // Assert that stack is at the bottom. - assertEquals(0, mDefaultTaskDisplayArea.getIndexOf(primarySplitScreen)); + assertEquals(primarySplitScreen, organizer.mSecondary.getChildAt(0)); // Ensure that the override mode is restored to what it was (fullscreen) - assertEquals(WINDOWING_MODE_FULLSCREEN, + assertEquals(WINDOWING_MODE_UNDEFINED, primarySplitScreen.getRequestedOverrideWindowingMode()); } @Test + public void testSplitScreenMoveToBack() { + TestSplitOrganizer organizer = new TestSplitOrganizer(mService); + // Set up split-screen with primary on top and secondary containing the home task below + // another stack. + final ActivityStack primaryTask = mDefaultTaskDisplayArea.createStack( + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final ActivityStack homeRoot = mDefaultTaskDisplayArea.getStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); + final ActivityStack secondaryTask = mDefaultTaskDisplayArea.createStack( + WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */); + mDefaultTaskDisplayArea.positionStackAtTop((ActivityStack) organizer.mPrimary, + false /* includingParents */); + + // Move primary to back. + primaryTask.moveToBack("test", null /* task */); + + // Assert that the primaryTask is now below home in its parent but primary is left alone. + assertEquals(0, organizer.mPrimary.getChildCount()); + assertEquals(primaryTask, organizer.mSecondary.getChildAt(0)); + assertEquals(1, organizer.mPrimary.compareTo(organizer.mSecondary)); + assertEquals(1, homeRoot.compareTo(primaryTask)); + assertEquals(homeRoot.getParent(), primaryTask.getParent()); + + // Make sure windowing modes are correct + assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, organizer.mPrimary.getWindowingMode()); + assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, primaryTask.getWindowingMode()); + + // Move secondary to back via parent (should be equivalent) + ((ActivityStack) organizer.mSecondary).moveToBack("test", secondaryTask); + + // Assert that it is now in back but still in secondary split + assertEquals(1, homeRoot.compareTo(primaryTask)); + assertEquals(secondaryTask, organizer.mSecondary.getChildAt(0)); + assertEquals(1, primaryTask.compareTo(secondaryTask)); + assertEquals(homeRoot.getParent(), secondaryTask.getParent()); + } + + @Test public void testStackInheritsDisplayWindowingMode() { final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index bdba4b6c8ac8..97734ff32de2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -30,7 +30,6 @@ import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_SWITCHES_CANCELED; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; @@ -64,10 +63,8 @@ import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.IApplicationThread; -import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -82,8 +79,6 @@ import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.service.voice.IVoiceInteractionSession; import android.view.Gravity; -import android.window.ITaskOrganizer; -import android.window.WindowContainerToken; import androidx.test.filters.SmallTest; @@ -1004,62 +999,4 @@ public class ActivityStarterTests extends ActivityTestsBase { verify(recentTasks, times(1)).add(any()); } - - static class TestSplitOrganizer extends ITaskOrganizer.Stub { - final ActivityTaskManagerService mService; - Task mPrimary; - Task mSecondary; - boolean mInSplit = false; - int mDisplayId; - TestSplitOrganizer(ActivityTaskManagerService service, int displayId) { - mService = service; - mDisplayId = displayId; - mService.mTaskOrganizerController.registerTaskOrganizer(this, - WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - mService.mTaskOrganizerController.registerTaskOrganizer(this, - WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask( - displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token; - mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask(); - WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask( - displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token; - mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask(); - } - @Override - public void onTaskAppeared(ActivityManager.RunningTaskInfo info) { - } - @Override - public void onTaskVanished(ActivityManager.RunningTaskInfo info) { - } - @Override - public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { - if (mInSplit) { - return; - } - if (info.topActivityType != ACTIVITY_TYPE_UNDEFINED) { - if (info.configuration.windowConfiguration.getWindowingMode() - == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { - mInSplit = true; - mService.mTaskOrganizerController.setLaunchRoot(mDisplayId, - mSecondary.mRemoteToken.toWindowContainerToken()); - // move everything to secondary because test expects this but usually sysui - // does it. - DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId); - for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { - final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); - for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { - final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); - if (!WindowConfiguration.isSplitScreenWindowingMode( - stack.getWindowingMode())) { - stack.reparent(mSecondary, POSITION_BOTTOM); - } - } - } - } - } - } - @Override - public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { - } - }; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 67d4769522b0..6ae8313e39dd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -17,7 +17,10 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -30,9 +33,12 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; +import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.IApplicationThread; +import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -43,6 +49,8 @@ import android.os.Build; import android.os.Bundle; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; +import android.window.ITaskOrganizer; +import android.window.WindowContainerToken; import com.android.server.AttributeCache; @@ -505,4 +513,74 @@ class ActivityTestsBase extends SystemServiceTestsBase { } } + + static class TestSplitOrganizer extends ITaskOrganizer.Stub { + final ActivityTaskManagerService mService; + Task mPrimary; + Task mSecondary; + boolean mInSplit = false; + // moves everything to secondary. Most tests expect this since sysui usually does it. + boolean mMoveToSecondaryOnEnter = true; + int mDisplayId; + TestSplitOrganizer(ActivityTaskManagerService service, int displayId) { + mService = service; + mDisplayId = displayId; + mService.mTaskOrganizerController.registerTaskOrganizer(this, + WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + mService.mTaskOrganizerController.registerTaskOrganizer(this, + WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask( + displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token; + mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask(); + WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask( + displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token; + mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask(); + } + TestSplitOrganizer(ActivityTaskManagerService service) { + this(service, + service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay().mDisplayId); + } + public void setMoveToSecondaryOnEnter(boolean move) { + mMoveToSecondaryOnEnter = move; + } + @Override + public void onTaskAppeared(ActivityManager.RunningTaskInfo info) { + } + @Override + public void onTaskVanished(ActivityManager.RunningTaskInfo info) { + } + @Override + public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { + if (mInSplit) { + return; + } + if (info.topActivityType == ACTIVITY_TYPE_UNDEFINED) { + // Not populated + return; + } + if (info.configuration.windowConfiguration.getWindowingMode() + != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + return; + } + mInSplit = true; + if (!mMoveToSecondaryOnEnter) { + return; + } + mService.mTaskOrganizerController.setLaunchRoot(mDisplayId, + mSecondary.mRemoteToken.toWindowContainerToken()); + DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId); + for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) { + stack.reparent(mSecondary, POSITION_BOTTOM); + } + } + } + } + @Override + public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { + } + }; } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java index 12bdec6ec1e1..0568be8d7fa6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java @@ -22,6 +22,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER; +import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER; import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS; import static com.android.server.wm.DisplayArea.Type.ANY; @@ -72,7 +73,11 @@ public class DisplayAreaPolicyBuilderTest { WindowManagerService wms = mSystemServices.getWindowManagerService(); DisplayArea.Root root = new SurfacelessDisplayAreaRoot(wms); DisplayArea<WindowContainer> ime = new DisplayArea<>(wms, ABOVE_TASKS, "Ime"); - DisplayArea<ActivityStack> tasks = new DisplayArea<>(wms, ANY, "Tasks"); + DisplayContent displayContent = mock(DisplayContent.class); + TaskDisplayArea taskDisplayArea = new TaskDisplayArea(displayContent, wms, "Tasks", + FEATURE_DEFAULT_TASK_CONTAINER); + List<TaskDisplayArea> taskDisplayAreaList = new ArrayList<>(); + taskDisplayAreaList.add(taskDisplayArea); final Feature foo; final Feature bar; @@ -86,7 +91,7 @@ public class DisplayAreaPolicyBuilderTest { .all() .except(TYPE_STATUS_BAR) .build()) - .build(wms, mock(DisplayContent.class), root, ime, tasks); + .build(wms, displayContent, root, ime, taskDisplayAreaList); policy.attachDisplayAreas(); @@ -98,9 +103,9 @@ public class DisplayAreaPolicyBuilderTest { assertThat(policy.findAreaForToken(tokenOfType(TYPE_STATUS_BAR)), is(not(decendantOfOneOf(policy.getDisplayAreas(bar))))); - assertThat(tasks, + assertThat(taskDisplayArea, is(decendantOfOneOf(policy.getDisplayAreas(foo)))); - assertThat(tasks, + assertThat(taskDisplayArea, is(decendantOfOneOf(policy.getDisplayAreas(bar)))); assertThat(ime, @@ -109,7 +114,8 @@ public class DisplayAreaPolicyBuilderTest { is(decendantOfOneOf(policy.getDisplayAreas(bar)))); List<DisplayArea<?>> actualOrder = collectLeafAreas(root); - Map<DisplayArea<?>, Set<Integer>> zSets = calculateZSets(policy, root, ime, tasks); + Map<DisplayArea<?>, Set<Integer>> zSets = calculateZSets(policy, root, ime, + taskDisplayArea); actualOrder = actualOrder.stream().filter(zSets::containsKey).collect(toList()); Map<DisplayArea<?>, Integer> expectedByMinLayer = mapValues(zSets, diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java index 4e4627bf7e52..6834ee5f3950 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaProviderTest.java @@ -77,8 +77,7 @@ public class DisplayAreaProviderTest { @Override public DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content, - DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer, - TaskDisplayArea taskDisplayArea) { + DisplayArea.Root root, DisplayArea<? extends WindowContainer> imeContainer) { throw new RuntimeException("test stub"); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java index 618e6086b582..880c486c15af 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java @@ -54,17 +54,6 @@ public class DisplayAreaTest { } @Test - public void testDisplayArea_positionChanged_throwsIfIncompatibleSibling() { - WindowManagerService wms = mWmsRule.getWindowManagerService(); - DisplayArea<WindowContainer> parent = new SurfacelessDisplayArea<>(wms, ANY, "Parent"); - DisplayArea<WindowContainer> child1 = new DisplayArea<>(wms, ANY, "Child1"); - DisplayArea<WindowContainer> child2 = new DisplayArea<>(wms, ANY, "Child2"); - - parent.addChild(child1, 0); - assertThrows(IllegalStateException.class, () -> parent.addChild(child2, 0)); - } - - @Test public void testType_typeOf() { WindowManagerService wms = mWmsRule.getWindowManagerService(); @@ -87,10 +76,10 @@ public class DisplayAreaTest { checkSiblings(BELOW_TASKS, ABOVE_TASKS); checkSiblings(ANY, ABOVE_TASKS); checkSiblings(ABOVE_TASKS, ABOVE_TASKS); + checkSiblings(ANY, ANY); assertThrows(IllegalStateException.class, () -> checkSiblings(ABOVE_TASKS, BELOW_TASKS)); assertThrows(IllegalStateException.class, () -> checkSiblings(ABOVE_TASKS, ANY)); - assertThrows(IllegalStateException.class, () -> checkSiblings(ANY, ANY)); assertThrows(IllegalStateException.class, () -> checkSiblings(ANY, BELOW_TASKS)); } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index a901d1ebd890..3f47b8722a39 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -826,7 +826,7 @@ public class DisplayContentTests extends WindowTestsBase { dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "app"); dc.mInputMethodTarget.setWindowingMode( WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - assertEquals(dc.getWindowingLayer(), dc.computeImeParent()); + assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent()); } } @@ -836,7 +836,8 @@ public class DisplayContentTests extends WindowTestsBase { doReturn(false).when(mAppWindow.mActivityRecord).matchParentBounds(); mDisplayContent.mInputMethodTarget = mAppWindow; // The surface parent of IME should be the display instead of app window. - assertEquals(mDisplayContent.getWindowingLayer(), mDisplayContent.computeImeParent()); + assertEquals(mDisplayContent.getImeContainer().getParentSurfaceControl(), + mDisplayContent.computeImeParent()); } @Test @@ -845,7 +846,7 @@ public class DisplayContentTests extends WindowTestsBase { new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) { final DisplayContent dc = createNewDisplay(); dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "statusBar"); - assertEquals(dc.getWindowingLayer(), dc.computeImeParent()); + assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent()); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java index 89bc65b5a44d..b6eb9010ce90 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java @@ -30,7 +30,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; -import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -41,7 +40,6 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; import android.platform.test.annotations.Presubmit; import android.util.IntArray; @@ -49,7 +47,6 @@ import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.test.InsetsModeSession; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.AfterClass; @@ -168,6 +165,18 @@ public class InsetsPolicyTest extends WindowTestsBase { } @Test + public void testControlsForDispatch_forceShowSystemBarsFromExternal_appHasNoControl() { + mDisplayContent.getDisplayPolicy().setForceShowSystemBars(true); + addWindow(TYPE_STATUS_BAR, "statusBar"); + addWindow(TYPE_NAVIGATION_BAR, "navBar"); + + final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch(); + + // The focused app window cannot control system bars. + assertNull(controls); + } + + @Test public void testShowTransientBars_bothCanBeTransient_appGetsBothFakeControls() { addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar") .getControllableInsetProvider().getSource().setVisible(false); diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java index 1144272a0e46..8a9504dd11b5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java @@ -23,12 +23,14 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; @@ -54,6 +56,7 @@ import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import java.util.Map; @@ -65,6 +68,7 @@ import java.util.Map; */ @MediumTest @Presubmit +@RunWith(WindowTestRunner.class) public class LaunchParamsControllerTests extends ActivityTestsBase { private LaunchParamsController mController; private TestLaunchParamsPersister mPersister; @@ -276,16 +280,21 @@ public class LaunchParamsControllerTests extends ActivityTestsBase { @Test public void testLayoutTaskPreferredDisplayChange() { final LaunchParams params = new LaunchParams(); - params.mPreferredDisplayId = 2; + final TestDisplayContent display = createNewDisplayContent(); + final TaskDisplayArea preferredTaskDisplayArea = display.getDefaultTaskDisplayArea(); + // TODO(b/152116619): Enable after complete switch to WindowContainerToken + //params.mPreferredWindowContainerToken = preferredTaskDisplayAreaToken; + params.mPreferredDisplayId = display.mDisplayId; final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params); final Task task = new TaskBuilder(mService.mStackSupervisor).build(); mController.registerModifier(positioner); - doNothing().when(mService).moveStackToDisplay(anyInt(), anyInt()); + doNothing().when(mRootWindowContainer).moveStackToTaskDisplayArea(anyInt(), any(), + anyBoolean()); mController.layoutTask(task, null /* windowLayout */); - verify(mService, times(1)).moveStackToDisplay(eq(task.getRootTaskId()), - eq(params.mPreferredDisplayId)); + verify(mRootWindowContainer, times(1)).moveStackToTaskDisplayArea(eq(task.getRootTaskId()), + eq(preferredTaskDisplayArea), anyBoolean()); } /** @@ -452,4 +461,14 @@ public class LaunchParamsControllerTests extends ActivityTestsBase { } } } + + private TestDisplayContent createNewDisplayContent() { + final TestDisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP); + spyOn(display.mDisplayContent.mDisplayFrames); + + // We didn't set up the overall environment for this test, so we need to mute the side + // effect of layout passes that loosen the stable frame. + doNothing().when(display.mDisplayContent.mDisplayFrames).onBeginLayout(); + return display; + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index add4e9cf3948..ea933dfe42dc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -1124,8 +1124,6 @@ public class RecentTasksTest extends ActivityTestsBase { } }); assertSecurityException(expectCallable, - () -> mService.moveTasksToFullscreenStack(INVALID_STACK_ID, true)); - assertSecurityException(expectCallable, () -> mService.startActivityFromRecents(0, new Bundle())); assertSecurityException(expectCallable, () -> mService.getTaskSnapshot(0, true)); assertSecurityException(expectCallable, () -> mService.registerTaskStackListener(null)); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index 6d2b7b1e86fe..f19550ced0bf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -23,7 +23,6 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; @@ -318,7 +317,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { // Assume activity transition should animate when no // IRecentsAnimationController#setDeferCancelUntilNextTransition called. assertFalse(mController.shouldDeferCancelWithScreenshot()); - assertTrue(activity.shouldAnimate(TRANSIT_ACTIVITY_CLOSE)); + assertTrue(activity.shouldAnimate()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java index 881561f5750b..1f6ba7adf114 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -238,9 +238,6 @@ public class RecentsAnimationTest extends ActivityTestsBase { assertTrue(targetActivity.mLaunchTaskBehind); anotherHomeActivity.moveFocusableActivityToTop("launchAnotherHome"); - // The current top activity is not the recents so the animation should be canceled. - verify(mService.mWindowManager, times(1)).cancelRecentsAnimation( - eq(REORDER_KEEP_IN_PLACE), any() /* reason */); // The test uses mocked RecentsAnimationController so we have to invoke the callback // manually to simulate the flow. @@ -279,10 +276,6 @@ public class RecentsAnimationTest extends ActivityTestsBase { fullscreenStack.moveToFront("Activity start"); - // Ensure that the recents animation was canceled by cancelAnimationSynchronously(). - verify(mService.mWindowManager, times(1)).cancelRecentsAnimation( - eq(REORDER_KEEP_IN_PLACE), any()); - // Assume recents animation already started, set a state that cancel recents animation // with screenshot. doReturn(true).when(mRecentsAnimationController).shouldDeferCancelUntilNextTransition(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index b648346eeb28..3c9051547eed 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -26,6 +26,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.TYPE_VIRTUAL; +import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -57,7 +58,6 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.res.Resources; -import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.util.Pair; @@ -125,9 +125,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { ensureStackPlacement(mFullscreenStack, firstActivity, secondActivity); // Move first activity to pinned stack. - final Rect sourceBounds = new Rect(); - mRootWindowContainer.moveActivityToPinnedStack(firstActivity, sourceBounds, - 0f /*aspectRatio*/, "initialMove"); + mRootWindowContainer.moveActivityToPinnedStack(firstActivity, "initialMove"); final TaskDisplayArea taskDisplayArea = mFullscreenStack.getDisplayArea(); ActivityStack pinnedStack = taskDisplayArea.getRootPinnedTask(); @@ -136,8 +134,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { ensureStackPlacement(mFullscreenStack, secondActivity); // Move second activity to pinned stack. - mRootWindowContainer.moveActivityToPinnedStack(secondActivity, sourceBounds, - 0f /*aspectRatio*/, "secondMove"); + mRootWindowContainer.moveActivityToPinnedStack(secondActivity, "secondMove"); // Need to get stacks again as a new instance might have been created. pinnedStack = taskDisplayArea.getRootPinnedTask(); @@ -247,6 +244,44 @@ public class RootActivityContainerTests extends ActivityTestsBase { assertEquals(originalStackCount, defaultTaskDisplayArea.getStackCount()); } + /** + * Verifies that removal of activities with task and stack is done correctly when there are + * several task display areas. + */ + @Test + public void testRemovingStackOnAppCrash_multipleDisplayAreas() { + final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer + .getDefaultTaskDisplayArea(); + final int originalStackCount = defaultTaskDisplayArea.getStackCount(); + final ActivityStack stack = defaultTaskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) + .setStack(stack).build(); + assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount()); + + final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent(); + doReturn(2).when(dc).getTaskDisplayAreaCount(); + final TaskDisplayArea secondTaskDisplayArea = new TaskDisplayArea(dc, + mRootWindowContainer.mWmService, "SecondaryTaskDisplayArea", FEATURE_VENDOR_FIRST); + // Add second display area right above the default one + defaultTaskDisplayArea.getParent().addChild(secondTaskDisplayArea, + defaultTaskDisplayArea.getParent().mChildren.indexOf(defaultTaskDisplayArea) + 1); + doReturn(secondTaskDisplayArea).when(dc).getTaskDisplayAreaAt(1); + final ActivityStack secondStack = secondTaskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + new ActivityBuilder(mService).setCreateTask(true).setStack(secondStack) + .setUseProcess(firstActivity.app).build(); + assertEquals(1, secondTaskDisplayArea.getStackCount()); + + // Let's pretend that the app has crashed. + firstActivity.app.setThread(null); + mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test"); + + // Verify that the stacks were removed. + assertEquals(originalStackCount, defaultTaskDisplayArea.getStackCount()); + assertEquals(0, secondTaskDisplayArea.getStackCount()); + } + @Test public void testFocusability() { final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer @@ -400,7 +435,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { taskDisplayArea.getRootHomeTask().removeIfPossible(); taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); - doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), anyInt()); + doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any()); mService.setBooted(true); @@ -408,7 +443,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { mRootWindowContainer.resumeFocusedStacksTopActivities(); // Verify that home activity was started on the default display - verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(DEFAULT_DISPLAY)); + verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea)); } /** @@ -430,7 +465,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { final Task task = new TaskBuilder(mSupervisor).setStack(stack).build(); new ActivityBuilder(mService).setTask(task).build(); - doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), anyInt()); + doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any()); mService.setBooted(true); @@ -438,7 +473,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { mRootWindowContainer.resumeFocusedStacksTopActivities(); // Verify that home activity was started on the default display - verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(DEFAULT_DISPLAY)); + verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea)); } /** @@ -575,8 +610,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */); try { - verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), - anyInt()); + verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any()); } finally { mRootWindowContainer.mCurrentUser = currentUser; } @@ -596,7 +630,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome", secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */); - verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), anyInt()); + verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any()); } /** @@ -634,7 +668,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Run the test. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer - .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); + .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/); assertEquals(aInfoSecondary.name, resolvedInfo.first.name); assertEquals(aInfoSecondary.applicationInfo.packageName, @@ -665,7 +699,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Run the test. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer - .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); + .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); assertEquals(aInfoSecondary.name, resolvedInfo.first.name); assertEquals(aInfoSecondary.applicationInfo.packageName, resolvedInfo.first.applicationInfo.packageName); @@ -686,7 +720,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Run the test. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer - .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); + .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/); assertEquals(aInfoSecondary.name, resolvedInfo.first.name); assertEquals(aInfoSecondary.applicationInfo.packageName, @@ -718,7 +752,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Run the test. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer - .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); + .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); assertEquals(aInfoPrimary.name, resolvedInfo.first.name); assertEquals(aInfoPrimary.applicationInfo.packageName, resolvedInfo.first.applicationInfo.packageName); @@ -752,7 +786,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Use the first one of matched activities in the same package as selected primary home. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer - .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); + .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); assertEquals(infoFake1.activityInfo.applicationInfo.packageName, resolvedInfo.first.applicationInfo.packageName); @@ -862,7 +896,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { .getSecondaryHomeIntent(null /* preferredPackage */); final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false); doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer) - .resolveSecondaryHomeActivity(anyInt(), anyInt()); + .resolveSecondaryHomeActivity(anyInt(), any()); } private ActivityInfo getFakeHomeActivityInfo(boolean primaryHome) { diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 673469474709..e47792f4920c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -243,6 +243,26 @@ public class SizeCompatTests extends ActivityTestsBase { } @Test + public void testAspectRatioMatchParentBoundsAndImeAttachable() { + setUpApp(new TestDisplayContent.Builder(mService, 1000, 2000) + .setSystemDecorations(true).build()); + prepareUnresizable(2f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); + assertFitted(); + + rotateDisplay(mActivity.mDisplayContent, ROTATION_90); + mActivity.mDisplayContent.mInputMethodTarget = addWindowToActivity(mActivity); + // Because the aspect ratio of display doesn't exceed the max aspect ratio of activity. + // The activity should still fill its parent container and IME can attach to the activity. + assertTrue(mActivity.matchParentBounds()); + assertTrue(mActivity.mDisplayContent.isImeAttachedToApp()); + + final Rect letterboxInnerBounds = new Rect(); + mActivity.getLetterboxInnerBounds(letterboxInnerBounds); + // The activity should not have letterbox. + assertTrue(letterboxInnerBounds.isEmpty()); + } + + @Test public void testMoveToDifferentOrientDisplay() { setUpDisplaySizeWithApp(1000, 2500); prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java index 9625ffdac052..52a51875427f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -51,10 +51,10 @@ import org.junit.Test; import org.junit.runner.RunWith; /** - * Tests for the {@link DisplayContent.TaskStackContainers} container in {@link DisplayContent}. + * Tests for the {@link TaskDisplayArea} container. * * Build/Install/Run: - * atest WmTests:TaskStackContainersTests + * atest WmTests:TaskDisplayAreaTests */ @SmallTest @Presubmit @@ -154,8 +154,9 @@ public class TaskDisplayAreaTests extends WindowTestsBase { ACTIVITY_TYPE_STANDARD, mDisplayContent); final Task newStack = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent); - doReturn(newStack).when(mDisplayContent.mTaskContainers).createStack(anyInt(), - anyInt(), anyBoolean(), any(), any(), anyBoolean()); + final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea(); + doReturn(newStack).when(taskDisplayArea).createStack(anyInt(), anyInt(), anyBoolean(), + any(), any(), anyBoolean()); final int type = ACTIVITY_TYPE_STANDARD; assertGetOrCreateStack(WINDOWING_MODE_FULLSCREEN, type, candidateTask, @@ -171,7 +172,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { assertGetOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, type, candidateTask, false /* reuseCandidate */); assertGetOrCreateStack(WINDOWING_MODE_PINNED, type, candidateTask, - false /* reuseCandidate */); + true /* reuseCandidate */); final int windowingMode = WINDOWING_MODE_FULLSCREEN; assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_HOME, candidateTask, @@ -186,7 +187,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { private void assertGetOrCreateStack(int windowingMode, int activityType, Task candidateTask, boolean reuseCandidate) { - final TaskDisplayArea taskDisplayArea = (TaskDisplayArea) candidateTask.getParent(); + final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea(); final ActivityStack stack = taskDisplayArea.getOrCreateStack(windowingMode, activityType, false /* onTop */, null /* intent */, candidateTask /* candidateTask */); assertEquals(reuseCandidate, stack == candidateTask); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java index 2ce9c2b9ced0..e41d4dcdb186 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java @@ -50,6 +50,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackInfo; import android.app.IRequestFinishCallback; @@ -69,6 +70,8 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -117,6 +120,13 @@ public class TaskOrganizerTests extends WindowTestsBase { return createTaskStackOnDisplay(mDisplayContent); } + @Before + public void setUp() { + // We defer callbacks since we need to adjust task surface visibility, but for these tests, + // just run the callbacks synchronously + mWm.mAtmService.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer((r) -> r.run()); + } + @Test public void testAppearVanish() throws RemoteException { final ActivityStack stack = createStack(); @@ -192,6 +202,21 @@ public class TaskOrganizerTests extends WindowTestsBase { } @Test + public void testTaskNoDraw() throws RemoteException { + final ActivityStack stack = createStack(); + final Task task = createTask(stack, false /* fakeDraw */); + final ITaskOrganizer organizer = registerMockOrganizer(); + + stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + verify(organizer, never()).onTaskAppeared(any()); + assertTrue(stack.isOrganized()); + + mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer); + verify(organizer, never()).onTaskVanished(any()); + assertFalse(stack.isOrganized()); + } + + @Test public void testClearOrganizer() throws RemoteException { final ActivityStack stack = createStack(); final Task task = createTask(stack); @@ -832,6 +857,30 @@ public class TaskOrganizerTests extends WindowTestsBase { } @Test + public void testChangeTaskDescription() { + class ChangeSavingOrganizer extends StubOrganizer { + RunningTaskInfo mChangedInfo; + @Override + public void onTaskInfoChanged(RunningTaskInfo info) { + mChangedInfo = info; + } + } + ChangeSavingOrganizer o = new ChangeSavingOrganizer(); + mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o, + WINDOWING_MODE_MULTI_WINDOW); + + final ActivityStack stack = createStack(); + final Task task = createTask(stack); + final ActivityRecord record = WindowTestUtils.createActivityRecordInTask( + stack.mDisplayContent, task); + + stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription")); + waitUntilHandlersIdle(); + assertEquals("TestDescription", o.mChangedInfo.taskDescription.getLabel()); + } + + @Test public void testPreventDuplicateAppear() throws RemoteException { final ActivityStack stack = createStack(); final Task task = createTask(stack); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java index 18737c2b4bb7..d2a2732d60ab 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java @@ -43,7 +43,9 @@ class TestDisplayContent extends DisplayContent { // hard-code to FULLSCREEN for tests. setWindowingMode(WINDOWING_MODE_FULLSCREEN); spyOn(this); - spyOn(mTaskContainers); + for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) { + spyOn(getTaskDisplayAreaAt(i)); + } final DisplayRotation displayRotation = getDisplayRotation(); spyOn(displayRotation); @@ -137,6 +139,7 @@ class TestDisplayContent extends DisplayContent { spyOn(displayPolicy); if (mSystemDecorations) { doReturn(true).when(newDisplay).supportsSystemDecorations(); + doReturn(true).when(displayPolicy).hasNavigationBar(); } else { doReturn(false).when(displayPolicy).hasNavigationBar(); doReturn(false).when(displayPolicy).hasStatusBar(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index 7a075a26cb31..4a8e8dafb57d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -120,8 +120,8 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { IWindow iWindow = mock(IWindow.class); doReturn(mock(IBinder.class)).when(iWindow).asBinder(); window = WindowTestsBase.createWindow(null, TYPE_APPLICATION_STARTING, activity, - "Starting window", 0 /* ownerId */, false /* internalWindows */, wm, - mock(Session.class), iWindow, mPowerManagerWrapper); + "Starting window", 0 /* ownerId */, 0 /* userId*/, false /* internalWindows */, + wm, mock(Session.class), iWindow, mPowerManagerWrapper); activity.startingWindow = window; } if (mRunnableWhenAddingSplashScreen != null) { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java index b8de3ca4ea1c..ee210b6eeaee 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; +import static org.mockito.ArgumentMatchers.any; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -49,6 +50,7 @@ public class WindowContainerThumbnailTest extends WindowTestsBase { GraphicBuffer.USAGE_SW_READ_RARELY | GraphicBuffer.USAGE_SW_WRITE_NEVER); final ActivityRecord mockAr = mock(ActivityRecord.class); when(mockAr.getPendingTransaction()).thenReturn(new StubTransaction()); + when(mockAr.makeChildSurface(any())).thenReturn(new MockSurfaceControlBuilder()); when(mockAr.makeSurface()).thenReturn(new MockSurfaceControlBuilder()); return new WindowContainerThumbnail(new StubTransaction(), mockAr, buffer, false, mock(Surface.class), mock(SurfaceAnimator.class)); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java index da4bde59a09e..79b9ae1b902a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -16,13 +16,18 @@ package com.android.server.wm; +import static android.os.Process.INVALID_UID; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import android.content.pm.PackageManager; import android.os.IBinder; @@ -85,4 +90,19 @@ public class WindowManagerServiceTests extends WindowTestsBase { assertFalse(windowToken.mRoundedCornerOverlay); assertTrue(windowToken.mFromClientToken); } + + @Test(expected = SecurityException.class) + public void testRemoveWindowToken_ownerUidNotMatch_throwException() { + IBinder token = mock(IBinder.class); + mWm.addWindowTokenWithOptions(token, TYPE_TOAST, mDisplayContent.getDisplayId(), + null /* options */, null /* options */); + + spyOn(mWm); + when(mWm.checkCallingPermission(anyString(), anyString())).thenReturn(false); + WindowToken windowToken = mWm.mRoot.getWindowToken(token); + spyOn(windowToken); + when(windowToken.getOwnerUid()).thenReturn(INVALID_UID); + + mWm.removeWindowToken(token, mDisplayContent.getDisplayId()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index 084216a9a543..fc95556750f1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -112,7 +112,7 @@ class WindowTestUtils { TestWindowState(WindowManagerService service, Session session, IWindow window, WindowManager.LayoutParams attrs, WindowToken token) { - super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, + super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, 0, false /* ownerCanAddInternalSystemWindow */); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 1ca2e318b0d7..e561c13a4e99 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -41,6 +41,7 @@ import static org.mockito.Mockito.mock; import android.content.Context; import android.content.Intent; +import android.os.UserHandle; import android.util.Log; import android.view.Display; import android.view.DisplayInfo; @@ -134,6 +135,7 @@ class WindowTestsBase extends SystemServiceTestsBase { mChildAppWindowBelow = createCommonWindow(mAppWindow, TYPE_APPLICATION_MEDIA_OVERLAY, "mChildAppWindowBelow"); + mDisplayContent.getDisplayPolicy().setForceShowSystemBars(false); } // Adding a display will cause freezing the display. Make sure to wait until it's @@ -295,12 +297,13 @@ class WindowTestsBase extends SystemServiceTestsBase { WindowState createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId, boolean ownerCanAddInternalSystemWindow) { - return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow, - mWm, mMockSession, mIWindow, mSystemServicesTestRule.getPowerManagerWrapper()); + return createWindow(parent, type, token, name, ownerId, UserHandle.getUserId(ownerId), + ownerCanAddInternalSystemWindow, mWm, mMockSession, mIWindow, + mSystemServicesTestRule.getPowerManagerWrapper()); } static WindowState createWindow(WindowState parent, int type, WindowToken token, - String name, int ownerId, boolean ownerCanAddInternalSystemWindow, + String name, int ownerId, int userId, boolean ownerCanAddInternalSystemWindow, WindowManagerService service, Session session, IWindow iWindow, WindowState.PowerManagerWrapper powerManagerWrapper) { synchronized (service.mGlobalLock) { @@ -308,8 +311,8 @@ class WindowTestsBase extends SystemServiceTestsBase { attrs.setTitle(name); final WindowState w = new WindowState(service, session, iWindow, token, parent, - OP_NONE, - 0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow, + OP_NONE, 0, attrs, VISIBLE, ownerId, userId, + ownerCanAddInternalSystemWindow, powerManagerWrapper); // TODO: Probably better to make this call in the WindowState ctor to avoid errors with // adding it to the token... diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index 7a347cb050be..535d53eeef71 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.os.Process.INVALID_UID; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; @@ -28,6 +29,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; +import android.content.res.Configuration; import android.os.IBinder; import android.platform.test.annotations.Presubmit; @@ -133,6 +135,30 @@ public class WindowTokenTests extends WindowTestsBase { assertEquals(0, token.getWindowsCount()); } + @Test + public void testClearFixedRotationTransform() { + final WindowToken appToken = mAppWindow.mToken; + final WindowToken wallpaperToken = mWallpaperWindow.mToken; + final Configuration config = new Configuration(mDisplayContent.getConfiguration()); + final int originalRotation = config.windowConfiguration.getRotation(); + final int targetRotation = (originalRotation + 1) % 4; + + config.windowConfiguration.setRotation(targetRotation); + appToken.applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); + wallpaperToken.linkFixedRotationTransform(appToken); + + // The window tokens should apply the rotation by the transformation. + assertEquals(targetRotation, appToken.getWindowConfiguration().getRotation()); + assertEquals(targetRotation, wallpaperToken.getWindowConfiguration().getRotation()); + + // The display doesn't rotate, the transformation will be canceled. + mAppWindow.mToken.clearFixedRotationTransform(null /* applyDisplayRotation */); + + // The window tokens should restore to the original rotation. + assertEquals(originalRotation, appToken.getWindowConfiguration().getRotation()); + assertEquals(originalRotation, wallpaperToken.getWindowConfiguration().getRotation()); + } + /** * Test that {@link WindowToken} constructor parameters is set with expectation. */ @@ -152,7 +178,7 @@ public class WindowTokenTests extends WindowTestsBase { token = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class), TYPE_TOAST, true /* persistOnEmpty */, mDisplayContent, true /* ownerCanManageAppTokens */, - true /* roundedCornerOverlay */, true /* fromClientToken */); + INVALID_UID, true /* roundedCornerOverlay */, true /* fromClientToken */); assertTrue(token.mRoundedCornerOverlay); assertTrue(token.mFromClientToken); } @@ -166,7 +192,7 @@ public class WindowTokenTests extends WindowTestsBase { public void testSurfaceCreatedForWindowToken() { final WindowToken fromClientToken = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class), TYPE_APPLICATION_OVERLAY, true /* persistOnEmpty */, - mDisplayContent, true /* ownerCanManageAppTokens */, + mDisplayContent, true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */, true /* fromClientToken */); assertNull(fromClientToken.mSurfaceControl); @@ -175,7 +201,7 @@ public class WindowTokenTests extends WindowTestsBase { final WindowToken nonClientToken = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class), TYPE_TOAST, true /* persistOnEmpty */, mDisplayContent, - true /* ownerCanManageAppTokens */, true /* roundedCornerOverlay */, + true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */, false /* fromClientToken */); assertNotNull(nonClientToken.mSurfaceControl); } diff --git a/startop/iorap/functional_tests/Android.bp b/startop/iorap/functional_tests/Android.bp index ad85f1430bdf..8a5bd34af653 100644 --- a/startop/iorap/functional_tests/Android.bp +++ b/startop/iorap/functional_tests/Android.bp @@ -15,7 +15,7 @@ android_test { name: "iorap-functional-tests", srcs: ["src/**/*.java"], - data: ["test_data/*"], + data: [":iorap-functional-test-apps"], static_libs: [ // Non-test dependencies // library under test diff --git a/startop/iorap/functional_tests/test_data/iorap_test_app_v1.apk b/startop/iorap/functional_tests/test_data/iorap_test_app_v1.apk deleted file mode 120000 index 1c1a437f6a55..000000000000 --- a/startop/iorap/functional_tests/test_data/iorap_test_app_v1.apk +++ /dev/null @@ -1 +0,0 @@ -../../../../../../packages/modules/ArtPrebuilt/iorap/test/iorap_test_app_v1.apk
\ No newline at end of file diff --git a/startop/iorap/functional_tests/test_data/iorap_test_app_v2.apk b/startop/iorap/functional_tests/test_data/iorap_test_app_v2.apk deleted file mode 120000 index 7cd41c48ba3a..000000000000 --- a/startop/iorap/functional_tests/test_data/iorap_test_app_v2.apk +++ /dev/null @@ -1 +0,0 @@ -../../../../../../packages/modules/ArtPrebuilt/iorap/test/iorap_test_app_v2.apk
\ No newline at end of file diff --git a/startop/iorap/functional_tests/test_data/iorap_test_app_v3.apk b/startop/iorap/functional_tests/test_data/iorap_test_app_v3.apk deleted file mode 120000 index 7f4e996e57d0..000000000000 --- a/startop/iorap/functional_tests/test_data/iorap_test_app_v3.apk +++ /dev/null @@ -1 +0,0 @@ -../../../../../../packages/modules/ArtPrebuilt/iorap/test/iorap_test_app_v3.apk
\ No newline at end of file diff --git a/startop/iorap/src/com/google/android/startop/iorap/DexOptEvent.java b/startop/iorap/src/com/google/android/startop/iorap/DexOptEvent.java new file mode 100644 index 000000000000..72c5eaa84c96 --- /dev/null +++ b/startop/iorap/src/com/google/android/startop/iorap/DexOptEvent.java @@ -0,0 +1,114 @@ +/* + * 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.google.android.startop.iorap; + +import android.annotation.NonNull; +import android.os.Parcelable; +import android.os.Parcel; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Notifications for iorapd specifying when a package is updated by dexopt service.<br /><br /> + * + * @hide + */ +public class DexOptEvent implements Parcelable { + public static final int TYPE_PACKAGE_UPDATE = 0; + private static final int TYPE_MAX = 0; + + /** @hide */ + @IntDef(flag = true, prefix = { "TYPE_" }, value = { + TYPE_PACKAGE_UPDATE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Type {} + + @Type public final int type; + public final String packageName; + + @NonNull + public static DexOptEvent createPackageUpdate(String packageName) { + return new DexOptEvent(TYPE_PACKAGE_UPDATE, packageName); + } + + private DexOptEvent(@Type int type, String packageName) { + this.type = type; + this.packageName = packageName; + + checkConstructorArguments(); + } + + private void checkConstructorArguments() { + CheckHelpers.checkTypeInRange(type, TYPE_MAX); + Objects.requireNonNull(packageName, "packageName"); + } + + @Override + public String toString() { + return String.format("{DexOptEvent: packageName: %s}", packageName); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } else if (other instanceof DexOptEvent) { + return equals((DexOptEvent) other); + } + return false; + } + + private boolean equals(DexOptEvent other) { + return packageName.equals(other.packageName); + } + + //<editor-fold desc="Binder boilerplate"> + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(type); + out.writeString(packageName); + } + + private DexOptEvent(Parcel in) { + this.type = in.readInt(); + this.packageName = in.readString(); + + checkConstructorArguments(); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<DexOptEvent> CREATOR + = new Parcelable.Creator<DexOptEvent>() { + public DexOptEvent createFromParcel(Parcel in) { + return new DexOptEvent(in); + } + + public DexOptEvent[] newArray(int size) { + return new DexOptEvent[size]; + } + }; + //</editor-fold> +} diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java index d5851d85345f..8f1d0addbcd8 100644 --- a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java +++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java @@ -34,18 +34,21 @@ import android.os.Parcel; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; +import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.server.IoThread; import com.android.server.LocalServices; import com.android.server.SystemService; +import com.android.server.pm.BackgroundDexOptService; import com.android.server.wm.ActivityMetricsLaunchObserver; import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto; import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature; import com.android.server.wm.ActivityMetricsLaunchObserverRegistry; import com.android.server.wm.ActivityTaskManagerInternal; +import java.util.ArrayList; import java.util.concurrent.TimeUnit; import java.util.HashMap; @@ -286,6 +289,7 @@ public class IorapForwardingService extends SystemService { private final AppLaunchObserver mAppLaunchObserver = new AppLaunchObserver(); private final EventSequenceValidator mEventSequenceValidator = new EventSequenceValidator(); + private final DexOptPackagesUpdated mDexOptPackagesUpdated = new DexOptPackagesUpdated(); private boolean mRegisteredListeners = false; private void registerInProcessListenersLocked() { @@ -308,9 +312,27 @@ public class IorapForwardingService extends SystemService { launchObserverRegistry.registerLaunchObserver(mAppLaunchObserver); launchObserverRegistry.registerLaunchObserver(mEventSequenceValidator); + BackgroundDexOptService.addPackagesUpdatedListener(mDexOptPackagesUpdated); + + mRegisteredListeners = true; } + private class DexOptPackagesUpdated implements BackgroundDexOptService.PackagesUpdatedListener { + @Override + public void onPackagesUpdated(ArraySet<String> updatedPackages) { + String[] updated = updatedPackages.toArray(new String[0]); + for (String packageName : updated) { + Log.d(TAG, "onPackagesUpdated: " + packageName); + invokeRemote(mIorapRemote, + (IIorap remote) -> + remote.onDexOptEvent(RequestId.nextValueForSequence(), + DexOptEvent.createPackageUpdate(packageName)) + ); + } + } + } + private class AppLaunchObserver implements ActivityMetricsLaunchObserver { // We add a synthetic sequence ID here to make it easier to differentiate new // launch sequences on the native side. diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index f019a9d33005..d9605522b3b0 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -74,6 +74,7 @@ public abstract class Conference extends Conferenceable { public void onConnectionEvent(Conference c, String event, Bundle extras) {} public void onCallerDisplayNameChanged( Conference c, String callerDisplayName, int presentation) {} + public void onCallDirectionChanged(Conference c, int callDirection) {} public void onRingbackRequested(Conference c, boolean ringback) {} } @@ -103,7 +104,9 @@ public abstract class Conference extends Conferenceable { private int mAddressPresentation; private String mCallerDisplayName; private int mCallerDisplayNamePresentation; + private int mCallDirection; private boolean mRingbackRequested = false; + private boolean mIsMultiparty = true; private final Connection.Listener mConnectionDeathListener = new Connection.Listener() { @Override @@ -996,8 +999,8 @@ public abstract class Conference extends Conferenceable { public void onExtrasChanged(Bundle extras) {} /** - * Set whether Telecom should treat this {@link Conference} as a conference call or if it - * should treat it as a single-party call. + * Set whether Telecom should treat this {@link Conference} as a multiparty conference call or + * if it should treat it as a single-party call. * This method is used as part of a workaround regarding IMS conference calls and user * expectation. In IMS, once a conference is formed, the UE is connected to an IMS conference * server. If all participants of the conference drop out of the conference except for one, the @@ -1018,12 +1021,46 @@ public abstract class Conference extends Conferenceable { @TestApi @RequiresPermission(MODIFY_PHONE_STATE) public void setConferenceState(boolean isConference) { + mIsMultiparty = isConference; for (Listener l : mListeners) { l.onConferenceStateChanged(this, isConference); } } /** + * Sets the call direction of this {@link Conference}. By default, all {@link Conference}s have + * a direction of {@link android.telecom.Call.Details.CallDirection#DIRECTION_UNKNOWN}. The + * direction of a {@link Conference} is only applicable to the case where + * {@link #setConferenceState(boolean)} has been set to {@code false}, otherwise the direction + * will be ignored. + * @param callDirection The direction of the conference. + * @hide + */ + @RequiresPermission(MODIFY_PHONE_STATE) + public final void setCallDirection(@Call.Details.CallDirection int callDirection) { + Log.d(this, "setDirection %d", callDirection); + mCallDirection = callDirection; + for (Listener l : mListeners) { + l.onCallDirectionChanged(this, callDirection); + } + } + + /** + * Determines if the {@link Conference} is considered "multiparty" or not. By default all + * conferences are considered multiparty. A multiparty conference is one where there are + * multiple conference participants (other than the host) in the conference. + * This is tied to {@link #setConferenceState(boolean)}, which is used for some use cases to + * have a conference appear as if it is a standalone call, in which case the conference will + * no longer be multiparty. + * @return {@code true} if conference is treated as a conference (i.e. it is multiparty), + * {@code false} if it should emulate a standalone call (i.e. not multiparty). + * @hide + */ + public boolean isMultiparty() { + return mIsMultiparty; + } + + /** * Sets the address of this {@link Conference}. Used when {@link #setConferenceState(boolean)} * is called to mark a conference temporarily as NOT a conference. * <p> @@ -1071,16 +1108,16 @@ public abstract class Conference extends Conferenceable { * This is applicable in two cases: * <ol> * <li>When {@link #setConferenceState(boolean)} is used to mark a conference as - * temporarily "not a conference"; we need to present the correct address in the in-call - * UI.</li> + * temporarily "not a conference"; we need to present the correct address presentation in + * the in-call UI.</li> * <li>When the conference is not hosted on the current device, we need to know the address - * information for the purpose of showing the original address to the user, as well as for - * logging to the call log.</li> + * presentation information for the purpose of showing the original address to the user, as + * well as for logging to the call log.</li> * </ol> - * @return The address of the conference, or {@code null} if not applicable. + * @return The address presentation of the conference. * @hide */ - public final int getAddressPresentation() { + public final @TelecomManager.Presentation int getAddressPresentation() { return mAddressPresentation; } @@ -1102,6 +1139,15 @@ public abstract class Conference extends Conferenceable { } /** + * @return The call direction of this conference. Only applicable when + * {@link #setConferenceState(boolean)} is set to false. + * @hide + */ + public final @Call.Details.CallDirection int getCallDirection() { + return mCallDirection; + } + + /** * Sets the caller display name (CNAP) of this {@link Conference}. Used when * {@link #setConferenceState(boolean)} is called to mark a conference temporarily as NOT a * conference. diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index ffd25c08a8ba..1b60e4820ad0 100755 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -1554,6 +1554,14 @@ public abstract class ConnectionService extends Service { } @Override + public void onCallDirectionChanged(Conference c, int direction) { + String id = mIdByConference.get(c); + if (id != null) { + mAdapter.setCallDirection(id, direction); + } + } + + @Override public void onAddressChanged(Conference c, Uri newAddress, int presentation) { String id = mIdByConference.get(c); if (id != null) { @@ -1857,25 +1865,23 @@ public abstract class ConnectionService extends Service { mConferenceById.put(callId, conference); mIdByConference.put(conference, callId); conference.addListener(mConferenceListener); - ParcelableConference parcelableConference = new ParcelableConference( - request.getAccountHandle(), - conference.getState(), - conference.getConnectionCapabilities(), - conference.getConnectionProperties(), - Collections.<String>emptyList(), //connectionIds - conference.getVideoProvider() == null ? - null : conference.getVideoProvider().getInterface(), - conference.getVideoState(), - conference.getConnectTimeMillis(), - conference.getConnectionStartElapsedRealtimeMillis(), - conference.getStatusHints(), - conference.getExtras(), - conference.getAddress(), - conference.getAddressPresentation(), - conference.getCallerDisplayName(), - conference.getCallerDisplayNamePresentation(), - conference.getDisconnectCause(), - conference.isRingbackRequested()); + ParcelableConference parcelableConference = new ParcelableConference.Builder( + request.getAccountHandle(), conference.getState()) + .setConnectionCapabilities(conference.getConnectionCapabilities()) + .setConnectionProperties(conference.getConnectionProperties()) + .setVideoAttributes(conference.getVideoProvider() == null + ? null : conference.getVideoProvider().getInterface(), + conference.getVideoState()) + .setConnectTimeMillis(conference.getConnectTimeMillis(), + conference.getConnectionStartElapsedRealtimeMillis()) + .setStatusHints(conference.getStatusHints()) + .setExtras(conference.getExtras()) + .setAddress(conference.getAddress(), conference.getAddressPresentation()) + .setCallerDisplayName(conference.getCallerDisplayName(), + conference.getCallerDisplayNamePresentation()) + .setDisconnectCause(conference.getDisconnectCause()) + .setRingbackRequested(conference.isRingbackRequested()) + .build(); if (conference.getState() != Connection.STATE_DISCONNECTED) { conference.setTelecomCallId(callId); mAdapter.setVideoProvider(callId, conference.getVideoProvider()); @@ -2476,27 +2482,34 @@ public abstract class ConnectionService extends Service { } } conference.setTelecomCallId(id); - ParcelableConference parcelableConference = new ParcelableConference( - conference.getPhoneAccountHandle(), - conference.getState(), - conference.getConnectionCapabilities(), - conference.getConnectionProperties(), - connectionIds, - conference.getVideoProvider() == null ? - null : conference.getVideoProvider().getInterface(), - conference.getVideoState(), - conference.getConnectTimeMillis(), - conference.getConnectionStartElapsedRealtimeMillis(), - conference.getStatusHints(), - conference.getExtras(), - conference.getAddress(), - conference.getAddressPresentation(), - conference.getCallerDisplayName(), - conference.getCallerDisplayNamePresentation()); + ParcelableConference parcelableConference = new ParcelableConference.Builder( + conference.getPhoneAccountHandle(), conference.getState()) + .setConnectionCapabilities(conference.getConnectionCapabilities()) + .setConnectionProperties(conference.getConnectionProperties()) + .setConnectionIds(connectionIds) + .setVideoAttributes(conference.getVideoProvider() == null + ? null : conference.getVideoProvider().getInterface(), + conference.getVideoState()) + .setConnectTimeMillis(conference.getConnectTimeMillis(), + conference.getConnectionStartElapsedRealtimeMillis()) + .setStatusHints(conference.getStatusHints()) + .setExtras(conference.getExtras()) + .setAddress(conference.getAddress(), conference.getAddressPresentation()) + .setCallerDisplayName(conference.getCallerDisplayName(), + conference.getCallerDisplayNamePresentation()) + .setDisconnectCause(conference.getDisconnectCause()) + .setRingbackRequested(conference.isRingbackRequested()) + .setCallDirection(conference.getCallDirection()) + .build(); mAdapter.addConferenceCall(id, parcelableConference); mAdapter.setVideoProvider(id, conference.getVideoProvider()); mAdapter.setVideoState(id, conference.getVideoState()); + // In some instances a conference can start its life as a standalone call with just a + // single participant; ensure we signal to Telecom in this case. + if (!conference.isMultiparty()) { + mAdapter.setConferenceState(id, conference.isMultiparty()); + } // Go through any child calls and set the parent. for (Connection connection : conference.getConnections()) { diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java index 8f273233044e..f8a6cf03934a 100644 --- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java +++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java @@ -693,4 +693,20 @@ final class ConnectionServiceAdapter implements DeathRecipient { } } } + + /** + * Sets the direction of a call. Setting a new direction of an existing call is usually only + * applicable during single caller emulation during conferencing, see + * {@link Conference#setConferenceState(boolean)} for more information. + * @param callId The identifier of the call. + * @param direction The new direction of the call. + */ + void setCallDirection(String callId, @Call.Details.CallDirection int direction) { + for (IConnectionServiceAdapter a : mAdapters) { + try { + a.setCallDirection(callId, direction, Log.getExternalSession()); + } catch (RemoteException e) { + } + } + } } diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java index 79ad51b92b81..6c1ea322e66e 100644 --- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java +++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java @@ -76,6 +76,7 @@ final class ConnectionServiceAdapterServant { private static final int MSG_CONNECTION_SERVICE_FOCUS_RELEASED = 35; private static final int MSG_SET_CONFERENCE_STATE = 36; private static final int MSG_HANDLE_CREATE_CONFERENCE_COMPLETE = 37; + private static final int MSG_SET_CALL_DIRECTION = 38; private final IConnectionServiceAdapter mDelegate; @@ -353,7 +354,7 @@ final class ConnectionServiceAdapterServant { case MSG_CONNECTION_SERVICE_FOCUS_RELEASED: mDelegate.onConnectionServiceFocusReleased(null /*Session.Info*/); break; - case MSG_SET_CONFERENCE_STATE: + case MSG_SET_CONFERENCE_STATE: { SomeArgs args = (SomeArgs) msg.obj; try { mDelegate.setConferenceState((String) args.arg1, (Boolean) args.arg2, @@ -361,6 +362,17 @@ final class ConnectionServiceAdapterServant { } finally { args.recycle(); } + break; + } + case MSG_SET_CALL_DIRECTION: { + SomeArgs args = (SomeArgs) msg.obj; + try { + mDelegate.setCallDirection((String) args.arg1, args.argi1, + (Session.Info) args.arg2); + } finally { + args.recycle(); + } + } } } }; @@ -670,6 +682,16 @@ final class ConnectionServiceAdapterServant { args.arg3 = sessionInfo; mHandler.obtainMessage(MSG_SET_CONFERENCE_STATE, args).sendToTarget(); } + + @Override + public void setCallDirection(String callId, int direction, + Session.Info sessionInfo) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = callId; + args.argi1 = direction; + args.arg2 = sessionInfo; + mHandler.obtainMessage(MSG_SET_CALL_DIRECTION, args).sendToTarget(); + } }; public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) { diff --git a/telecomm/java/android/telecom/GatewayInfo.java b/telecomm/java/android/telecom/GatewayInfo.java index 0faa4fd2027a..31c24d54918a 100644 --- a/telecomm/java/android/telecom/GatewayInfo.java +++ b/telecomm/java/android/telecom/GatewayInfo.java @@ -111,7 +111,7 @@ public class GatewayInfo implements Parcelable { @Override public void writeToParcel(Parcel destination, int flags) { destination.writeString(mGatewayProviderPackageName); - mGatewayAddress.writeToParcel(destination, 0); - mOriginalAddress.writeToParcel(destination, 0); + Uri.writeToParcel(destination, mGatewayAddress); + Uri.writeToParcel(destination, mOriginalAddress); } } diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index 415a817b58d5..182dc8bb8325 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -629,7 +629,7 @@ public final class ParcelableCall implements Parcelable { int capabilities = source.readInt(); int properties = source.readInt(); long connectTimeMillis = source.readLong(); - Uri handle = source.readParcelable(classLoader); + Uri handle = Uri.CREATOR.createFromParcel(source); int handlePresentation = source.readInt(); String callerDisplayName = source.readString(); int callerDisplayNamePresentation = source.readInt(); @@ -711,7 +711,7 @@ public final class ParcelableCall implements Parcelable { destination.writeInt(mCapabilities); destination.writeInt(mProperties); destination.writeLong(mConnectTimeMillis); - destination.writeParcelable(mHandle, 0); + Uri.writeToParcel(destination, mHandle); destination.writeInt(mHandlePresentation); destination.writeString(mCallerDisplayName); destination.writeInt(mCallerDisplayNamePresentation); diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java index 90b69a338c7e..1f8aafbca476 100644 --- a/telecomm/java/android/telecom/ParcelableConference.java +++ b/telecomm/java/android/telecom/ParcelableConference.java @@ -22,6 +22,7 @@ import android.os.Parcel; import android.os.Parcelable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import com.android.internal.telecom.IVideoProvider; @@ -32,25 +33,130 @@ import com.android.internal.telecom.IVideoProvider; */ public final class ParcelableConference implements Parcelable { - private PhoneAccountHandle mPhoneAccount; - private int mState; - private int mConnectionCapabilities; - private int mConnectionProperties; - private List<String> mConnectionIds; - private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; + public static final class Builder { + private final PhoneAccountHandle mPhoneAccount; + private final int mState; + private int mConnectionCapabilities; + private int mConnectionProperties; + private List<String> mConnectionIds = Collections.emptyList(); + private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; + private IVideoProvider mVideoProvider; + private int mVideoState = VideoProfile.STATE_AUDIO_ONLY; + private StatusHints mStatusHints; + private Bundle mExtras; + private long mConnectElapsedTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; + private Uri mAddress; + private int mAddressPresentation = TelecomManager.PRESENTATION_UNKNOWN; + private String mCallerDisplayName; + private int mCallerDisplayNamePresentation = TelecomManager.PRESENTATION_UNKNOWN;; + private DisconnectCause mDisconnectCause; + private boolean mRingbackRequested; + private int mCallDirection = Call.Details.DIRECTION_UNKNOWN; + + public Builder( + PhoneAccountHandle phoneAccount, + int state) { + mPhoneAccount = phoneAccount; + mState = state; + } + + public Builder setDisconnectCause(DisconnectCause cause) { + mDisconnectCause = cause; + return this; + } + + public Builder setRingbackRequested(boolean requested) { + mRingbackRequested = requested; + return this; + } + + public Builder setCallerDisplayName(String callerDisplayName, + @TelecomManager.Presentation int callerDisplayNamePresentation) { + mCallerDisplayName = callerDisplayName; + mCallerDisplayNamePresentation = callerDisplayNamePresentation; + return this; + } + + public Builder setAddress(Uri address, + @TelecomManager.Presentation int addressPresentation) { + mAddress = address; + mAddressPresentation = addressPresentation; + return this; + } + + public Builder setExtras(Bundle extras) { + mExtras = extras; + return this; + } + + public Builder setStatusHints(StatusHints hints) { + mStatusHints = hints; + return this; + } + + public Builder setConnectTimeMillis(long connectTimeMillis, long connectElapsedTimeMillis) { + mConnectTimeMillis = connectTimeMillis; + mConnectElapsedTimeMillis = connectElapsedTimeMillis; + return this; + } + + public Builder setVideoAttributes(IVideoProvider provider, + @VideoProfile.VideoState int videoState) { + mVideoProvider = provider; + mVideoState = videoState; + return this; + } + + public Builder setConnectionIds(List<String> connectionIds) { + mConnectionIds = connectionIds; + return this; + } + + public Builder setConnectionProperties(int properties) { + mConnectionProperties = properties; + return this; + } + + public Builder setConnectionCapabilities(int capabilities) { + mConnectionCapabilities = capabilities; + return this; + } + + public Builder setCallDirection(int callDirection) { + mCallDirection = callDirection; + return this; + } + + public ParcelableConference build() { + return new ParcelableConference(mPhoneAccount, mState, mConnectionCapabilities, + mConnectionProperties, mConnectionIds, mVideoProvider, mVideoState, + mConnectTimeMillis, mConnectElapsedTimeMillis, mStatusHints, mExtras, mAddress, + mAddressPresentation, mCallerDisplayName, mCallerDisplayNamePresentation, + mDisconnectCause, mRingbackRequested, mCallDirection); + } + } + + + private final PhoneAccountHandle mPhoneAccount; + private final int mState; + private final int mConnectionCapabilities; + private final int mConnectionProperties; + private final List<String> mConnectionIds; + private final long mConnectTimeMillis; private final IVideoProvider mVideoProvider; private final int mVideoState; - private StatusHints mStatusHints; - private Bundle mExtras; - private long mConnectElapsedTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; + private final StatusHints mStatusHints; + private final Bundle mExtras; + private final long mConnectElapsedTimeMillis; private final Uri mAddress; private final int mAddressPresentation; private final String mCallerDisplayName; private final int mCallerDisplayNamePresentation; - private DisconnectCause mDisconnectCause; - private boolean mRingbackRequested; + private final DisconnectCause mDisconnectCause; + private final boolean mRingbackRequested; + private final int mCallDirection; - public ParcelableConference( + private ParcelableConference( PhoneAccountHandle phoneAccount, int state, int connectionCapabilities, @@ -67,31 +173,8 @@ public final class ParcelableConference implements Parcelable { String callerDisplayName, int callerDisplayNamePresentation, DisconnectCause disconnectCause, - boolean ringbackRequested) { - this(phoneAccount, state, connectionCapabilities, connectionProperties, connectionIds, - videoProvider, videoState, connectTimeMillis, connectElapsedTimeMillis, - statusHints, extras, address, addressPresentation, callerDisplayName, - callerDisplayNamePresentation); - mDisconnectCause = disconnectCause; - mRingbackRequested = ringbackRequested; - } - - public ParcelableConference( - PhoneAccountHandle phoneAccount, - int state, - int connectionCapabilities, - int connectionProperties, - List<String> connectionIds, - IVideoProvider videoProvider, - int videoState, - long connectTimeMillis, - long connectElapsedTimeMillis, - StatusHints statusHints, - Bundle extras, - Uri address, - int addressPresentation, - String callerDisplayName, - int callerDisplayNamePresentation) { + boolean ringbackRequested, + int callDirection) { mPhoneAccount = phoneAccount; mState = state; mConnectionCapabilities = connectionCapabilities; @@ -107,8 +190,9 @@ public final class ParcelableConference implements Parcelable { mAddressPresentation = addressPresentation; mCallerDisplayName = callerDisplayName; mCallerDisplayNamePresentation = callerDisplayNamePresentation; - mDisconnectCause = null; - mRingbackRequested = false; + mDisconnectCause = disconnectCause; + mRingbackRequested = ringbackRequested; + mCallDirection = callDirection; } @Override @@ -134,6 +218,8 @@ public final class ParcelableConference implements Parcelable { .append(mRingbackRequested) .append(", disconnectCause: ") .append(mDisconnectCause) + .append(", callDirection: ") + .append(mCallDirection) .toString(); } @@ -192,10 +278,15 @@ public final class ParcelableConference implements Parcelable { public boolean isRingbackRequested() { return mRingbackRequested; } + public int getHandlePresentation() { return mAddressPresentation; } + public int getCallDirection() { + return mCallDirection; + } + public static final @android.annotation.NonNull Parcelable.Creator<ParcelableConference> CREATOR = new Parcelable.Creator<ParcelableConference> () { @Override @@ -220,12 +311,13 @@ public final class ParcelableConference implements Parcelable { int callerDisplayNamePresentation = source.readInt(); DisconnectCause disconnectCause = source.readParcelable(classLoader); boolean isRingbackRequested = source.readInt() == 1; + int callDirection = source.readInt(); return new ParcelableConference(phoneAccount, state, capabilities, properties, connectionIds, videoCallProvider, videoState, connectTimeMillis, connectElapsedTimeMillis, statusHints, extras, address, addressPresentation, callerDisplayName, callerDisplayNamePresentation, disconnectCause, - isRingbackRequested); + isRingbackRequested, callDirection); } @Override @@ -261,5 +353,6 @@ public final class ParcelableConference implements Parcelable { destination.writeInt(mCallerDisplayNamePresentation); destination.writeParcelable(mDisconnectCause, 0); destination.writeInt(mRingbackRequested ? 1 : 0); + destination.writeInt(mCallDirection); } } diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java index 76640e036eeb..cad5b707a146 100644 --- a/telecomm/java/android/telecom/RemoteConnectionService.java +++ b/telecomm/java/android/telecom/RemoteConnectionService.java @@ -485,6 +485,11 @@ final class RemoteConnectionService { Session.Info sessionInfo) { // Do nothing } + + @Override + public void setCallDirection(String callId, int direction, Session.Info sessionInfo) { + // Do nothing + } }; private final ConnectionServiceAdapterServant mServant = diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index c993cfad1d05..b974c567008f 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -1534,12 +1534,22 @@ public class TelecomManager { /** * Return the line 1 phone number for given phone account. * - * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_SMS READ_SMS}, + * {@link android.Manifest.permission#READ_PHONE_NUMBERS READ_PHONE_NUMBERS}, + * or that the caller is the default SMS app for any API level. + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * for apps targeting SDK API level 29 and below. * * @param accountHandle The handle for the account retrieve a number for. * @return A string representation of the line 1 phone number. */ - @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges or default SMS app + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PHONE_STATE, + android.Manifest.permission.READ_SMS, + android.Manifest.permission.READ_PHONE_NUMBERS + }, conditional = true) public String getLine1Number(PhoneAccountHandle accountHandle) { try { if (isServiceConnected()) { diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl index 4f63e08abce6..3fd7f949cfe6 100644 --- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl @@ -132,4 +132,6 @@ oneway interface IConnectionServiceAdapter { void resetConnectionTime(String callIdi, in Session.Info sessionInfo); void setConferenceState(String callId, boolean isConference, in Session.Info sessionInfo); + + void setCallDirection(String callId, int direction, in Session.Info sessionInfo); } diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java index f3e9de0d2688..3048ad7c1fb0 100644 --- a/telephony/common/android/telephony/LocationAccessPolicy.java +++ b/telephony/common/android/telephony/LocationAccessPolicy.java @@ -311,7 +311,7 @@ public final class LocationAccessPolicy { } // If the user or profile is current, permission is granted. // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission. - return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, uid, pid); + return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context, pid, uid); } private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 327e8b344eeb..545c8a35058f 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1147,6 +1147,21 @@ public class CarrierConfigManager { "support_ims_conference_event_package_bool"; /** + * Determines whether processing of conference event package data received on a device other + * than the conference host is supported. + * <p> + * When a device A merges calls B and C into a conference it is considered the conference host + * and B and C are considered the conference peers. + * <p> + * When {@code true}, the conference peer will display the conference state if it receives + * conference event package data from the network. When {@code false}, the conference peer will + * ignore conference event package data received from the network. + * @hide + */ + public static final String KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_ON_PEER_BOOL = + "support_ims_conference_event_package_on_peer_bool"; + + /** * Determines whether High Definition audio property is displayed in the dialer UI. * If {@code false}, remove the HD audio property from the connection so that HD audio related * UI is not displayed. If {@code true}, keep HD audio property as it is configured. @@ -1163,6 +1178,25 @@ public class CarrierConfigManager { "support_ims_conference_call_bool"; /** + * Determines whether the device will locally disconnect an IMS conference when the participant + * count drops to zero. When {@code true}, it is assumed the carrier does NOT disconnect a + * conference when the participant count drops to zero and that the device must do this by + * disconnecting the conference locally. When {@code false}, it is assumed that the carrier + * is responsible for disconnecting the conference when there are no longer any participants + * present. + * <p> + * Note: both {@link #KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL} and + * {@link #KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL} must be true for this configuration to + * have any effect. + * <p> + * Defaults to {@code false}, meaning the carrier network is responsible for disconnecting an + * empty IMS conference. + * @hide + */ + public static final String KEY_LOCAL_DISCONNECT_EMPTY_IMS_CONFERENCE_BOOL = + "local_disconnect_empty_ims_conference_bool"; + + /** * Determines whether video conference calls are supported by a carrier. When {@code true}, * video calls can be merged into conference calls, {@code false} otherwiwse. * <p> @@ -2495,6 +2529,16 @@ public class CarrierConfigManager { "parameters_use_for_5g_nr_signal_bar_int"; /** + * There are two signal strengths, NR and LTE signal strength, during NR (non-standalone). + * Boolean indicating whether to use LTE signal strength as primary during NR (non-standalone). + * By default this value is true. + * + * @hide + */ + public static final String KEY_SIGNAL_STRENGTH_NR_NSA_USE_LTE_AS_PRIMARY_BOOL = + "signal_strength_nr_nsa_use_lte_as_primary_bool"; + + /** * String array of default bandwidth values per network type. * The entries should be of form "network_name:downstream,upstream", with values in Kbps. * @hide @@ -3040,6 +3084,28 @@ public class CarrierConfigManager { public static final String KEY_UNMETERED_NR_NSA_SUB6_BOOL = "unmetered_nr_nsa_sub6_bool"; /** + * Whether NR (standalone) should be unmetered for all frequencies. + * If either {@link #KEY_UNMETERED_NR_SA_MMWAVE_BOOL} or + * {@link #KEY_UNMETERED_NR_SA_SUB6_BOOL} are true, then this value will be ignored. + * @hide + */ + public static final String KEY_UNMETERED_NR_SA_BOOL = "unmetered_nr_sa_bool"; + + /** + * Whether NR (standalone) frequencies above 6GHz (millimeter wave) should be unmetered. + * If this is true, then the value for {@link #KEY_UNMETERED_NR_SA_BOOL} will be ignored. + * @hide + */ + public static final String KEY_UNMETERED_NR_SA_MMWAVE_BOOL = "unmetered_nr_sa_mmwave_bool"; + + /** + * Whether NR (standalone) frequencies below 6GHz (sub6) should be unmetered. + * If this is true, then the value for {@link #KEY_UNMETERED_NR_SA_BOOL} will be ignored. + * @hide + */ + public static final String KEY_UNMETERED_NR_SA_SUB6_BOOL = "unmetered_nr_sa_sub6_bool"; + + /** * Support ASCII 7-BIT encoding for long SMS. This carrier config is used to enable * this feature. * @hide @@ -3591,6 +3657,17 @@ public class CarrierConfigManager { public static final String KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY = "missed_incoming_call_sms_originator_string_array"; + + /** + * String array of Apn Type configurations. + * The entries should be of form "APN_TYPE_NAME:priority". + * priority is an integer that is sorted from highest to lowest. + * example: cbs:5 + * + * @hide + */ + public static final String KEY_APN_PRIORITY_STRING_ARRAY = "apn_priority_string_array"; + /** * The patterns of missed incoming call sms. This is the regular expression used for * matching the missed incoming call's date, time, and caller id. The pattern should match @@ -3778,8 +3855,10 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL, false); sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true); sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true); + sDefaults.putBoolean(KEY_LOCAL_DISCONNECT_EMPTY_IMS_CONFERENCE_BOOL, false); sDefaults.putBoolean(KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL, true); sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL, true); + sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_ON_PEER_BOOL, true); sDefaults.putBoolean(KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL, false); sDefaults.putBoolean(KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL, false); sDefaults.putInt(KEY_IMS_CONFERENCE_SIZE_LIMIT_INT, 5); @@ -4026,6 +4105,7 @@ public class CarrierConfigManager { }); sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, CellSignalStrengthNr.USE_SSRSRP); + sDefaults.putBoolean(KEY_SIGNAL_STRENGTH_NR_NSA_USE_LTE_AS_PRIMARY_BOOL, true); sDefaults.putStringArray(KEY_BANDWIDTH_STRING_ARRAY, new String[]{ "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA-IS95A:14,14", "CDMA-IS95B:14,14", "1xRTT:30,30", "EvDo-rev.0:750,48", "EvDo-rev.A:950,550", "HSDPA:4300,620", @@ -4054,6 +4134,9 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_BOOL, false); sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false); sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_SUB6_BOOL, false); + sDefaults.putBoolean(KEY_UNMETERED_NR_SA_BOOL, false); + sDefaults.putBoolean(KEY_UNMETERED_NR_SA_MMWAVE_BOOL, false); + sDefaults.putBoolean(KEY_UNMETERED_NR_SA_SUB6_BOOL, false); sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false); sDefaults.putBoolean(KEY_SHOW_WIFI_CALLING_ICON_IN_STATUS_BAR_BOOL, false); /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */ @@ -4118,6 +4201,10 @@ public class CarrierConfigManager { sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, TimeUnit.DAYS.toMillis(1)); sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY, new String[0]); + sDefaults.putStringArray(KEY_APN_PRIORITY_STRING_ARRAY, new String[] { + "default:0", "mms:2", "supl:2", "dun:2", "hipri:3", "fota:2", + "ims:2", "cbs:2", "ia:2", "emergency:2", "mcx:3", "xcap:3" + }); sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]); } diff --git a/telephony/java/android/telephony/CbGeoUtils.java b/telephony/java/android/telephony/CbGeoUtils.java index c0ae99e89cb3..806bac0c32c9 100644 --- a/telephony/java/android/telephony/CbGeoUtils.java +++ b/telephony/java/android/telephony/CbGeoUtils.java @@ -128,6 +128,23 @@ public class CbGeoUtils { public String toString() { return "(" + lat + "," + lng + ")"; } + + /** + * @hide + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof LatLng)) { + return false; + } + + LatLng l = (LatLng) o; + return lat == l.lat && lng == l.lng; + } } /** @@ -280,6 +297,32 @@ public class CbGeoUtils { } return str; } + + /** + * @hide + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof Polygon)) { + return false; + } + + Polygon p = (Polygon) o; + if (mVertices.size() != p.mVertices.size()) { + return false; + } + for (int i = 0; i < mVertices.size(); i++) { + if (!mVertices.get(i).equals(p.mVertices.get(i))) { + return false; + } + } + + return true; + } } /** @@ -335,6 +378,24 @@ public class CbGeoUtils { return str; } + + /** + * @hide + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof Circle)) { + return false; + } + + Circle c = (Circle) o; + return mCenter.equals(c.mCenter) + && Double.compare(mRadiusMeter, c.mRadiusMeter) == 0; + } } /** diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java index 2bb4eb1538bd..1376cddbc41f 100644 --- a/telephony/java/android/telephony/SignalStrength.java +++ b/telephony/java/android/telephony/SignalStrength.java @@ -82,6 +82,8 @@ public class SignalStrength implements Parcelable { // Effectively final. Timestamp is set during construction of SignalStrength private long mTimestampMillis; + private boolean mLteAsPrimaryInNrNsa = true; + CellSignalStrengthCdma mCdma; CellSignalStrengthGsm mGsm; CellSignalStrengthWcdma mWcdma; @@ -188,6 +190,10 @@ public class SignalStrength implements Parcelable { private CellSignalStrength getPrimary() { // This behavior is intended to replicate the legacy behavior of getLevel() by prioritizing // newer faster RATs for default/for display purposes. + + if (mLteAsPrimaryInNrNsa) { + if (mLte.isValid()) return mLte; + } if (mNr.isValid()) return mNr; if (mLte.isValid()) return mLte; if (mCdma.isValid()) return mCdma; @@ -268,6 +274,10 @@ public class SignalStrength implements Parcelable { /** @hide */ public void updateLevel(PersistableBundle cc, ServiceState ss) { + if (cc != null) { + mLteAsPrimaryInNrNsa = cc.getBoolean( + CarrierConfigManager.KEY_SIGNAL_STRENGTH_NR_NSA_USE_LTE_AS_PRIMARY_BOOL, true); + } mCdma.updateLevel(cc, ss); mGsm.updateLevel(cc, ss); mWcdma.updateLevel(cc, ss); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index d6cdaa6d8bc0..835ef59f9ef3 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -147,6 +147,10 @@ import java.util.regex.Pattern; * information unless it has the appropriate permissions declared in * its manifest file. Where permissions apply, they are noted in the * the methods through which you access the protected information. + * + * <p>TelephonyManager is intended for use on devices that implement + * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY FEATURE_TELEPHONY}. On devices + * that do not implement this feature, the behavior is not reliable. */ @SystemService(Context.TELEPHONY_SERVICE) public class TelephonyManager { @@ -5842,6 +5846,10 @@ public class TelephonyManager { * {@link android.telephony.PhoneStateListener#onCellInfoChanged onCellInfoChanged()} * for each active subscription. * + * <p>This method returns valid data for devices with + * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY FEATURE_TELEPHONY}. On devices + * that do not implement this feature, the behavior is not reliable. + * * @param executor the executor on which callback will be invoked. * @param callback a callback to receive CellInfo. */ @@ -5888,6 +5896,10 @@ public class TelephonyManager { * {@link android.telephony.PhoneStateListener#onCellInfoChanged onCellInfoChanged()} * for each active subscription. * + * <p>This method returns valid data for devices with + * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY FEATURE_TELEPHONY}. On devices + * that do not implement this feature, the behavior is not reliable. + * * @param workSource the requestor to whom the power consumption for this should be attributed. * @param executor the executor on which callback will be invoked. * @param callback a callback to receive CellInfo. @@ -13238,4 +13250,21 @@ public class TelephonyManager { public static void enableServiceHandleCaching() { sServiceHandleCacheEnabled = true; } + + /** + * Whether device can connect to 5G network when two SIMs are active. + * @hide + * TODO b/153669716: remove or make system API. + */ + public boolean canConnectTo5GInDsdsMode() { + ITelephony telephony = getITelephony(); + if (telephony == null) return true; + try { + return telephony.canConnectTo5GInDsdsMode(); + } catch (RemoteException ex) { + return true; + } catch (NullPointerException ex) { + return true; + } + } } diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java index 2b1d9e58c4d5..18e25921555a 100644 --- a/telephony/java/com/android/internal/telephony/DctConstants.java +++ b/telephony/java/com/android/internal/telephony/DctConstants.java @@ -113,6 +113,7 @@ public class DctConstants { public static final int EVENT_5G_TIMER_HYSTERESIS = BASE + 53; public static final int EVENT_5G_TIMER_WATCHDOG = BASE + 54; public static final int EVENT_CARRIER_CONFIG_CHANGED = BASE + 55; + public static final int EVENT_SIM_STATE_UPDATED = BASE + 56; /***** Constants *****/ diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 43aeb19fe1bd..f5cd68f050a4 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2268,4 +2268,9 @@ interface ITelephony { * @return operatorinfo on success */ String getManualNetworkSelectionPlmn(int subId); + + /** + * Whether device can connect to 5G network when two SIMs are active. + */ + boolean canConnectTo5GInDsdsMode(); } diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index 13bf17954aa4..2d2f4dbdf907 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -107,7 +107,9 @@ public class AppLaunch extends InstrumentationTestCase { private static final int PROFILE_SAVE_SLEEP_TIMEOUT = 1000; // Allow 1s for the profile to save private static final int IORAP_TRACE_DURATION_TIMEOUT = 7000; // Allow 7s for trace to complete. private static final int IORAP_TRIAL_LAUNCH_ITERATIONS = 3; // min 3 launches to merge traces. - private static final int IORAP_COMPILE_CMD_TIMEOUT = 600; // in seconds: 10 minutes + private static final int IORAP_COMPILE_CMD_TIMEOUT = 60; // in seconds: 1 minutes + private static final int IORAP_COMPILE_MIN_TRACES = 1; // configure iorapd to need 1 trace. + private static final int IORAP_COMPILE_RETRIES = 3; // retry compiler 3 times if it fails. private static final String LAUNCH_SUB_DIRECTORY = "launch_logs"; private static final String LAUNCH_FILE = "applaunch.txt"; private static final String TRACE_SUB_DIRECTORY = "atrace_logs"; @@ -132,9 +134,9 @@ public class AppLaunch extends InstrumentationTestCase { private static final String LAUNCH_ORDER_CYCLIC = "cyclic"; private static final String LAUNCH_ORDER_SEQUENTIAL = "sequential"; private static final String COMPILE_CMD = "cmd package compile -f -m %s %s"; - private static final String IORAP_COMPILE_CMD = "cmd jobscheduler run -f android 283673059"; + private static final String IORAP_COMPILE_CMD = "dumpsys iorapd --compile-package %s"; private static final String IORAP_MAINTENANCE_CMD = - "iorap.cmd.maintenance --purge-package %s /data/misc/iorapd/sqlite.db"; + "dumpsys iorapd --purge-package %s"; private static final String IORAP_DUMPSYS_CMD = "dumpsys iorapd"; private static final String SPEED_PROFILE_FILTER = "speed-profile"; private static final String VERIFY_FILTER = "verify"; @@ -350,9 +352,9 @@ public class AppLaunch extends InstrumentationTestCase { sleep(IORAP_TRACE_DURATION_TIMEOUT); if (launch.getLaunchReason().equals(IORAP_TRIAL_LAUNCH_LAST)) { - // run the iorap job scheduler and wait for iorap to compile fully. - assertTrue(String.format("Not able to iorap-compile the app : %s", appPkgName), - compileAppForIorap(appPkgName)); + // run the iorap compiler and wait for iorap to compile fully. + // this throws an exception if it fails. + compileAppForIorapWithRetries(appPkgName, IORAP_COMPILE_RETRIES); } } @@ -506,6 +508,22 @@ public class AppLaunch extends InstrumentationTestCase { } /** + * Compile the app package using compilerFilter, + * retrying if the compilation command fails in between. + */ + private void compileAppForIorapWithRetries(String appPkgName, int retries) throws IOException { + for (int i = 0; i < retries; ++i) { + if (compileAppForIorap(appPkgName)) { + return; + } + sleep(1000); + } + + throw new IllegalStateException("compileAppForIorapWithRetries: timed out after " + + retries + " retries"); + } + + /** * Compile the app package using compilerFilter and return true or false * based on status of the compilation command. */ @@ -513,7 +531,7 @@ public class AppLaunch extends InstrumentationTestCase { String logcatTimestamp = getTimeNowForLogcat(); getInstrumentation().getUiAutomation(). - executeShellCommand(IORAP_COMPILE_CMD); + executeShellCommand(String.format(IORAP_COMPILE_CMD, appPkgName)); int i = 0; for (i = 0; i < IORAP_COMPILE_CMD_TIMEOUT; ++i) { @@ -525,7 +543,8 @@ public class AppLaunch extends InstrumentationTestCase { } else if (status == IorapCompilationStatus.INSUFFICIENT_TRACES) { Log.e(TAG, "compileAppForIorap: failed due to insufficient traces"); logDumpsysIorapd(appPkgName); - return false; + throw new IllegalStateException( + "compileAppForIorap: failed due to insufficient traces"); } // else INCOMPLETE. keep asking iorapd if it's done yet. sleep(1000); } @@ -536,19 +555,7 @@ public class AppLaunch extends InstrumentationTestCase { return false; } - // Wait for the job to finish completely. - // Other packages could be compiled in cyclic runs. - int currentAttempt = 0; - do { - String logcatLines = getLogcatSinceTime(logcatTimestamp); - if (logcatLines.contains("IorapForwardingService: Finished background job")) { - return true; - } - sleep(1000); - } while (currentAttempt++ < IORAP_COMPILE_CMD_TIMEOUT); - - Log.e(TAG, "compileAppForIorap: failed due to jobscheduler timeout."); - return false; + return true; } /** Save the contents of $(adb shell dumpsys iorapd) to the launch_logs directory. */ @@ -808,11 +815,9 @@ public class AppLaunch extends InstrumentationTestCase { } Log.v(TAG, "Purge iorap package: " + packageName); - stopIorapd(); getInstrumentation().getUiAutomation() .executeShellCommand(String.format(IORAP_MAINTENANCE_CMD, packageName)); Log.v(TAG, "Executed: " + String.format(IORAP_MAINTENANCE_CMD, packageName)); - startIorapd(); } String executeShellCommandWithTempFile(String cmd) { @@ -892,12 +897,16 @@ public class AppLaunch extends InstrumentationTestCase { throw new AssertionError(e); } - stopIorapd(); getInstrumentation().getUiAutomation() .executeShellCommand(String.format("setprop iorapd.perfetto.enable %b", enable)); getInstrumentation().getUiAutomation() .executeShellCommand(String.format("setprop iorapd.readahead.enable %b", enable)); - startIorapd(); + getInstrumentation().getUiAutomation() + .executeShellCommand(String.format( + "setprop iorapd.maintenance.min_traces %d", IORAP_COMPILE_MIN_TRACES)); + // this last command blocks until iorapd refreshes its system properties + getInstrumentation().getUiAutomation() + .executeShellCommand(String.format("dumpsys iorapd --refresh-properties")); if (enable) { mIorapStatus = IorapStatus.ENABLED; diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java index 4c29e72ec713..a4c81d577522 100644 --- a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java +++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java @@ -56,8 +56,7 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test { cleanUp(); mOriginalUserId = getDevice().getCurrentUser(); createAndStartSecondaryUser(); - // TODO(b/149733368): Remove the '-g' workaround when the bug is fixed. - installPackage("RollbackTest.apk", "-g --user all"); + installPackage("RollbackTest.apk", "--user all"); } @Test diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java index b40d022f075d..86c3fa0fe034 100644 --- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java +++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java @@ -53,8 +53,9 @@ public class TaskOrganizerMultiWindowTest extends Activity { return true; } - float x = e.getX(0); + float x = e.getRawX(0); float ratio = (float) x / (float) getWidth() ; + ratio = 1-ratio; LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(0, @@ -172,10 +173,14 @@ public class TaskOrganizerMultiWindowTest extends Activity { setContentView(splitView); } + private void addFlags(Intent intent) { + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION); + } + Intent makeSettingsIntent() { Intent intent = new Intent(); intent.setAction(android.provider.Settings.ACTION_SETTINGS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + addFlags(intent); return intent; } @@ -183,7 +188,7 @@ public class TaskOrganizerMultiWindowTest extends Activity { Intent intent = new Intent(); intent.setAction(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_APP_CONTACTS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + addFlags(intent); return intent; } diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java index 03615f332723..aa041f22a46e 100644 --- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java +++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java @@ -80,8 +80,10 @@ class TaskView extends SurfaceView implements SurfaceHolder.Callback { } catch (Exception e) { // System server died.. oh well } + t.reparent(leash, getSurfaceControl()) .setPosition(leash, 0, 0) + .show(leash) .apply(); } } diff --git a/tests/net/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt index 00714382684f..bd1847b7c440 100644 --- a/tests/net/java/android/net/CaptivePortalDataTest.kt +++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt @@ -16,17 +16,22 @@ package android.net +import android.os.Build import androidx.test.filters.SmallTest -import androidx.test.runner.AndroidJUnit4 import com.android.testutils.assertParcelSane import com.android.testutils.assertParcelingIsLossless +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import com.android.testutils.DevSdkIgnoreRunner +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import kotlin.test.assertEquals import kotlin.test.assertNotEquals @SmallTest -@RunWith(AndroidJUnit4::class) +@RunWith(DevSdkIgnoreRunner::class) +@IgnoreUpTo(Build.VERSION_CODES.Q) class CaptivePortalDataTest { private val data = CaptivePortalData.Builder() .setRefreshTime(123L) @@ -63,6 +68,46 @@ class CaptivePortalDataTest { assertNotEqualsAfterChange { it.setCaptive(false) } } + @Test + fun testUserPortalUrl() { + assertEquals(Uri.parse("https://portal.example.com/test"), data.userPortalUrl) + } + + @Test + fun testVenueInfoUrl() { + assertEquals(Uri.parse("https://venue.example.com/test"), data.venueInfoUrl) + } + + @Test + fun testIsSessionExtendable() { + assertTrue(data.isSessionExtendable) + } + + @Test + fun testByteLimit() { + assertEquals(456L, data.byteLimit) + // Test byteLimit unset. + assertEquals(-1L, CaptivePortalData.Builder(null).build().byteLimit) + } + + @Test + fun testRefreshTimeMillis() { + assertEquals(123L, data.refreshTimeMillis) + } + + @Test + fun testExpiryTimeMillis() { + assertEquals(789L, data.expiryTimeMillis) + // Test expiryTimeMillis unset. + assertEquals(-1L, CaptivePortalData.Builder(null).build().expiryTimeMillis) + } + + @Test + fun testIsCaptive() { + assertTrue(data.isCaptive) + assertFalse(makeBuilder().setCaptive(false).build().isCaptive) + } + private fun CaptivePortalData.mutate(mutator: (CaptivePortalData.Builder) -> Unit) = CaptivePortalData.Builder(this).apply { mutator(this) }.build() diff --git a/tests/net/common/java/android/net/DependenciesTest.java b/tests/net/common/java/android/net/DependenciesTest.java new file mode 100644 index 000000000000..ac1c28a45462 --- /dev/null +++ b/tests/net/common/java/android/net/DependenciesTest.java @@ -0,0 +1,113 @@ +/* + * 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 android.net; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +/** + * A simple class that tests dependencies to java standard tools from the + * Network stack. These tests are not meant to be comprehensive tests of + * the relevant APIs : such tests belong in the relevant test suite for + * these dependencies. Instead, this just makes sure coverage is present + * by calling the methods in the exact way (or a representative way of how) + * they are called in the network stack. + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DependenciesTest { + // Used to in ipmemorystore's RegularMaintenanceJobService to convert + // 24 hours into seconds + @Test + public void testTimeUnit() { + final int hours = 24; + final long inSeconds = TimeUnit.HOURS.toMillis(hours); + assertEquals(inSeconds, hours * 60 * 60 * 1000); + } + + private byte[] makeTrivialArray(final int size) { + final byte[] src = new byte[size]; + for (int i = 0; i < size; ++i) { + src[i] = (byte) i; + } + return src; + } + + // Used in ApfFilter to find an IP address from a byte array + @Test + public void testArrays() { + final int size = 128; + final byte[] src = makeTrivialArray(size); + + // Test copy + final int copySize = 16; + final int offset = 24; + final byte[] expected = new byte[copySize]; + for (int i = 0; i < copySize; ++i) { + expected[i] = (byte) (offset + i); + } + + final byte[] copy = Arrays.copyOfRange(src, offset, offset + copySize); + assertArrayEquals(expected, copy); + assertArrayEquals(new byte[0], Arrays.copyOfRange(src, size, size)); + } + + // Used mainly in the Dhcp code + @Test + public void testCopyOf() { + final byte[] src = makeTrivialArray(128); + final byte[] copy = Arrays.copyOf(src, src.length); + assertArrayEquals(src, copy); + assertFalse(src == copy); + + assertArrayEquals(new byte[0], Arrays.copyOf(src, 0)); + + final int excess = 16; + final byte[] biggerCopy = Arrays.copyOf(src, src.length + excess); + for (int i = src.length; i < src.length + excess; ++i) { + assertEquals(0, biggerCopy[i]); + } + for (int i = src.length - 1; i >= 0; --i) { + assertEquals(src[i], biggerCopy[i]); + } + } + + // Used mainly in DnsUtils but also various other places + @Test + public void testAsList() { + final int size = 24; + final Object[] src = new Object[size]; + final ArrayList<Object> expected = new ArrayList<>(size); + for (int i = 0; i < size; ++i) { + final Object o = new Object(); + src[i] = o; + expected.add(o); + } + assertEquals(expected, Arrays.asList(src)); + } +} diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java index 6e9dc8eaf2dc..3f8261d5ad7f 100644 --- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java @@ -17,6 +17,8 @@ package android.net; import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; +import static android.net.NetworkCapabilities.MAX_TRANSPORT; +import static android.net.NetworkCapabilities.MIN_TRANSPORT; import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; @@ -32,10 +34,12 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVIT import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES; +import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES; import static com.android.testutils.ParcelUtilsKt.assertParcelSane; @@ -45,10 +49,15 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.net.wifi.aware.DiscoverySession; +import android.net.wifi.aware.PeerHandle; +import android.net.wifi.aware.WifiAwareNetworkSpecifier; import android.os.Build; +import android.os.Process; import android.test.suitebuilder.annotation.SmallTest; import android.util.ArraySet; @@ -61,6 +70,7 @@ import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import java.util.Arrays; import java.util.Set; @@ -74,6 +84,9 @@ public class NetworkCapabilitiesTest { @Rule public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule(); + private DiscoverySession mDiscoverySession = Mockito.mock(DiscoverySession.class); + private PeerHandle mPeerHandle = Mockito.mock(PeerHandle.class); + private boolean isAtLeastR() { // BuildCompat.isAtLeastR() is used to check the Android version before releasing Android R. // Build.VERSION.SDK_INT > Build.VERSION_CODES.Q is used to check the Android version after @@ -685,4 +698,238 @@ public class NetworkCapabilitiesTest { assertEquals(TRANSPORT_VPN, transportTypes[2]); assertEquals(TRANSPORT_TEST, transportTypes[3]); } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testTelephonyNetworkSpecifier() { + final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(1); + final NetworkCapabilities nc1 = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_WIFI) + .setNetworkSpecifier(specifier) + .build(); + assertEquals(specifier, nc1.getNetworkSpecifier()); + try { + final NetworkCapabilities nc2 = new NetworkCapabilities.Builder() + .setNetworkSpecifier(specifier) + .build(); + fail("Must have a single transport type. Without transport type or multiple transport" + + " types is invalid."); + } catch (IllegalStateException expected) { } + } + + @Test + public void testWifiAwareNetworkSpecifier() { + final NetworkCapabilities nc = new NetworkCapabilities() + .addTransportType(TRANSPORT_WIFI_AWARE); + // If NetworkSpecifier is not set, the default value is null. + assertNull(nc.getNetworkSpecifier()); + final WifiAwareNetworkSpecifier specifier = new WifiAwareNetworkSpecifier.Builder( + mDiscoverySession, mPeerHandle).build(); + nc.setNetworkSpecifier(specifier); + assertEquals(specifier, nc.getNetworkSpecifier()); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testAdministratorUidsAndOwnerUid() { + // Test default owner uid. + // If the owner uid is not set, the default value should be Process.INVALID_UID. + final NetworkCapabilities nc1 = new NetworkCapabilities.Builder().build(); + assertEquals(Process.INVALID_UID, nc1.getOwnerUid()); + // Test setAdministratorUids and getAdministratorUids. + final int[] administratorUids = {1001, 10001}; + final NetworkCapabilities nc2 = new NetworkCapabilities.Builder() + .setAdministratorUids(administratorUids) + .build(); + assertTrue(Arrays.equals(administratorUids, nc2.getAdministratorUids())); + // Test setOwnerUid and getOwnerUid. + // The owner UID must be included in administrator UIDs, or throw IllegalStateException. + try { + final NetworkCapabilities nc3 = new NetworkCapabilities.Builder() + .setOwnerUid(1001) + .build(); + fail("The owner UID must be included in administrator UIDs."); + } catch (IllegalStateException expected) { } + final NetworkCapabilities nc4 = new NetworkCapabilities.Builder() + .setAdministratorUids(administratorUids) + .setOwnerUid(1001) + .build(); + assertEquals(1001, nc4.getOwnerUid()); + try { + final NetworkCapabilities nc5 = new NetworkCapabilities.Builder() + .setAdministratorUids(null) + .build(); + fail("Should not set null into setAdministratorUids"); + } catch (NullPointerException expected) { } + } + + @Test + public void testLinkBandwidthKbps() { + final NetworkCapabilities nc = new NetworkCapabilities(); + // The default value of LinkDown/UpstreamBandwidthKbps should be LINK_BANDWIDTH_UNSPECIFIED. + assertEquals(LINK_BANDWIDTH_UNSPECIFIED, nc.getLinkDownstreamBandwidthKbps()); + assertEquals(LINK_BANDWIDTH_UNSPECIFIED, nc.getLinkUpstreamBandwidthKbps()); + nc.setLinkDownstreamBandwidthKbps(512); + nc.setLinkUpstreamBandwidthKbps(128); + assertEquals(512, nc.getLinkDownstreamBandwidthKbps()); + assertNotEquals(128, nc.getLinkDownstreamBandwidthKbps()); + assertEquals(128, nc.getLinkUpstreamBandwidthKbps()); + assertNotEquals(512, nc.getLinkUpstreamBandwidthKbps()); + } + + @Test + public void testSignalStrength() { + final NetworkCapabilities nc = new NetworkCapabilities(); + // The default value of signal strength should be SIGNAL_STRENGTH_UNSPECIFIED. + assertEquals(SIGNAL_STRENGTH_UNSPECIFIED, nc.getSignalStrength()); + nc.setSignalStrength(-80); + assertEquals(-80, nc.getSignalStrength()); + assertNotEquals(-50, nc.getSignalStrength()); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testDeduceRestrictedCapability() { + final NetworkCapabilities nc = new NetworkCapabilities(); + // Default capabilities don't have restricted capability. + assertFalse(nc.deduceRestrictedCapability()); + // If there is a force restricted capability, then the network capabilities is restricted. + nc.addCapability(NET_CAPABILITY_OEM_PAID); + nc.addCapability(NET_CAPABILITY_INTERNET); + assertTrue(nc.deduceRestrictedCapability()); + // Except for the force restricted capability, if there is any unrestricted capability in + // capabilities, then the network capabilities is not restricted. + nc.removeCapability(NET_CAPABILITY_OEM_PAID); + nc.addCapability(NET_CAPABILITY_CBS); + assertFalse(nc.deduceRestrictedCapability()); + // Except for the force restricted capability, the network capabilities will only be treated + // as restricted when there is no any unrestricted capability. + nc.removeCapability(NET_CAPABILITY_INTERNET); + assertTrue(nc.deduceRestrictedCapability()); + } + + private void assertNoTransport(NetworkCapabilities nc) { + for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) { + assertFalse(nc.hasTransport(i)); + } + } + + // Checks that all transport types from MIN_TRANSPORT to maxTransportType are set and all + // transport types from maxTransportType + 1 to MAX_TRANSPORT are not set when positiveSequence + // is true. If positiveSequence is false, then the check sequence is opposite. + private void checkCurrentTransportTypes(NetworkCapabilities nc, int maxTransportType, + boolean positiveSequence) { + for (int i = MIN_TRANSPORT; i <= maxTransportType; i++) { + if (positiveSequence) { + assertTrue(nc.hasTransport(i)); + } else { + assertFalse(nc.hasTransport(i)); + } + } + for (int i = MAX_TRANSPORT; i > maxTransportType; i--) { + if (positiveSequence) { + assertFalse(nc.hasTransport(i)); + } else { + assertTrue(nc.hasTransport(i)); + } + } + } + + @Test + public void testMultipleTransportTypes() { + final NetworkCapabilities nc = new NetworkCapabilities(); + assertNoTransport(nc); + // Test adding multiple transport types. + for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) { + nc.addTransportType(i); + checkCurrentTransportTypes(nc, i, true /* positiveSequence */); + } + // Test removing multiple transport types. + for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) { + nc.removeTransportType(i); + checkCurrentTransportTypes(nc, i, false /* positiveSequence */); + } + assertNoTransport(nc); + nc.addTransportType(TRANSPORT_WIFI); + assertTrue(nc.hasTransport(TRANSPORT_WIFI)); + assertFalse(nc.hasTransport(TRANSPORT_VPN)); + nc.addTransportType(TRANSPORT_VPN); + assertTrue(nc.hasTransport(TRANSPORT_WIFI)); + assertTrue(nc.hasTransport(TRANSPORT_VPN)); + nc.removeTransportType(TRANSPORT_WIFI); + assertFalse(nc.hasTransport(TRANSPORT_WIFI)); + assertTrue(nc.hasTransport(TRANSPORT_VPN)); + nc.removeTransportType(TRANSPORT_VPN); + assertFalse(nc.hasTransport(TRANSPORT_WIFI)); + assertFalse(nc.hasTransport(TRANSPORT_VPN)); + assertNoTransport(nc); + } + + @Test + public void testAddAndRemoveTransportType() { + final NetworkCapabilities nc = new NetworkCapabilities(); + try { + nc.addTransportType(-1); + fail("Should not set invalid transport type into addTransportType"); + } catch (IllegalArgumentException expected) { } + try { + nc.removeTransportType(-1); + fail("Should not set invalid transport type into removeTransportType"); + } catch (IllegalArgumentException e) { } + } + + private class TestTransportInfo implements TransportInfo { + TestTransportInfo() { + } + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testBuilder() { + final int ownerUid = 1001; + final int signalStrength = -80; + final int requestUid = 10100; + final int[] administratorUids = {ownerUid, 10001}; + final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(1); + final TestTransportInfo transportInfo = new TestTransportInfo(); + final String ssid = "TEST_SSID"; + final String packageName = "com.google.test.networkcapabilities"; + final NetworkCapabilities nc = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_WIFI) + .addTransportType(TRANSPORT_CELLULAR) + .removeTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_EIMS) + .addCapability(NET_CAPABILITY_CBS) + .removeCapability(NET_CAPABILITY_CBS) + .setAdministratorUids(administratorUids) + .setOwnerUid(ownerUid) + .setLinkDownstreamBandwidthKbps(512) + .setLinkUpstreamBandwidthKbps(128) + .setNetworkSpecifier(specifier) + .setTransportInfo(transportInfo) + .setSignalStrength(signalStrength) + .setSsid(ssid) + .setRequestorUid(requestUid) + .setRequestorPackageName(packageName) + .build(); + assertEquals(1, nc.getTransportTypes().length); + assertEquals(TRANSPORT_WIFI, nc.getTransportTypes()[0]); + assertTrue(nc.hasCapability(NET_CAPABILITY_EIMS)); + assertFalse(nc.hasCapability(NET_CAPABILITY_CBS)); + assertTrue(Arrays.equals(administratorUids, nc.getAdministratorUids())); + assertEquals(ownerUid, nc.getOwnerUid()); + assertEquals(512, nc.getLinkDownstreamBandwidthKbps()); + assertNotEquals(128, nc.getLinkDownstreamBandwidthKbps()); + assertEquals(128, nc.getLinkUpstreamBandwidthKbps()); + assertNotEquals(512, nc.getLinkUpstreamBandwidthKbps()); + assertEquals(specifier, nc.getNetworkSpecifier()); + assertEquals(transportInfo, nc.getTransportInfo()); + assertEquals(signalStrength, nc.getSignalStrength()); + assertNotEquals(-50, nc.getSignalStrength()); + assertEquals(ssid, nc.getSsid()); + assertEquals(requestUid, nc.getRequestorUid()); + assertEquals(packageName, nc.getRequestorPackageName()); + // Cannot assign null into NetworkCapabilities.Builder + try { + final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(null); + fail("Should not set null into NetworkCapabilities.Builder"); + } catch (NullPointerException expected) { } + assertEquals(nc, new NetworkCapabilities.Builder(nc).build()); + } } diff --git a/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt b/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt index 9119d62fb023..7b22e45db90a 100644 --- a/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt +++ b/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt @@ -31,7 +31,6 @@ import android.net.NetworkStats.TAG_NONE import android.os.Build import androidx.test.filters.SmallTest import com.android.testutils.DevSdkIgnoreRule -import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.assertFieldCountEquals import com.android.testutils.assertNetworkStatsEquals import com.android.testutils.assertParcelingIsLossless @@ -47,70 +46,22 @@ import kotlin.test.assertEquals class NetworkStatsApiTest { @Rule @JvmField - val ignoreRule = DevSdkIgnoreRule() + val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q) private val testStatsEmpty = NetworkStats(0L, 0) + // Note that these variables need to be initialized outside of constructor, initialize + // here with methods that don't exist in Q devices will result in crash. + // stats1 and stats2 will have some entries with common keys, which are expected to // be merged if performing add on these 2 stats. - private val testStats1 = NetworkStats(0L, 0) - // Entries which only appear in set1. - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3)) - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8)) - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, - METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2)) - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 37, 52, 1, 10, 4)) - // Entries which are common for set1 and set2. - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5)) - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 17, 2, 11, 1, 0)) - .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 40, 1, 0, 0, 8)) - .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 1, 6, 2, 0)) - - private val testStats2 = NetworkStats(0L, 0) - // Entries which are common for set1 and set2. - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1)) - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45)) - .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7)) - .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0)) - // Entry which only appears in set2. - .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0)) + private lateinit var testStats1: NetworkStats + private lateinit var testStats2: NetworkStats // This is a result of adding stats1 and stats2, while the merging of common key items is // subject to test later, this should not be initialized with for a loop to add stats1 // and stats2 above. - private val testStats3 = NetworkStats(0L, 9) - // Entries which are unique either in stats1 or stats2. - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5)) - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8)) - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, - METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2)) - .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0)) - // Entries which are common for stats1 and stats2 are being merged. - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3)) - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 20, 17, 13, 32, 1)) - .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 50, 113, 11, 11, 49)) - .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 51, 3, 3, 4, 15)) - .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 7, 4, 8, 3, 0)) + private lateinit var testStats3: NetworkStats companion object { private const val TEST_IFACE = "test0" @@ -120,13 +71,67 @@ class NetworkStatsApiTest { @Before fun setUp() { + testStats1 = NetworkStats(0L, 0) + // Entries which only appear in set1. + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 37, 52, 1, 10, 4)) + // Entries which are common for set1 and set2. + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 17, 2, 11, 1, 0)) + .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 40, 1, 0, 0, 8)) + .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 1, 6, 2, 0)) assertEquals(8, testStats1.size()) + + testStats2 = NetworkStats(0L, 0) + // Entries which are common for set1 and set2. + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45)) + .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7)) + .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0)) + // Entry which only appears in set2. + .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0)) assertEquals(5, testStats2.size()) + + testStats3 = NetworkStats(0L, 9) + // Entries which are unique either in stats1 or stats2. + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2)) + .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0)) + // Entries which are common for stats1 and stats2 are being merged. + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 20, 17, 13, 32, 1)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 50, 113, 11, 11, 49)) + .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 51, 3, 3, 4, 15)) + .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 7, 4, 8, 3, 0)) assertEquals(9, testStats3.size()) } @Test - @IgnoreUpTo(Build.VERSION_CODES.Q) fun testAddEntry() { val expectedEntriesInStats2 = arrayOf( Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80, @@ -156,7 +161,6 @@ class NetworkStatsApiTest { } @Test - @IgnoreUpTo(Build.VERSION_CODES.Q) fun testAdd() { var stats = NetworkStats(0L, 0) assertNetworkStatsEquals(testStatsEmpty, stats) @@ -168,7 +172,6 @@ class NetworkStatsApiTest { } @Test - @IgnoreUpTo(Build.VERSION_CODES.Q) fun testParcelUnparcel() { assertParcelingIsLossless(testStatsEmpty) assertParcelingIsLossless(testStats1) @@ -177,7 +180,6 @@ class NetworkStatsApiTest { } @Test - @IgnoreUpTo(Build.VERSION_CODES.Q) fun testDescribeContents() { assertEquals(0, testStatsEmpty.describeContents()) assertEquals(0, testStats1.describeContents()) @@ -186,7 +188,6 @@ class NetworkStatsApiTest { } @Test - @IgnoreUpTo(Build.VERSION_CODES.Q) fun testSubtract() { // STATS3 - STATS2 = STATS1 assertNetworkStatsEquals(testStats1, testStats3.subtract(testStats2)) @@ -195,7 +196,6 @@ class NetworkStatsApiTest { } @Test - @IgnoreUpTo(Build.VERSION_CODES.Q) fun testMethodsDontModifyReceiver() { listOf(testStatsEmpty, testStats1, testStats2, testStats3).forEach { val origStats = it.clone() diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 912a27f08f30..b864e37f9ed0 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -4908,6 +4908,29 @@ public class ConnectivityServiceTest { } @Test + public void testDnsConfigurationTransTypesPushed() throws Exception { + // Clear any interactions that occur as a result of CS starting up. + reset(mMockDnsResolver); + + final NetworkRequest request = new NetworkRequest.Builder() + .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET) + .build(); + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(request, callback); + + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + verify(mMockDnsResolver, times(1)).createNetworkCache( + eq(mWiFiNetworkAgent.getNetwork().netId)); + verify(mMockDnsResolver, times(2)).setResolverConfiguration( + mResolverParamsParcelCaptor.capture()); + final ResolverParamsParcel resolverParams = mResolverParamsParcelCaptor.getValue(); + assertContainsExactly(resolverParams.transportTypes, TRANSPORT_WIFI); + reset(mMockDnsResolver); + } + + @Test public void testPrivateDnsNotification() throws Exception { NetworkRequest request = new NetworkRequest.Builder() .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET) diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java index 8fa0ab979a54..a392ae3f130a 100644 --- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java @@ -18,22 +18,34 @@ package com.android.server.connectivity; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; +import static com.android.testutils.MiscAssertsKt.assertContainsExactly; +import static com.android.testutils.MiscAssertsKt.assertContainsStringsExactly; +import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.NonNull; import android.content.Context; import android.net.IDnsResolver; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; +import android.net.ResolverOptionsParcel; +import android.net.ResolverParamsParcel; import android.net.RouteInfo; import android.net.shared.PrivateDnsConfig; import android.provider.Settings; @@ -47,6 +59,7 @@ import com.android.internal.util.test.FakeSettingsProvider; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -66,8 +79,11 @@ public class DnsManagerTest { static final int TEST_NETID = 100; static final int TEST_NETID_ALTERNATE = 101; static final int TEST_NETID_UNTRACKED = 102; - final boolean IS_DEFAULT = true; - final boolean NOT_DEFAULT = false; + static final int TEST_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800; + static final int TEST_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25; + static final int TEST_DEFAULT_MIN_SAMPLES = 8; + static final int TEST_DEFAULT_MAX_SAMPLES = 64; + static final int[] TEST_TRANSPORT_TYPES = {TRANSPORT_WIFI, TRANSPORT_VPN}; DnsManager mDnsManager; MockContentResolver mContentResolver; @@ -76,6 +92,35 @@ public class DnsManagerTest { @Mock IDnsResolver mMockDnsResolver; @Mock MockableSystemProperties mSystemProperties; + private void assertResolverOptionsEquals( + @NonNull ResolverOptionsParcel actual, + @NonNull ResolverOptionsParcel expected) { + assertEquals(actual.hosts, expected.hosts); + assertEquals(actual.tcMode, expected.tcMode); + assertFieldCountEquals(2, ResolverOptionsParcel.class); + } + + private void assertResolverParamsEquals(@NonNull ResolverParamsParcel actual, + @NonNull ResolverParamsParcel expected) { + assertEquals(actual.netId, expected.netId); + assertEquals(actual.sampleValiditySeconds, expected.sampleValiditySeconds); + assertEquals(actual.successThreshold, expected.successThreshold); + assertEquals(actual.minSamples, expected.minSamples); + assertEquals(actual.maxSamples, expected.maxSamples); + assertEquals(actual.baseTimeoutMsec, expected.baseTimeoutMsec); + assertEquals(actual.retryCount, expected.retryCount); + assertContainsStringsExactly(actual.servers, expected.servers); + assertContainsStringsExactly(actual.domains, expected.domains); + assertEquals(actual.tlsName, expected.tlsName); + assertContainsStringsExactly(actual.tlsServers, expected.tlsServers); + assertContainsStringsExactly(actual.tlsFingerprints, expected.tlsFingerprints); + assertEquals(actual.caCertificate, expected.caCertificate); + assertEquals(actual.tlsConnectTimeoutMs, expected.tlsConnectTimeoutMs); + assertResolverOptionsEquals(actual.resolverOptions, expected.resolverOptions); + assertContainsExactly(actual.transportTypes, expected.transportTypes); + assertFieldCountEquals(16, ResolverParamsParcel.class); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -103,8 +148,13 @@ public class DnsManagerTest { lp.addDnsServer(InetAddress.getByName("4.4.4.4")); // Send a validation event that is tracked on the alternate netId - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT); - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID_ALTERNATE, lp, NOT_DEFAULT); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); + mDnsManager.updateTransportsForNetwork(TEST_NETID_ALTERNATE, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID_ALTERNATE, lp); + mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_ALTERNATE, InetAddress.parseNumericAddress("4.4.4.4"), "", true)); @@ -135,7 +185,10 @@ public class DnsManagerTest { InetAddress.parseNumericAddress("6.6.6.6"), InetAddress.parseNumericAddress("2001:db8:66:66::1") })); - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); fixedLp = new LinkProperties(lp); mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp); assertTrue(fixedLp.isPrivateDnsActive()); @@ -168,7 +221,10 @@ public class DnsManagerTest { // be tracked. LinkProperties lp = new LinkProperties(); lp.addDnsServer(InetAddress.getByName("3.3.3.3")); - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, InetAddress.parseNumericAddress("3.3.3.3"), "", true)); @@ -179,7 +235,10 @@ public class DnsManagerTest { // Validation event has untracked netId mDnsManager.updatePrivateDns(new Network(TEST_NETID), mDnsManager.getPrivateDnsConfig()); - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED, InetAddress.parseNumericAddress("3.3.3.3"), "", true)); @@ -225,7 +284,10 @@ public class DnsManagerTest { Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OFF); mDnsManager.updatePrivateDns(new Network(TEST_NETID), mDnsManager.getPrivateDnsConfig()); - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, InetAddress.parseNumericAddress("3.3.3.3"), "", true)); @@ -258,4 +320,38 @@ public class DnsManagerTest { assertEquals("strictmode.com", cfgStrict.hostname); assertEquals(new InetAddress[0], cfgStrict.ips); } + + @Test + public void testSendDnsConfiguration() throws Exception { + reset(mMockDnsResolver); + mDnsManager.updatePrivateDns(new Network(TEST_NETID), + mDnsManager.getPrivateDnsConfig()); + final LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(TEST_IFACENAME); + lp.addDnsServer(InetAddress.getByName("3.3.3.3")); + lp.addDnsServer(InetAddress.getByName("4.4.4.4")); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); + + final ArgumentCaptor<ResolverParamsParcel> resolverParamsParcelCaptor = + ArgumentCaptor.forClass(ResolverParamsParcel.class); + verify(mMockDnsResolver, times(1)).setResolverConfiguration( + resolverParamsParcelCaptor.capture()); + final ResolverParamsParcel actualParams = resolverParamsParcelCaptor.getValue(); + final ResolverParamsParcel expectedParams = new ResolverParamsParcel(); + expectedParams.netId = TEST_NETID; + expectedParams.sampleValiditySeconds = TEST_DEFAULT_SAMPLE_VALIDITY_SECONDS; + expectedParams.successThreshold = TEST_DEFAULT_SUCCESS_THRESHOLD_PERCENT; + expectedParams.minSamples = TEST_DEFAULT_MIN_SAMPLES; + expectedParams.maxSamples = TEST_DEFAULT_MAX_SAMPLES; + expectedParams.servers = new String[]{"3.3.3.3", "4.4.4.4"}; + expectedParams.domains = new String[]{}; + expectedParams.tlsName = ""; + expectedParams.tlsServers = new String[]{"3.3.3.3", "4.4.4.4"}; + expectedParams.transportTypes = TEST_TRANSPORT_TYPES; + expectedParams.resolverOptions = new ResolverOptionsParcel(); + assertResolverParamsEquals(actualParams, expectedParams); + } } diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java index 4c2a984f8198..737665fb97e4 100644 --- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java @@ -17,6 +17,7 @@ package com.android.framework.permission.tests; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import android.os.Binder; import android.os.RemoteException; @@ -27,6 +28,8 @@ import android.view.IWindowManager; import junit.framework.TestCase; +import org.junit.Test; + /** * TODO: Remove this. This is only a placeholder, need to implement this. */ @@ -53,7 +56,7 @@ public class WindowManagerPermissionTests extends TestCase { } try { - mWm.addWindowToken(null, 0, DEFAULT_DISPLAY); + mWm.addWindowToken(null, TYPE_APPLICATION, DEFAULT_DISPLAY); fail("IWindowManager.addWindowToken did not throw SecurityException as" + " expected"); } catch (SecurityException e) { @@ -63,16 +66,6 @@ public class WindowManagerPermissionTests extends TestCase { } try { - mWm.removeWindowToken(null, DEFAULT_DISPLAY); - fail("IWindowManager.removeWindowToken did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - - try { mWm.prepareAppTransition(0, false); fail("IWindowManager.prepareAppTransition did not throw SecurityException as" + " expected"); @@ -182,4 +175,29 @@ public class WindowManagerPermissionTests extends TestCase { fail("Unexpected remote exception"); } } + + @Test + public void testADD_WINDOW_TOKEN_WITH_OPTIONS() { + // Verify if addWindowTokenWithOptions throw SecurityException for privileged window type. + try { + mWm.addWindowTokenWithOptions(null, TYPE_APPLICATION, DEFAULT_DISPLAY, null, ""); + fail("IWindowManager.addWindowTokenWithOptions did not throw SecurityException as" + + " expected"); + } catch (SecurityException e) { + // expected + } catch (RemoteException e) { + fail("Unexpected remote exception"); + } + + // Verify if addWindowTokenWithOptions throw SecurityException for null packageName. + try { + mWm.addWindowTokenWithOptions(null, TYPE_APPLICATION, DEFAULT_DISPLAY, null, null); + fail("IWindowManager.addWindowTokenWithOptions did not throw SecurityException as" + + " expected"); + } catch (SecurityException e) { + // expected + } catch (RemoteException e) { + fail("Unexpected remote exception"); + } + } } diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java index 3026e0b51133..0dd45bad8a01 100644 --- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java +++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java @@ -47,7 +47,8 @@ public final class FrameworksTestsFilter extends SelectTest { "android.view.InsetsSourceConsumerTest", "android.view.InsetsStateTest", "android.view.WindowMetricsTest", - "android.view.PendingInsetsControllerTest" + "android.view.PendingInsetsControllerTest", + "android.app.WindowContextTest" }; public FrameworksTestsFilter(Bundle testArgs) { diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h index d56f2be7ecb3..b513463ec98f 100644 --- a/tools/stats_log_api_gen/Collation.h +++ b/tools/stats_log_api_gen/Collation.h @@ -160,7 +160,7 @@ struct AtomDecl { int exclusiveField = 0; int defaultState = INT_MAX; int triggerStateReset = INT_MAX; - bool nested; + bool nested = true; int uidField = 0; diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp index 23a0f7278271..5fe94987aa65 100644 --- a/tools/stats_log_api_gen/atoms_info_writer.cpp +++ b/tools/stats_log_api_gen/atoms_info_writer.cpp @@ -42,7 +42,6 @@ static void write_atoms_info_header_body(FILE* out, const Atoms& atoms) { fprintf(out, " const static std::set<int> " "kTruncatingTimestampAtomBlackList;\n"); - fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n"); fprintf(out, " const static std::set<int> kAtomsWithAttributionChain;\n"); fprintf(out, " const static std::map<int, StateAtomFieldOptions> " @@ -101,28 +100,6 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) { fprintf(out, "};\n"); fprintf(out, "\n"); - fprintf(out, "static std::map<int, int> getAtomUidField() {\n"); - fprintf(out, " std::map<int, int> uidField;\n"); - for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end(); - atomIt++) { - if ((*atomIt)->uidField == 0) { - continue; - } - fprintf(out, - "\n // Adding uid field for atom " - "(%d)%s\n", - (*atomIt)->code, (*atomIt)->name.c_str()); - fprintf(out, " uidField[%d /* %s */] = %d;\n", (*atomIt)->code, - make_constant_name((*atomIt)->name).c_str(), (*atomIt)->uidField); - } - - fprintf(out, " return uidField;\n"); - fprintf(out, "};\n"); - - fprintf(out, - "const std::map<int, int> AtomsInfo::kAtomsWithUidField = " - "getAtomUidField();\n"); - fprintf(out, "static std::map<int, StateAtomFieldOptions> " "getStateAtomFieldOptions() {\n"); diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt index eeb006ee6ab2..2ecf3092035d 100644 --- a/wifi/jarjar-rules.txt +++ b/wifi/jarjar-rules.txt @@ -1,68 +1,95 @@ # used by wifi-service +# TODO (b/153596226): Find a solution for networkstack's AIDL parcelables & interfaces. +# Parcelable class names are serialized in the wire, so renaming them +# will result in the class not being found for any parcelable received/sent from the +# wifi-service jar. + +# Note: This rule is needed to ensure the rule below does not rename a Parcelable (see TODO above). rule android.net.DhcpResultsParcelable* @0 -rule android.net.DhcpResults* com.android.server.x.wifi.net.DhcpResults@1 +rule android.net.DhcpResults* com.android.wifi.x.@0 +# Note: This rule is needed to ensure the rule below does not rename a Parcelable (see TODO above). rule android.net.InterfaceConfigurationParcel* @0 -rule android.net.InterfaceConfiguration* com.android.server.x.wifi.net.InterfaceConfiguration@1 -rule android.net.IpMemoryStore* com.android.server.x.wifi.net.IpMemoryStore@1 -rule android.net.NetworkMonitorManager* com.android.server.x.wifi.net.NetworkMonitorManager@1 -rule android.net.TcpKeepalivePacketData* com.android.server.x.wifi.net.TcpKeepalivePacketData@1 -rule android.net.NetworkFactory* com.android.server.x.wifi.net.NetworkFactory@1 -rule android.net.ip.IpClientCallbacks* com.android.server.x.wifi.net.ip.IpClientCallbacks@1 -rule android.net.ip.IpClientManager* com.android.server.x.wifi.net.ip.IpClientManager@1 -rule android.net.ip.IpClientUtil* com.android.server.x.wifi.net.ip.IpClientUtil@1 -rule android.net.shared.InetAddressUtils* com.android.server.x.wifi.net.shared.InetAddressUtils@1 -rule android.net.shared.InitialConfiguration* com.android.server.x.wifi.net.shared.InitialConfiguration@1 -rule android.net.shared.IpConfigurationParcelableUtil* com.android.server.x.wifi.net.shared.IpConfigurationParcelableUtil@1 -rule android.net.shared.LinkPropertiesParcelableUtil* com.android.server.x.wifi.net.shared.LinkPropertiesParcelableUtil@1 -rule android.net.shared.ParcelableUtil* com.android.server.x.wifi.net.shared.ParcelableUtil@1 -rule android.net.shared.NetdUtils* com.android.server.x.wifi.net.shared.NetdUtils@1 -rule android.net.shared.NetworkMonitorUtils* com.android.server.x.wifi.net.shared.NetworkMonitorUtils@1 -rule android.net.shared.ParcelableUtil* com.android.server.x.wifi.net.shared.ParcelableUtil@1 -rule android.net.shared.PrivateDnsConfig* com.android.server.x.wifi.net.shared.PrivateDnsConfig@1 -rule android.net.shared.ProvisioningConfiguration* com.android.server.x.wifi.net.shared.ProvisioningConfiguration@1 -rule android.net.shared.RouteUtils* com.android.server.x.wifi.net.shared.RouteUtils@1 -rule android.net.util.KeepalivePacketDataUtil* com.android.server.x.wifi.net.util.KeepalivePacketDataUtil@1 -rule android.net.util.NetworkConstants* com.android.server.x.wifi.net.util.NetworkConstants@1 -rule android.net.util.InterfaceParams* com.android.server.x.wifi.net.util.InterfaceParams@1 -rule android.net.util.SharedLog* com.android.server.x.wifi.net.util.SharedLog@1 -rule android.net.util.NetUtils* com.android.server.x.wifi.net.util.NetUtils@1 -rule android.net.util.IpUtils* com.android.server.x.wifi.net.util.IpUtils@1 +rule android.net.InterfaceConfiguration* com.android.wifi.x.@0 +rule android.net.IpMemoryStore* com.android.wifi.x.@0 +rule android.net.NetworkMonitorManager* com.android.wifi.x.@0 +rule android.net.TcpKeepalivePacketData* com.android.wifi.x.@0 +rule android.net.NetworkFactory* com.android.wifi.x.@0 +rule android.net.ip.IpClientCallbacks* com.android.wifi.x.@0 +rule android.net.ip.IpClientManager* com.android.wifi.x.@0 +rule android.net.ip.IpClientUtil* com.android.wifi.x.@0 +rule android.net.ipmemorystore.OnBlobRetrievedListener* com.android.wifi.x.@0 +rule android.net.ipmemorystore.OnStatusListener* com.android.wifi.x.@0 +# Note: This rule is needed to ensure the rule below does not rename a Parcelable (see TODO above). +rule android.net.ipmemorystore.StatusParcelable* @0 +rule android.net.ipmemorystore.Status* com.android.wifi.x.@0 +rule android.net.networkstack.ModuleNetworkStackClient* com.android.wifi.x.@0 +rule android.net.networkstack.NetworkStackClientBase* com.android.wifi.x.@0 +rule android.net.shared.InetAddressUtils* com.android.wifi.x.@0 +rule android.net.shared.InitialConfiguration* com.android.wifi.x.@0 +rule android.net.shared.IpConfigurationParcelableUtil* com.android.wifi.x.@0 +rule android.net.shared.Layer2Information* com.android.wifi.x.@0 +rule android.net.shared.LinkPropertiesParcelableUtil* com.android.wifi.x.@0 +rule android.net.shared.NetdUtils* com.android.wifi.x.@0 +rule android.net.shared.NetworkMonitorUtils* com.android.wifi.x.@0 +rule android.net.shared.ParcelableUtil* com.android.wifi.x.@0 +rule android.net.shared.PrivateDnsConfig* com.android.wifi.x.@0 +rule android.net.shared.ProvisioningConfiguration* com.android.wifi.x.@0 +rule android.net.shared.RouteUtils* com.android.wifi.x.@0 +rule android.net.util.KeepalivePacketDataUtil* com.android.wifi.x.@0 +rule android.net.util.NetworkConstants* com.android.wifi.x.@0 +rule android.net.util.InterfaceParams* com.android.wifi.x.@0 +rule android.net.util.SharedLog* com.android.wifi.x.@0 +rule android.net.util.NetUtils* com.android.wifi.x.@0 +rule android.net.util.IpUtils* com.android.wifi.x.@0 + +rule androidx.annotation.** com.android.wifi.x.@0 # We don't jar-jar the entire package because, we still use some classes (like # AsyncChannel in com.android.internal.util) from these packages which are not # inside our jar (currently in framework.jar, but will be in wifisdk.jar in the future). -rule com.android.internal.util.FastXmlSerializer* com.android.server.x.wifi.util.FastXmlSerializer@1 -rule com.android.internal.util.HexDump* com.android.server.x.wifi.util.HexDump@1 -rule com.android.internal.util.IState* com.android.server.x.wifi.util.IState@1 -rule com.android.internal.util.MessageUtils* com.android.server.x.wifi.util.MessageUtils@1 -rule com.android.internal.util.State* com.android.server.x.wifi.util.State@1 -rule com.android.internal.util.StateMachine* com.android.server.x.wifi.util.StateMachine@1 -rule com.android.internal.util.WakeupMessage* com.android.server.x.wifi.util.WakeupMessage@1 +rule com.android.internal.util.FastXmlSerializer* com.android.wifi.x.@0 +rule com.android.internal.util.HexDump* com.android.wifi.x.@0 +rule com.android.internal.util.IState* com.android.wifi.x.@0 +rule com.android.internal.util.MessageUtils* com.android.wifi.x.@0 +rule com.android.internal.util.State* com.android.wifi.x.@0 +rule com.android.internal.util.StateMachine* com.android.wifi.x.@0 +rule com.android.internal.util.WakeupMessage* com.android.wifi.x.@0 -rule android.util.BackupUtils* com.android.server.x.wifi.util.BackupUtils@1 -rule android.util.LocalLog* com.android.server.x.wifi.util.LocalLog@1 -rule android.util.Rational* com.android.server.x.wifi.util.Rational@1 +rule android.util.BackupUtils* com.android.wifi.x.@0 +rule android.util.LocalLog* com.android.wifi.x.@0 +rule android.util.Rational* com.android.wifi.x.@0 -rule android.os.BasicShellCommandHandler* com.android.server.x.wifi.os.BasicShellCommandHandler@1 +rule android.os.BasicShellCommandHandler* com.android.wifi.x.@0 # Use our statically linked bouncy castle library -rule org.bouncycastle.** com.android.server.x.wifi.bouncycastle.@1 +rule org.bouncycastle.** com.android.wifi.x.@0 # Use our statically linked protobuf library -rule com.google.protobuf.** com.android.server.x.wifi.protobuf.@1 +rule com.google.protobuf.** com.android.wifi.x.@0 # use statically linked SystemMessageProto -rule com.android.internal.messages.SystemMessageProto* com.android.server.x.wifi.messages.SystemMessageProto@1 +rule com.android.internal.messages.SystemMessageProto* com.android.wifi.x.@0 # Use our statically linked PlatformProperties library -rule android.sysprop.** com.android.server.x.wifi.sysprop.@1 +rule android.sysprop.** com.android.wifi.x.@0 +# Use our statically linked HIDL stubs +# Note: android.hardware.wifi.** is used by various wifi feature flags. This unfortunately is also the namespace +# used by vendor HAL stubs. So, this rule is intentionally weird to try and filter the vendor HAL stubs only. +rule android.hardware.wifi.V** com.android.wifi.x.@0 +rule android.hardware.wifi.supplicant.** com.android.wifi.x.@0 +rule android.hardware.wifi.hostapd.** com.android.wifi.x.@0 +rule android.hidl.** com.android.wifi.x.@0 +# Use our statically linked ksoap2 +rule org.ksoap2.** com.android.wifi.x.@0 +# Use our statically linked nanohttpd +rule fi.iki.elonen.** com.android.wifi.x.@0 # used by both framework-wifi and wifi-service -rule android.content.pm.BaseParceledListSlice* android.x.net.wifi.util.BaseParceledListSlice@1 -rule android.content.pm.ParceledListSlice* android.x.net.wifi.util.ParceledListSlice@1 -rule android.net.shared.Inet4AddressUtils* android.x.net.wifi.util.Inet4AddressUtils@1 -rule android.net.util.MacAddressUtils* android.x.net.wifi.util.MacAddressUtils@1 -rule android.net.util.nsd.DnsSdTxtRecord* android.x.net.wifi.util.nsd.DnsSdTxtRecord@1 -rule android.os.HandlerExecutor* android.x.net.wifi.util.HandlerExecutor@1 -rule android.telephony.Annotation* android.x.net.wifi.util.TelephonyAnnotation@1 -rule com.android.internal.util.AsyncChannel* android.x.net.wifi.util.AsyncChannel@1 -rule com.android.internal.util.AsyncService* android.x.net.wifi.util.AsyncService@1 -rule com.android.internal.util.Preconditions* android.x.net.wifi.util.Preconditions@1 -rule com.android.internal.util.Protocol* android.x.net.wifi.util.Protocol@1 +rule android.content.pm.BaseParceledListSlice* com.android.wifi.x.@0 +rule android.content.pm.ParceledListSlice* com.android.wifi.x.@0 +rule android.net.shared.Inet4AddressUtils* com.android.wifi.x.@0 +rule android.net.util.MacAddressUtils* com.android.wifi.x.@0 +rule android.net.util.nsd.DnsSdTxtRecord* com.android.wifi.x.@0 +rule android.os.HandlerExecutor* com.android.wifi.x.@0 +rule android.telephony.Annotation* com.android.wifi.x.@0 +rule com.android.internal.util.AsyncChannel* com.android.wifi.x.@0 +rule com.android.internal.util.AsyncService* com.android.wifi.x.@0 +rule com.android.internal.util.Preconditions* com.android.wifi.x.@0 +rule com.android.internal.util.Protocol* com.android.wifi.x.@0 diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index b110a6139429..71f0ab8087ab 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -2973,4 +2973,15 @@ public class WifiConfiguration implements Parcelable { */ public boolean isMostRecentlyConnected = false; + /** + * Whether the key mgmt indicates if the WifiConfiguration needs a preSharedKey or not. + * @return true if preSharedKey is needed, false otherwise. + * @hide + */ + public boolean needsPreSharedKey() { + return allowedKeyManagement.get(KeyMgmt.WPA_PSK) + || allowedKeyManagement.get(KeyMgmt.SAE) + || allowedKeyManagement.get(KeyMgmt.WAPI_PSK); + } + } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index f1be8b20eb53..6c8dc00cb579 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -179,6 +179,8 @@ public class WifiManager { /** * Reason code if one or more of the network suggestions added already exists in platform's * database. + * Note: this code will not be returned with Android 11 as in-place modification is allowed, + * please check {@link #addNetworkSuggestions(List)}. * @see WifiNetworkSuggestion#equals(Object) */ public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3; @@ -186,6 +188,8 @@ public class WifiManager { /** * Reason code if the number of network suggestions provided by the app crosses the max * threshold set per app. + * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)} if + * the total size exceeds the limit. * @see #getMaxNumberOfNetworkSuggestionsPerApp() */ public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4; @@ -193,21 +197,27 @@ public class WifiManager { /** * Reason code if one or more of the network suggestions removed does not exist in platform's * database. + * The framework won't remove any suggestions if one or more of suggestions provided + * by {@link #removeNetworkSuggestions(List)} does not exist in database. + * @see WifiNetworkSuggestion#equals(Object) */ public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5; /** * Reason code if one or more of the network suggestions added is not allowed. - * + * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)} + * if one or more of them is not allowed. * This error may be caused by suggestion is using SIM-based encryption method, but calling app * is not carrier privileged. */ public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED = 6; /** - * Reason code if one or more of the network suggestions added is invalid. - * - * Please user {@link WifiNetworkSuggestion.Builder} to create network suggestions. + * Reason code if one or more of the network suggestions added is invalid. Framework will reject + * all the suggestions in the list. + * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)} + * if one or more of them is invalid. + * Please use {@link WifiNetworkSuggestion.Builder} to create network suggestions. */ public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID = 7; @@ -1887,7 +1897,7 @@ public class WifiManager { * <li> If user reset network settings, all added suggestions will be discarded. Apps can use * {@link #getNetworkSuggestions()} to check if their suggestions are in the device.</li> * <li> In-place modification of existing suggestions are allowed. - * <li>If the provided suggestions includes any previously provided suggestions by the app, + * <li> If the provided suggestions include any previously provided suggestions by the app, * previous suggestions will be updated.</li> * <li>If one of the provided suggestions marks a previously unmetered suggestion as metered and * the device is currently connected to that suggested network, then the device will disconnect diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java index ed54ad13e5e1..737b7c7b9caf 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java +++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java @@ -21,7 +21,6 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.MacAddress; -import android.net.MatchAllNetworkSpecifier; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.os.Parcel; @@ -553,13 +552,6 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc /** @hide */ @Override public boolean canBeSatisfiedBy(NetworkSpecifier other) { - if (this == other) { - return true; - } - // Any generic requests should be satisifed by a specific wifi network. - if (other == null || other instanceof MatchAllNetworkSpecifier) { - return true; - } if (other instanceof WifiNetworkAgentSpecifier) { return ((WifiNetworkAgentSpecifier) other).satisfiesNetworkSpecifier(this); } diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index e210e4fec98e..a7b6765e886a 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -16,9 +16,13 @@ package android.net.wifi; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OPEN; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_SAE; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WAPI_PSK; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -507,4 +511,30 @@ public class WifiConfigurationTest { assertEquals(NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED, status2.getNetworkSelectionStatus()); } + + @Test + public void testNeedsPreSharedKey() throws Exception { + WifiConfiguration configuration = new WifiConfiguration(); + + configuration.setSecurityParams(SECURITY_TYPE_PSK); + assertTrue(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_SAE); + assertTrue(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_WAPI_PSK); + assertTrue(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_OPEN); + assertFalse(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_OWE); + assertFalse(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_EAP); + assertFalse(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B); + assertFalse(configuration.needsPreSharedKey()); + } } diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java index 53a7d032da42..fc0ef469ad80 100644 --- a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java +++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java @@ -382,11 +382,11 @@ public class WifiNetworkSpecifierTest { /** * Validate NetworkSpecifier matching. * a) Create a network specifier for WPA_PSK network - * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier} + * b) Ensure that the specifier does not match {@code null} and {@link MatchAllNetworkSpecifier} * specifiers. */ @Test - public void testWifiNetworkSpecifierSatisfiesNullAndAllMatch() { + public void testWifiNetworkSpecifierDoesNotSatisfyNullAndAllMatch() { WifiConfiguration wifiConfiguration = new WifiConfiguration(); wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY; @@ -396,8 +396,8 @@ public class WifiNetworkSpecifierTest { MacAddress.fromString(TEST_BSSID_OUI_MASK)), wifiConfiguration); - assertTrue(specifier.canBeSatisfiedBy(null)); - assertTrue(specifier.canBeSatisfiedBy(new MatchAllNetworkSpecifier())); + assertFalse(specifier.canBeSatisfiedBy(null)); + assertFalse(specifier.canBeSatisfiedBy(new MatchAllNetworkSpecifier())); } /** |