diff options
1700 files changed, 31561 insertions, 14782 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 85323c35aad7..eac416a37c20 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -171,6 +171,7 @@ java_aconfig_library {  // DeviceStateManager  aconfig_declarations {      name: "android.hardware.devicestate.feature.flags-aconfig", +    exportable: true,      package: "android.hardware.devicestate.feature.flags",      srcs: ["core/java/android/hardware/devicestate/feature/*.aconfig"],  } @@ -184,6 +185,7 @@ java_aconfig_library {  // Input  aconfig_declarations {      name: "com.android.hardware.input.input-aconfig", +    exportable: true,      package: "com.android.hardware.input",      srcs: ["core/java/android/hardware/input/*.aconfig"],  } @@ -456,6 +458,7 @@ cc_aconfig_library {  // Hardware  aconfig_declarations {      name: "android.hardware.flags-aconfig", +    exportable: true,      package: "android.hardware.flags",      srcs: ["core/java/android/hardware/flags/*.aconfig"],  } @@ -548,6 +551,7 @@ java_aconfig_library {  // Media Editing  aconfig_declarations {      name: "com.android.media.flags.editing-aconfig", +    exportable: true,      package: "com.android.media.editing.flags",      srcs: [          "media/java/android/media/flags/editing.aconfig", @@ -593,6 +597,7 @@ java_aconfig_library {  // Media TV  aconfig_declarations {      name: "android.media.tv.flags-aconfig", +    exportable: true,      package: "android.media.tv.flags",      srcs: ["media/java/android/media/tv/flags/media_tv.aconfig"],  } @@ -606,6 +611,7 @@ java_aconfig_library {  // OnDeviceIntelligence  aconfig_declarations {      name: "android.app.ondeviceintelligence-aconfig", +    exportable: true,      package: "android.app.ondeviceintelligence.flags",      srcs: ["core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig"],  } @@ -657,6 +663,7 @@ cc_aconfig_library {  // Biometrics  aconfig_declarations {      name: "android.hardware.biometrics.flags-aconfig", +    exportable: true,      package: "android.hardware.biometrics",      srcs: ["core/java/android/hardware/biometrics/flags.aconfig"],  } @@ -734,6 +741,7 @@ java_aconfig_library {  // Broadcast Radio  aconfig_declarations {      name: "android.hardware.radio.flags-aconfig", +    exportable: true,      package: "android.hardware.radio",      srcs: ["core/java/android/hardware/radio/*.aconfig"],  } @@ -768,6 +776,7 @@ java_aconfig_library {  // Content Protection  aconfig_declarations {      name: "android.view.contentprotection.flags-aconfig", +    exportable: true,      package: "android.view.contentprotection.flags",      srcs: ["core/java/android/view/contentprotection/flags/*.aconfig"],  } @@ -794,6 +803,7 @@ java_aconfig_library {  // App prediction  aconfig_declarations {      name: "android.service.appprediction.flags-aconfig", +    exportable: true,      package: "android.service.appprediction.flags",      srcs: ["core/java/android/service/appprediction/flags/*.aconfig"],  } @@ -807,6 +817,7 @@ java_aconfig_library {  // Controls  aconfig_declarations {      name: "android.service.controls.flags-aconfig", +    exportable: true,      package: "android.service.controls.flags",      srcs: ["core/java/android/service/controls/flags/*.aconfig"],  } @@ -820,6 +831,7 @@ java_aconfig_library {  // Voice  aconfig_declarations {      name: "android.service.voice.flags-aconfig", +    exportable: true,      package: "android.service.voice.flags",      srcs: ["core/java/android/service/voice/flags/*.aconfig"],  } @@ -849,6 +861,7 @@ java_aconfig_library {  // Companion  aconfig_declarations {      name: "android.companion.flags-aconfig", +    exportable: true,      package: "android.companion",      srcs: ["core/java/android/companion/*.aconfig"],  } @@ -862,6 +875,7 @@ java_aconfig_library {  // Networking  aconfig_declarations {      name: "android.net.platform.flags-aconfig", +    exportable: true,      package: "android.net.platform.flags",      srcs: ["core/java/android/net/flags.aconfig"],      visibility: [":__subpackages__"], @@ -870,6 +884,7 @@ aconfig_declarations {  // Thread network  aconfig_declarations {      name: "com.android.net.thread.platform.flags-aconfig", +    exportable: true,      package: "com.android.net.thread.platform.flags",      srcs: ["core/java/android/net/thread/flags.aconfig"],  } @@ -967,6 +982,7 @@ java_aconfig_library {  aconfig_declarations {      name: "framework-jobscheduler-job.flags-aconfig",      package: "android.app.job", +    exportable: true,      srcs: ["apex/jobscheduler/framework/aconfig/job.aconfig"],  } @@ -1032,6 +1048,7 @@ java_aconfig_library {  // Smartspace  aconfig_declarations {      name: "android.app.smartspace.flags-aconfig", +    exportable: true,      package: "android.app.smartspace.flags",      srcs: ["core/java/android/app/smartspace/flags.aconfig"],  } @@ -1065,6 +1082,7 @@ java_aconfig_library {  // USB  aconfig_declarations {      name: "android.hardware.usb.flags-aconfig", +    exportable: true,      package: "android.hardware.usb.flags",      srcs: ["core/java/android/hardware/usb/flags/*.aconfig"],  } @@ -1145,6 +1163,7 @@ java_aconfig_library {  // Provider  aconfig_declarations {      name: "android.provider.flags-aconfig", +    exportable: true,      package: "android.provider",      srcs: ["core/java/android/provider/*.aconfig"],  } @@ -1165,6 +1184,7 @@ java_aconfig_library {  // Speech  aconfig_declarations {      name: "android.speech.flags-aconfig", +    exportable: true,      package: "android.speech.flags",      srcs: ["core/java/android/speech/flags/*.aconfig"],  } @@ -1185,6 +1205,7 @@ java_aconfig_library {  // Content  aconfig_declarations {      name: "android.content.flags-aconfig", +    exportable: true,      package: "android.content.flags",      srcs: ["core/java/android/content/flags/flags.aconfig"],  } @@ -1211,6 +1232,7 @@ java_aconfig_library {  // CrashRecovery Module  aconfig_declarations {      name: "android.crashrecovery.flags-aconfig", +    exportable: true,      package: "android.crashrecovery.flags",      srcs: ["packages/CrashRecovery/aconfig/flags.aconfig"],  } @@ -1221,6 +1243,13 @@ java_aconfig_library {      defaults: ["framework-minus-apex-aconfig-java-defaults"],  } +java_aconfig_library { +    name: "android.crashrecovery.flags-aconfig-java-host", +    aconfig_declarations: "android.crashrecovery.flags-aconfig", +    defaults: ["framework-minus-apex-aconfig-java-defaults"], +    host_supported: true, +} +  // Backup  java_aconfig_library {      name: "backup_flags_lib", @@ -1249,6 +1278,7 @@ java_aconfig_library {  // Wearable Sensing  aconfig_declarations {      name: "android.app.wearable.flags-aconfig", +    exportable: true,      package: "android.app.wearable",      srcs: ["core/java/android/app/wearable/*.aconfig"],  } diff --git a/apct-tests/perftests/inputmethod/AndroidManifest.xml b/apct-tests/perftests/inputmethod/AndroidManifest.xml index 3eea418fe5c7..5dd6ccccfb1c 100644 --- a/apct-tests/perftests/inputmethod/AndroidManifest.xml +++ b/apct-tests/perftests/inputmethod/AndroidManifest.xml @@ -22,7 +22,8 @@      <application>          <uses-library android:name="android.test.runner" />          <activity android:name="android.perftests.utils.PerfTestActivity" -            android:exported="true"> +                  android:theme="@android:style/Theme.DeviceDefault.NoActionBar" +                  android:exported="true">            <intent-filter>              <action android:name="com.android.perftests.core.PERFTEST" />            </intent-filter> diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java index f3bea17b2f0d..0c2ee8cb238a 100644 --- a/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java +++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java @@ -19,7 +19,9 @@ package android.perftests.utils;  import android.app.Activity;  import android.content.Context;  import android.content.Intent; +import android.graphics.Insets;  import android.os.Bundle; +import android.view.WindowInsets;  import android.view.WindowManager;  import android.widget.EditText;  import android.widget.LinearLayout; @@ -42,6 +44,11 @@ public class PerfTestActivity extends Activity {          if (getIntent().getBooleanExtra(INTENT_EXTRA_ADD_EDIT_TEXT, false)) {              final LinearLayout layout = new LinearLayout(this);              layout.setOrientation(LinearLayout.VERTICAL); +            layout.setOnApplyWindowInsetsListener((v, w) -> { +                final Insets insets = w.getSystemWindowInsets(); +                v.setPadding(insets.left, insets.top, insets.right, insets.bottom); +                return WindowInsets.CONSUMED; +            });              final EditText editText = new EditText(this);              editText.setId(ID_EDITOR); diff --git a/apex/jobscheduler/service/aconfig/device_idle.aconfig b/apex/jobscheduler/service/aconfig/device_idle.aconfig index e8c99b12828f..c4d0d1850a18 100644 --- a/apex/jobscheduler/service/aconfig/device_idle.aconfig +++ b/apex/jobscheduler/service/aconfig/device_idle.aconfig @@ -2,6 +2,16 @@ package: "com.android.server.deviceidle"  container: "system"  flag { +  name: "remove_idle_location" +  namespace: "location" +  description: "Remove DeviceIdleController usage of location" +  bug: "332770178" +  metadata { +    purpose: PURPOSE_BUGFIX +  } +} + +flag {      name: "disable_wakelocks_in_light_idle"      namespace: "backstage_power"      description: "Disable wakelocks for background apps while Light Device Idle is active" diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 4832ea624bd7..11fa7b75182f 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -109,6 +109,7 @@ import com.android.modules.expresslog.Counter;  import com.android.server.am.BatteryStatsService;  import com.android.server.deviceidle.ConstraintController;  import com.android.server.deviceidle.DeviceIdleConstraintTracker; +import com.android.server.deviceidle.Flags;  import com.android.server.deviceidle.IDeviceIdleConstraint;  import com.android.server.deviceidle.TvConstraintController;  import com.android.server.net.NetworkPolicyManagerInternal; @@ -2558,7 +2559,7 @@ public class DeviceIdleController extends SystemService          }          boolean isLocationPrefetchEnabled() { -            return mContext.getResources().getBoolean( +            return !Flags.removeIdleLocation() && mContext.getResources().getBoolean(                     com.android.internal.R.bool.config_autoPowerModePrefetchLocation);          } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java index 096238aeda7c..012ede274bc1 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java @@ -1737,17 +1737,6 @@ class JobConcurrencyManager {                      continue;                  } -                if (!nextPending.isReady()) { -                    // This could happen when the job count reached its quota, the constrains -                    // for the job has been updated but hasn't been removed from the pending -                    // queue yet. -                    if (DEBUG) { -                        Slog.w(TAG, "Pending+not ready job: " + nextPending); -                    } -                    pendingJobQueue.remove(nextPending); -                    continue; -                } -                  if (DEBUG && isSimilarJobRunningLocked(nextPending)) {                      Slog.w(TAG, "Already running similar job to: " + nextPending);                  } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java index cfbfa5dce399..3c9648b20003 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java @@ -512,7 +512,7 @@ public final class QuotaController extends StateController {      /** An app has reached its quota. The message should contain a {@link UserPackage} object. */      @VisibleForTesting -    static final int MSG_REACHED_TIME_QUOTA = 0; +    static final int MSG_REACHED_QUOTA = 0;      /** Drop any old timing sessions. */      private static final int MSG_CLEAN_UP_SESSIONS = 1;      /** Check if a package is now within its quota. */ @@ -524,7 +524,7 @@ public final class QuotaController extends StateController {       * object.       */      @VisibleForTesting -    static final int MSG_REACHED_EJ_TIME_QUOTA = 4; +    static final int MSG_REACHED_EJ_QUOTA = 4;      /**       * Process a new {@link UsageEvents.Event}. The event will be the message's object and the       * userId will the first arg. @@ -533,11 +533,6 @@ public final class QuotaController extends StateController {      /** A UID's free quota grace period has ended. */      @VisibleForTesting      static final int MSG_END_GRACE_PERIOD = 6; -    /** -     * An app has reached its job count quota. The message should contain a {@link UserPackage} -     * object. -     */ -    static final int MSG_REACHED_COUNT_QUOTA = 7;      public QuotaController(@NonNull JobSchedulerService service,              @NonNull BackgroundJobsController backgroundJobsController, @@ -879,37 +874,17 @@ public final class QuotaController extends StateController {      }      @VisibleForTesting -    @GuardedBy("mLock")      boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {          final int standbyBucket = jobStatus.getEffectiveStandbyBucket();          // A job is within quota if one of the following is true:          //   1. it was started while the app was in the TOP state          //   2. the app is currently in the foreground          //   3. the app overall is within its quota -        if (jobStatus.shouldTreatAsUserInitiatedJob() +        return jobStatus.shouldTreatAsUserInitiatedJob()                  || isTopStartedJobLocked(jobStatus) -                || isUidInForeground(jobStatus.getSourceUid())) { -            return true; -        } - -        if (standbyBucket == NEVER_INDEX) return false; - -        if (isQuotaFreeLocked(standbyBucket)) return true; - -        final ExecutionStats stats = getExecutionStatsLocked(jobStatus.getSourceUserId(), -                jobStatus.getSourcePackageName(), standbyBucket); -        if (!(getRemainingExecutionTimeLocked(stats) > 0)) { -            // Out of execution time quota. -            return false; -        } - -        if (mService.isCurrentlyRunningLocked(jobStatus)) { -            // if job is running, considered as in quota so it can keep running. -            return true; -        } - -        // Check if the app is within job count quota. -        return isUnderJobCountQuotaLocked(stats) && isUnderSessionCountQuotaLocked(stats); +                || isUidInForeground(jobStatus.getSourceUid()) +                || isWithinQuotaLocked( +                jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);      }      @GuardedBy("mLock") @@ -934,11 +909,12 @@ public final class QuotaController extends StateController {          ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);          // TODO: use a higher minimum remaining time for jobs with MINIMUM priority          return getRemainingExecutionTimeLocked(stats) > 0 -                && isUnderJobCountQuotaLocked(stats) -                && isUnderSessionCountQuotaLocked(stats); +                && isUnderJobCountQuotaLocked(stats, standbyBucket) +                && isUnderSessionCountQuotaLocked(stats, standbyBucket);      } -    private boolean isUnderJobCountQuotaLocked(@NonNull ExecutionStats stats) { +    private boolean isUnderJobCountQuotaLocked(@NonNull ExecutionStats stats, +            final int standbyBucket) {          final long now = sElapsedRealtimeClock.millis();          final boolean isUnderAllowedTimeQuota =                  (stats.jobRateLimitExpirationTimeElapsed <= now @@ -947,7 +923,8 @@ public final class QuotaController extends StateController {                  && stats.bgJobCountInWindow < stats.jobCountLimit;      } -    private boolean isUnderSessionCountQuotaLocked(@NonNull ExecutionStats stats) { +    private boolean isUnderSessionCountQuotaLocked(@NonNull ExecutionStats stats, +            final int standbyBucket) {          final long now = sElapsedRealtimeClock.millis();          final boolean isUnderAllowedTimeQuota = (stats.sessionRateLimitExpirationTimeElapsed <= now                  || stats.sessionCountInRateLimitingWindow < mMaxSessionCountPerRateLimitingWindow); @@ -1472,7 +1449,6 @@ public final class QuotaController extends StateController {                  stats.jobCountInRateLimitingWindow = 0;              }              stats.jobCountInRateLimitingWindow += count; -            stats.bgJobCountInWindow += count;          }      } @@ -1707,11 +1683,10 @@ public final class QuotaController extends StateController {                      changedJobs.add(js);                  }              } else if (realStandbyBucket != EXEMPTED_INDEX && realStandbyBucket != ACTIVE_INDEX -                    && realStandbyBucket == js.getEffectiveStandbyBucket() -                    && !mService.isCurrentlyRunningLocked(js)) { +                    && realStandbyBucket == js.getEffectiveStandbyBucket()) {                  // An app in the ACTIVE bucket may be out of quota while the job could be in quota                  // for some reason. Therefore, avoid setting the real value here and check each job -                // individually. Running job need to determine its own quota status as well. +                // individually.                  if (setConstraintSatisfied(js, nowElapsed, realInQuota, isWithinEJQuota)) {                      changedJobs.add(js);                  } @@ -1830,8 +1805,9 @@ public final class QuotaController extends StateController {          }          ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket); -        final boolean isUnderJobCountQuota = isUnderJobCountQuotaLocked(stats); -        final boolean isUnderTimingSessionCountQuota = isUnderSessionCountQuotaLocked(stats); +        final boolean isUnderJobCountQuota = isUnderJobCountQuotaLocked(stats, standbyBucket); +        final boolean isUnderTimingSessionCountQuota = isUnderSessionCountQuotaLocked(stats, +                standbyBucket);          final long remainingEJQuota = getRemainingEJExecutionTimeLocked(userId, packageName);          final boolean inRegularQuota = @@ -2150,11 +2126,6 @@ public final class QuotaController extends StateController {                  mBgJobCount++;                  if (mRegularJobTimer) {                      incrementJobCountLocked(mPkg.userId, mPkg.packageName, 1); -                    final ExecutionStats stats = getExecutionStatsLocked(mPkg.userId, -                            mPkg.packageName, jobStatus.getEffectiveStandbyBucket(), false); -                    if (stats.bgJobCountInWindow >= stats.jobCountLimit) { -                        mHandler.obtainMessage(MSG_REACHED_COUNT_QUOTA, mPkg).sendToTarget(); -                    }                  }                  if (mRunningBgJobs.size() == 1) {                      // Started tracking the first job. @@ -2286,6 +2257,7 @@ public final class QuotaController extends StateController {                      // repeatedly plugged in and unplugged, or an app changes foreground state                      // very frequently, the job count for a package may be artificially high.                      mBgJobCount = mRunningBgJobs.size(); +                      if (mRegularJobTimer) {                          incrementJobCountLocked(mPkg.userId, mPkg.packageName, mBgJobCount);                          // Starting the timer means that all cached execution stats are now @@ -2312,8 +2284,7 @@ public final class QuotaController extends StateController {                      return;                  }                  Message msg = mHandler.obtainMessage( -                        mRegularJobTimer ? MSG_REACHED_TIME_QUOTA : MSG_REACHED_EJ_TIME_QUOTA, -                        mPkg); +                        mRegularJobTimer ? MSG_REACHED_QUOTA : MSG_REACHED_EJ_QUOTA, mPkg);                  final long timeRemainingMs = mRegularJobTimer                          ? getTimeUntilQuotaConsumedLocked(mPkg.userId, mPkg.packageName)                          : getTimeUntilEJQuotaConsumedLocked(mPkg.userId, mPkg.packageName); @@ -2330,7 +2301,7 @@ public final class QuotaController extends StateController {          private void cancelCutoff() {              mHandler.removeMessages( -                    mRegularJobTimer ? MSG_REACHED_TIME_QUOTA : MSG_REACHED_EJ_TIME_QUOTA, mPkg); +                    mRegularJobTimer ? MSG_REACHED_QUOTA : MSG_REACHED_EJ_QUOTA, mPkg);          }          public void dump(IndentingPrintWriter pw, Predicate<JobStatus> predicate) { @@ -2586,7 +2557,7 @@ public final class QuotaController extends StateController {                      break;                  default:                      if (DEBUG) { -                        Slog.d(TAG, "Dropping usage event " + event.getEventType()); +                        Slog.d(TAG, "Dropping event " + event.getEventType());                      }                      break;              } @@ -2695,7 +2666,7 @@ public final class QuotaController extends StateController {          public void handleMessage(Message msg) {              synchronized (mLock) {                  switch (msg.what) { -                    case MSG_REACHED_TIME_QUOTA: { +                    case MSG_REACHED_QUOTA: {                          UserPackage pkg = (UserPackage) msg.obj;                          if (DEBUG) {                              Slog.d(TAG, "Checking if " + pkg + " has reached its quota."); @@ -2714,7 +2685,7 @@ public final class QuotaController extends StateController {                              // This could potentially happen if an old session phases out while a                              // job is currently running.                              // Reschedule message -                            Message rescheduleMsg = obtainMessage(MSG_REACHED_TIME_QUOTA, pkg); +                            Message rescheduleMsg = obtainMessage(MSG_REACHED_QUOTA, pkg);                              timeRemainingMs = getTimeUntilQuotaConsumedLocked(pkg.userId,                                      pkg.packageName);                              if (DEBUG) { @@ -2724,7 +2695,7 @@ public final class QuotaController extends StateController {                          }                          break;                      } -                    case MSG_REACHED_EJ_TIME_QUOTA: { +                    case MSG_REACHED_EJ_QUOTA: {                          UserPackage pkg = (UserPackage) msg.obj;                          if (DEBUG) {                              Slog.d(TAG, "Checking if " + pkg + " has reached its EJ quota."); @@ -2742,7 +2713,7 @@ public final class QuotaController extends StateController {                              // This could potentially happen if an old session phases out while a                              // job is currently running.                              // Reschedule message -                            Message rescheduleMsg = obtainMessage(MSG_REACHED_EJ_TIME_QUOTA, pkg); +                            Message rescheduleMsg = obtainMessage(MSG_REACHED_EJ_QUOTA, pkg);                              timeRemainingMs = getTimeUntilEJQuotaConsumedLocked(                                      pkg.userId, pkg.packageName);                              if (DEBUG) { @@ -2752,18 +2723,6 @@ public final class QuotaController extends StateController {                          }                          break;                      } -                    case MSG_REACHED_COUNT_QUOTA: { -                        UserPackage pkg = (UserPackage) msg.obj; -                        if (DEBUG) { -                            Slog.d(TAG, pkg + " has reached its count quota."); -                        } - -                        mStateChangedListener.onControllerStateChanged( -                                maybeUpdateConstraintForPkgLocked( -                                        sElapsedRealtimeClock.millis(), -                                        pkg.userId, pkg.packageName)); -                        break; -                    }                      case MSG_CLEAN_UP_SESSIONS:                          if (DEBUG) {                              Slog.d(TAG, "Cleaning up timing sessions."); diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp index 1b1bc6b9afdb..f56a95011dee 100644 --- a/api/StubLibraries.bp +++ b/api/StubLibraries.bp @@ -54,34 +54,34 @@ non_updatable_exportable_droidstubs {              baseline_file: ":non-updatable-lint-baseline.txt",          },      }, -    dists: [ -        { -            targets: ["sdk"], -            dir: "apistubs/android/public/api", -            dest: "android-non-updatable.txt", -        }, -        { -            targets: ["sdk"], -            dir: "apistubs/android/public/api", -            dest: "android-non-updatable-removed.txt", -        }, -    ],      soong_config_variables: {          release_hidden_api_exportable_stubs: {              dists: [                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/public/api", +                    dest: "android-non-updatable.txt",                      tag: ".exportable.api.txt",                  },                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/public/api", +                    dest: "android-non-updatable-removed.txt",                      tag: ".exportable.removed-api.txt",                  },              ],              conditions_default: {                  dists: [                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/public/api", +                        dest: "android-non-updatable.txt",                          tag: ".api.txt",                      },                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/public/api", +                        dest: "android-non-updatable-removed.txt",                          tag: ".removed-api.txt",                      },                  ], @@ -134,34 +134,34 @@ non_updatable_exportable_droidstubs {              baseline_file: ":non-updatable-system-lint-baseline.txt",          },      }, -    dists: [ -        { -            targets: ["sdk"], -            dir: "apistubs/android/system/api", -            dest: "android-non-updatable.txt", -        }, -        { -            targets: ["sdk"], -            dir: "apistubs/android/system/api", -            dest: "android-non-updatable-removed.txt", -        }, -    ],      soong_config_variables: {          release_hidden_api_exportable_stubs: {              dists: [                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/system/api", +                    dest: "android-non-updatable.txt",                      tag: ".exportable.api.txt",                  },                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/system/api", +                    dest: "android-non-updatable-removed.txt",                      tag: ".exportable.removed-api.txt",                  },              ],              conditions_default: {                  dists: [                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/system/api", +                        dest: "android-non-updatable.txt",                          tag: ".api.txt",                      },                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/system/api", +                        dest: "android-non-updatable-removed.txt",                          tag: ".removed-api.txt",                      },                  ], @@ -189,56 +189,58 @@ non_updatable_exportable_droidstubs {              baseline_file: ":non-updatable-test-lint-baseline.txt",          },      }, -    dists: [ -        { -            targets: ["sdk"], -            dir: "apistubs/android/test/api", -            dest: "android.txt", -        }, -        { -            targets: ["sdk"], -            dir: "apistubs/android/test/api", -            dest: "removed.txt", -        }, -        { -            targets: ["sdk"], -            dir: "apistubs/android/test/api", -            dest: "android-non-updatable.txt", -        }, -        { -            targets: ["sdk"], -            dir: "apistubs/android/test/api", -            dest: "android-non-updatable-removed.txt", -        }, -    ],      soong_config_variables: {          release_hidden_api_exportable_stubs: {              dists: [                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/test/api", +                    dest: "android.txt",                      tag: ".exportable.api.txt",                  },                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/test/api", +                    dest: "removed.txt",                      tag: ".exportable.removed-api.txt",                  },                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/test/api", +                    dest: "android-non-updatable.txt",                      tag: ".exportable.api.txt",                  },                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/test/api", +                    dest: "android-non-updatable-removed.txt",                      tag: ".exportable.removed-api.txt",                  },              ],              conditions_default: {                  dists: [                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/test/api", +                        dest: "android.txt",                          tag: ".api.txt",                      },                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/test/api", +                        dest: "removed.txt",                          tag: ".removed-api.txt",                      },                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/test/api", +                        dest: "android-non-updatable.txt",                          tag: ".api.txt",                      },                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/test/api", +                        dest: "android-non-updatable-removed.txt",                          tag: ".removed-api.txt",                      },                  ], @@ -271,34 +273,34 @@ non_updatable_exportable_droidstubs {              baseline_file: ":non-updatable-module-lib-lint-baseline.txt",          },      }, -    dists: [ -        { -            targets: ["sdk"], -            dir: "apistubs/android/module-lib/api", -            dest: "android-non-updatable.txt", -        }, -        { -            targets: ["sdk"], -            dir: "apistubs/android/module-lib/api", -            dest: "android-non-updatable-removed.txt", -        }, -    ],      soong_config_variables: {          release_hidden_api_exportable_stubs: {              dists: [                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/module-lib/api", +                    dest: "android-non-updatable.txt",                      tag: ".exportable.api.txt",                  },                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/module-lib/api", +                    dest: "android-non-updatable-removed.txt",                      tag: ".exportable.removed-api.txt",                  },              ],              conditions_default: {                  dists: [                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/module-lib/api", +                        dest: "android-non-updatable.txt",                          tag: ".api.txt",                      },                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/module-lib/api", +                        dest: "android-non-updatable-removed.txt",                          tag: ".removed-api.txt",                      },                  ], diff --git a/api/coverage/tools/Android.bp b/api/coverage/tools/Android.bp index 3e169120dc48..caaca99bdc45 100644 --- a/api/coverage/tools/Android.bp +++ b/api/coverage/tools/Android.bp @@ -30,3 +30,24 @@ java_library_host {          type: "full",      },  } + +java_test_host { +    name: "extract-flagged-apis-test", +    srcs: ["ExtractFlaggedApisTest.kt"], +    libs: [ +        "extract_flagged_apis_proto", +        "junit", +        "libprotobuf-java-full", +    ], +    static_libs: [ +        "truth", +        "truth-liteproto-extension", +        "truth-proto-extension", +    ], +    data: [ +        ":extract-flagged-apis", +    ], +    test_options: { +        unit_test: true, +    }, +} diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt index d5adfd09b994..5efda98a1518 100644 --- a/api/coverage/tools/ExtractFlaggedApis.kt +++ b/api/coverage/tools/ExtractFlaggedApis.kt @@ -17,6 +17,7 @@  package android.platform.coverage  import com.android.tools.metalava.model.ClassItem +import com.android.tools.metalava.model.Item  import com.android.tools.metalava.model.MethodItem  import com.android.tools.metalava.model.text.ApiFile  import java.io.File @@ -28,12 +29,10 @@ fun main(args: Array<String>) {      val builder = FlagApiMap.newBuilder()      for (pkg in cb.getPackages().packages) {          val packageName = pkg.qualifiedName() -        pkg.allClasses() -            .filter { it.methods().size > 0 } -            .forEach { -                extractFlaggedApisFromClass(it, it.methods(), packageName, builder) -                extractFlaggedApisFromClass(it, it.constructors(), packageName, builder) -            } +        pkg.allClasses().forEach { +            extractFlaggedApisFromClass(it, it.methods(), packageName, builder) +            extractFlaggedApisFromClass(it, it.constructors(), packageName, builder) +        }      }      val flagApiMap = builder.build()      FileWriter(args[1]).use { it.write(flagApiMap.toString()) } @@ -45,20 +44,10 @@ fun extractFlaggedApisFromClass(      packageName: String,      builder: FlagApiMap.Builder  ) { -    val classFlag = -        classItem.modifiers -            .findAnnotation("android.annotation.FlaggedApi") -            ?.findAttribute("value") -            ?.value -            ?.value() as? String +    if (methods.isEmpty()) return +    val classFlag = getClassFlag(classItem)      for (method in methods) { -        val methodFlag = -            method.modifiers -                .findAnnotation("android.annotation.FlaggedApi") -                ?.findAttribute("value") -                ?.value -                ?.value() as? String -                ?: classFlag +        val methodFlag = getFlagAnnotation(method) ?: classFlag          val api =              JavaMethod.newBuilder()                  .setPackageName(packageName) @@ -82,3 +71,23 @@ fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: St          builder.putFlagToApi(flag, apis)      }  } + +fun getClassFlag(classItem: ClassItem): String? { +    var classFlag = getFlagAnnotation(classItem) +    var cur = classItem +    // If a class is not an inner class, use its @FlaggedApi annotation value. +    // Otherwise, use the flag value of the closest outer class that is annotated by @FlaggedApi. +    while (cur.isInnerClass() && classFlag == null) { +        cur = cur.parent() as ClassItem +        classFlag = getFlagAnnotation(cur) +    } +    return classFlag +} + +fun getFlagAnnotation(item: Item): String? { +    return item.modifiers +        .findAnnotation("android.annotation.FlaggedApi") +        ?.findAttribute("value") +        ?.value +        ?.value() as? String +} diff --git a/api/coverage/tools/ExtractFlaggedApisTest.kt b/api/coverage/tools/ExtractFlaggedApisTest.kt new file mode 100644 index 000000000000..427be36254d3 --- /dev/null +++ b/api/coverage/tools/ExtractFlaggedApisTest.kt @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.platform.coverage + +import com.google.common.truth.extensions.proto.ProtoTruth.assertThat +import com.google.protobuf.TextFormat +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.StandardOpenOption +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class ExtractFlaggedApisTest { + +    companion object { +        const val COMMAND = "java -jar extract-flagged-apis.jar %s %s" +    } + +    private var apiTextFile: Path = Files.createTempFile("current", ".txt") +    private var flagToApiMap: Path = Files.createTempFile("flag_api_map", ".textproto") + +    @Before +    fun setup() { +        apiTextFile = Files.createTempFile("current", ".txt") +        flagToApiMap = Files.createTempFile("flag_api_map", ".textproto") +    } + +    @After +    fun cleanup() { +        Files.deleteIfExists(apiTextFile) +        Files.deleteIfExists(flagToApiMap) +    } + +    @Test +    fun extractFlaggedApis_onlyMethodFlag_useMethodFlag() { +        val apiText = +            """ +            // Signature format: 2.0 +            package android.net.ipsec.ike { +              public final class IkeSession implements java.lang.AutoCloseable { +                method @FlaggedApi("com.android.ipsec.flags.dumpsys_api") public void dump(@NonNull java.io.PrintWriter); +              } +            } +        """ +                .trimIndent() +        Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND) + +        val process = Runtime.getRuntime().exec(createCommand()) +        process.waitFor() + +        val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8) +        val result = TextFormat.parse(content, FlagApiMap::class.java) + +        val expected = FlagApiMap.newBuilder() +        val api = +            JavaMethod.newBuilder() +                .setPackageName("android.net.ipsec.ike") +                .setClassName("IkeSession") +                .setMethodName("dump") +        api.addParameters("java.io.PrintWriter") +        addFlaggedApi(expected, api, "com.android.ipsec.flags.dumpsys_api") +        assertThat(result).isEqualTo(expected.build()) +    } + +    @Test +    fun extractFlaggedApis_onlyClassFlag_useClassFlag() { +        val apiText = +            """ +            // Signature format: 2.0 +            package android.net.ipsec.ike { +              @FlaggedApi("com.android.ipsec.flags.dumpsys_api") public final class IkeSession implements java.lang.AutoCloseable { +                method public void dump(@NonNull java.io.PrintWriter); +              } +            } +        """ +                .trimIndent() +        Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND) + +        val process = Runtime.getRuntime().exec(createCommand()) +        process.waitFor() + +        val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8) +        val result = TextFormat.parse(content, FlagApiMap::class.java) + +        val expected = FlagApiMap.newBuilder() +        val api = +            JavaMethod.newBuilder() +                .setPackageName("android.net.ipsec.ike") +                .setClassName("IkeSession") +                .setMethodName("dump") +        api.addParameters("java.io.PrintWriter") +        addFlaggedApi(expected, api, "com.android.ipsec.flags.dumpsys_api") +        assertThat(result).isEqualTo(expected.build()) +    } + +    @Test +    fun extractFlaggedApis_flaggedConstructorsAreFlaggedApis() { +        val apiText = +            """ +            // Signature format: 2.0 +            package android.app.pinner { +              @FlaggedApi("android.app.pinner_service_client_api") public class PinnerServiceClient { +                ctor @FlaggedApi("android.app.pinner_service_client_api") public PinnerServiceClient(); +              } +            } +        """ +                .trimIndent() +        Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND) + +        val process = Runtime.getRuntime().exec(createCommand()) +        process.waitFor() + +        val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8) +        val result = TextFormat.parse(content, FlagApiMap::class.java) + +        val expected = FlagApiMap.newBuilder() +        val api = +            JavaMethod.newBuilder() +                .setPackageName("android.app.pinner") +                .setClassName("PinnerServiceClient") +                .setMethodName("PinnerServiceClient") +        addFlaggedApi(expected, api, "android.app.pinner_service_client_api") +        assertThat(result).isEqualTo(expected.build()) +    } + +    @Test +    fun extractFlaggedApis_unflaggedNestedClassShouldUseOuterClassFlag() { +        val apiText = +            """ +            // Signature format: 2.0 +            package android.location.provider { +              @FlaggedApi(Flags.FLAG_NEW_GEOCODER) public final class ForwardGeocodeRequest implements android.os.Parcelable { +                method public int describeContents(); +              } +              public static final class ForwardGeocodeRequest.Builder { +                method @NonNull public android.location.provider.ForwardGeocodeRequest build(); +              } +            } +        """ +                .trimIndent() +        Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND) + +        val process = Runtime.getRuntime().exec(createCommand()) +        process.waitFor() + +        val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8) +        val result = TextFormat.parse(content, FlagApiMap::class.java) + +        val expected = FlagApiMap.newBuilder() +        val api1 = +            JavaMethod.newBuilder() +                .setPackageName("android.location.provider") +                .setClassName("ForwardGeocodeRequest") +                .setMethodName("describeContents") +        addFlaggedApi(expected, api1, "Flags.FLAG_NEW_GEOCODER") +        val api2 = +            JavaMethod.newBuilder() +                .setPackageName("android.location.provider") +                .setClassName("ForwardGeocodeRequest.Builder") +                .setMethodName("build") +        addFlaggedApi(expected, api2, "Flags.FLAG_NEW_GEOCODER") +        assertThat(result).ignoringRepeatedFieldOrder().isEqualTo(expected.build()) +    } + +    @Test +    fun extractFlaggedApis_unflaggedNestedClassShouldUseOuterClassFlag_deeplyNested() { +        val apiText = +            """ +            // Signature format: 2.0 +            package android.package.xyz { +              @FlaggedApi(outer_class_flag) public final class OuterClass { +                method public int apiInOuterClass(); +              } +              public final class OuterClass.Deeply.NestedClass { +                method public void apiInNestedClass(); +              } +            } +        """ +                .trimIndent() +        Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND) + +        val process = Runtime.getRuntime().exec(createCommand()) +        process.waitFor() + +        val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8) +        val result = TextFormat.parse(content, FlagApiMap::class.java) + +        val expected = FlagApiMap.newBuilder() +        val api1 = +            JavaMethod.newBuilder() +                .setPackageName("android.package.xyz") +                .setClassName("OuterClass") +                .setMethodName("apiInOuterClass") +        addFlaggedApi(expected, api1, "outer_class_flag") +        val api2 = +            JavaMethod.newBuilder() +                .setPackageName("android.package.xyz") +                .setClassName("OuterClass.Deeply.NestedClass") +                .setMethodName("apiInNestedClass") +        addFlaggedApi(expected, api2, "outer_class_flag") +        assertThat(result).ignoringRepeatedFieldOrder().isEqualTo(expected.build()) +    } + +    private fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: String) { +        if (builder.containsFlagToApi(flag)) { +            val updatedApis = +                builder.getFlagToApiOrThrow(flag).toBuilder().addJavaMethods(api).build() +            builder.putFlagToApi(flag, updatedApis) +        } else { +            val apis = FlaggedApis.newBuilder().addJavaMethods(api).build() +            builder.putFlagToApi(flag, apis) +        } +    } + +    private fun createCommand(): Array<String> { +        val command = +            String.format(COMMAND, apiTextFile.toAbsolutePath(), flagToApiMap.toAbsolutePath()) +        return command.split(" ").toTypedArray() +    } +} diff --git a/core/api/current.txt b/core/api/current.txt index 13d5e03da7ed..c189a24c84ae 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -54479,7 +54479,6 @@ package android.view {      field @FlaggedApi("com.android.window.flags.cover_display_opt_in") public static final int COMPAT_SMALL_COVER_SCREEN_OPT_IN = 1; // 0x1      field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";      field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"; -    field @FlaggedApi("com.android.window.flags.untrusted_embedding_state_sharing") public static final String PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING = "android.window.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING";      field public static final String PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION = "android.window.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION";      field public static final String PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH = "android.window.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH";      field public static final String PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE = "android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE"; diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 3b988e195597..443a6c0e91e6 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -589,6 +589,7 @@ package android.app.admin {      method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceNetworkLogs();      method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void forceRemoveActiveAdmin(@NonNull android.content.ComponentName, int);      method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceSecurityLogs(); +    method @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_internal_bug_fix_enabled") @RequiresPermission("android.permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT") public void forceSetMaxPolicyStorageLimit(int);      method public void forceUpdateUserSetupComplete(int);      method @NonNull public java.util.Set<java.lang.String> getDefaultCrossProfilePackages();      method @Deprecated public int getDeviceOwnerType(@NonNull android.content.ComponentName); @@ -599,6 +600,7 @@ package android.app.admin {      method public long getLastSecurityLogRetrievalTime();      method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle);      method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public java.util.Set<java.lang.String> getPolicyExemptApps(); +    method @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_internal_bug_fix_enabled") @RequiresPermission("android.permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT") public int getPolicySizeForAdmin(@NonNull android.app.admin.EnforcingAdmin);      method public boolean isCurrentInputMethodSetByOwner();      method public boolean isFactoryResetProtectionPolicySupported();      method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean isNewUserDisclaimerAcknowledged(); @@ -667,6 +669,10 @@ package android.app.admin {      field @NonNull public static final android.app.admin.DpcAuthority DPC_AUTHORITY;    } +  public final class EnforcingAdmin implements android.os.Parcelable { +    ctor @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_internal_bug_fix_enabled") public EnforcingAdmin(@NonNull String, @NonNull android.app.admin.Authority, @NonNull android.os.UserHandle, @Nullable android.content.ComponentName); +  } +    public final class FlagUnion extends android.app.admin.ResolutionMechanism<java.lang.Integer> {      method public int describeContents();      method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -4129,7 +4135,6 @@ package android.window {      method @NonNull public static String typeToString(int);      method public void writeToParcel(@NonNull android.os.Parcel, int);      field @NonNull public static final android.os.Parcelable.Creator<android.window.BackNavigationInfo> CREATOR; -    field public static final String KEY_TRIGGER_BACK = "TriggerBack";      field public static final int TYPE_CALLBACK = 4; // 0x4      field public static final int TYPE_CROSS_ACTIVITY = 2; // 0x2      field public static final int TYPE_CROSS_TASK = 3; // 0x3 diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3575545e202d..eaa23b9db166 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2608,7 +2608,14 @@ public final class ActivityThread extends ClientTransactionHandler                      break;                  case EXECUTE_TRANSACTION:                      final ClientTransaction transaction = (ClientTransaction) msg.obj; -                    mTransactionExecutor.execute(transaction); +                    final ClientTransactionListenerController controller = +                            ClientTransactionListenerController.getInstance(); +                    controller.onClientTransactionStarted(); +                    try { +                        mTransactionExecutor.execute(transaction); +                    } finally { +                        controller.onClientTransactionFinished(); +                    }                      if (isSystem()) {                          // Client transactions inside system process are recycled on the client side                          // instead of ClientLifecycleManager to avoid being cleared before this @@ -3720,12 +3727,6 @@ public final class ActivityThread extends ClientTransactionHandler          return mActivities.get(token);      } -    @Nullable -    @Override -    public Context getWindowContext(@NonNull IBinder clientToken) { -        return WindowTokenClientController.getInstance().getWindowContext(clientToken); -    } -      @VisibleForTesting(visibility = PACKAGE)      public Configuration getConfiguration() {          return mConfigurationController.getConfiguration(); @@ -6747,6 +6748,21 @@ public final class ActivityThread extends ClientTransactionHandler      void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r,              @NonNull Configuration overrideConfig, int displayId,              @NonNull ActivityWindowInfo activityWindowInfo, boolean alwaysReportChange) { +        final ClientTransactionListenerController controller = +                ClientTransactionListenerController.getInstance(); +        final Context contextToUpdate = r.activity; +        controller.onContextConfigurationPreChanged(contextToUpdate); +        try { +            handleActivityConfigurationChangedInner(r, overrideConfig, displayId, +                    activityWindowInfo, alwaysReportChange); +        } finally { +            controller.onContextConfigurationPostChanged(contextToUpdate); +        } +    } + +    private void handleActivityConfigurationChangedInner(@NonNull ActivityClientRecord r, +            @NonNull Configuration overrideConfig, int displayId, +            @NonNull ActivityWindowInfo activityWindowInfo, boolean alwaysReportChange) {          synchronized (mPendingOverrideConfigs) {              final Configuration pendingOverrideConfig = mPendingOverrideConfigs.get(r.token);              if (overrideConfig.isOtherSeqNewer(pendingOverrideConfig)) { diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java index 308178c8e57b..76d6547c2b70 100644 --- a/core/java/android/app/AutomaticZenRule.java +++ b/core/java/android/app/AutomaticZenRule.java @@ -671,7 +671,7 @@ public final class AutomaticZenRule implements Parcelable {          private String mName;          private ComponentName mOwner;          private Uri mConditionId; -        private int mInterruptionFilter; +        private int mInterruptionFilter = NotificationManager.INTERRUPTION_FILTER_PRIORITY;          private boolean mEnabled = true;          private ComponentName mConfigurationActivity = null;          private ZenPolicy mPolicy = null; diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 01153c9e7efc..f0c319673ade 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -23,7 +23,6 @@ import android.app.servertransaction.ClientTransaction;  import android.app.servertransaction.DestroyActivityItem;  import android.app.servertransaction.PendingTransactionActions;  import android.app.servertransaction.TransactionExecutor; -import android.content.Context;  import android.content.Intent;  import android.content.pm.ApplicationInfo;  import android.content.res.Configuration; @@ -32,7 +31,6 @@ import android.util.MergedConfiguration;  import android.view.SurfaceControl;  import android.window.ActivityWindowInfo;  import android.window.SplashScreenView.SplashScreenViewParcelable; -import android.window.WindowContext;  import android.window.WindowContextInfo;  import com.android.internal.annotations.VisibleForTesting; @@ -90,10 +88,6 @@ public abstract class ClientTransactionHandler {      /** Get activity instance for the token. */      public abstract Activity getActivity(IBinder token); -    /** Gets the {@link WindowContext} instance for the token. */ -    @Nullable -    public abstract Context getWindowContext(@NonNull IBinder clientToken); -      // Prepare phase related logic and handlers. Methods that inform about about pending changes or      // do other internal bookkeeping. diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java index 18dc1ce18baf..62a50dbbd6f7 100644 --- a/core/java/android/app/ConfigurationController.java +++ b/core/java/android/app/ConfigurationController.java @@ -21,6 +21,7 @@ import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;  import android.annotation.NonNull;  import android.annotation.Nullable; +import android.app.servertransaction.ClientTransactionListenerController;  import android.content.ComponentCallbacks2;  import android.content.Context;  import android.content.res.CompatibilityInfo; @@ -145,6 +146,24 @@ class ConfigurationController {       */      void handleConfigurationChanged(@Nullable Configuration config,              @Nullable CompatibilityInfo compat) { +        final ClientTransactionListenerController controller = +                ClientTransactionListenerController.getInstance(); +        final Context contextToUpdate = ActivityThread.currentApplication(); +        controller.onContextConfigurationPreChanged(contextToUpdate); +        try { +            handleConfigurationChangedInner(config, compat); +        } finally { +            controller.onContextConfigurationPostChanged(contextToUpdate); +        } +    } + +    /** +     * Update the configuration to latest. +     * @param config The new configuration. +     * @param compat The new compatibility information. +     */ +    private void handleConfigurationChangedInner(@Nullable Configuration config, +            @Nullable CompatibilityInfo compat) {          int configDiff;          boolean equivalent; diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 8f81ae2ae7d6..cf0641651d66 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -50,8 +50,8 @@ interface INotificationManager      void cancelAllNotifications(String pkg, int userId);      void clearData(String pkg, int uid, boolean fromApp); -    void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, boolean isUiContext, int displayId, @nullable ITransientNotificationCallback callback); -    void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, boolean isUiContext, int displayId); +    boolean enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, boolean isUiContext, int displayId, @nullable ITransientNotificationCallback callback); +    boolean enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, boolean isUiContext, int displayId);      void cancelToast(String pkg, IBinder token);      void finishToken(String pkg, IBinder token); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index fe261bee41d8..6ff1bfc5291c 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -23,6 +23,7 @@ import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICO  import static android.app.admin.DevicePolicyResources.UNDEFINED;  import static android.graphics.drawable.Icon.TYPE_URI;  import static android.graphics.drawable.Icon.TYPE_URI_ADAPTIVE_BITMAP; +import static android.app.Flags.cleanUpSpansAndNewLines;  import static android.app.Flags.evenlyDividedCallStyleActionLayout;  import static android.app.Flags.updateRankingTime; @@ -2582,6 +2583,7 @@ public class Notification implements Parcelable          this.when = System.currentTimeMillis();          if (updateRankingTime()) {              creationTime = when; +            extras.putBoolean(EXTRA_SHOW_WHEN, true);          } else {              this.creationTime = System.currentTimeMillis();          } @@ -2597,6 +2599,7 @@ public class Notification implements Parcelable      {          if (updateRankingTime()) {              creationTime = when; +            extras.putBoolean(EXTRA_SHOW_WHEN, true);          }          new Builder(context)                  .setWhen(when) @@ -2629,6 +2632,7 @@ public class Notification implements Parcelable          this.when = when;          if (updateRankingTime()) {              creationTime = when; +            extras.putBoolean(EXTRA_SHOW_WHEN, true);          } else {              this.creationTime = System.currentTimeMillis();          } @@ -2654,8 +2658,16 @@ public class Notification implements Parcelable          if (mAllowlistToken == null) {              mAllowlistToken = processAllowlistToken;          } -        // Propagate this token to all pending intents that are unmarshalled from the parcel. -        parcel.setClassCookie(PendingIntent.class, mAllowlistToken); +        if (Flags.secureAllowlistToken()) { +            // Propagate this token to all pending intents that are unmarshalled from the parcel, +            // or keep the one we're already propagating, if that's the case. +            if (!parcel.hasClassCookie(PendingIntent.class)) { +                parcel.setClassCookie(PendingIntent.class, mAllowlistToken); +            } +        } else { +            // Propagate this token to all pending intents that are unmarshalled from the parcel. +            parcel.setClassCookie(PendingIntent.class, mAllowlistToken); +        }          when = parcel.readLong();          creationTime = parcel.readLong(); @@ -3124,9 +3136,29 @@ public class Notification implements Parcelable                      + " instance is a custom Parcelable and not allowed in Notification");              return cs.toString();          } +        if (Flags.cleanUpSpansAndNewLines()) { +            return stripStyling(cs); +        } +          return removeTextSizeSpans(cs);      } +    private static CharSequence stripStyling(@Nullable CharSequence cs) { +        if (cs == null) { +            return cs; +        } + +        return cs.toString(); +    } + +    private static CharSequence cleanUpNewLines(@Nullable CharSequence charSequence) { +        if (charSequence == null) { +            return charSequence; +        } + +        return charSequence.toString().replaceAll("[\r\n]+", "\n"); +    } +      private static CharSequence removeTextSizeSpans(CharSequence charSequence) {          if (charSequence instanceof Spanned) {              Spanned ss = (Spanned) charSequence; @@ -3189,9 +3221,29 @@ public class Notification implements Parcelable              PendingIntent.addOnMarshaledListener(addedListener);          }          try { -            // IMPORTANT: Add marshaling code in writeToParcelImpl as we -            // want to intercept all pending events written to the parcel. -            writeToParcelImpl(parcel, flags); +            if (Flags.secureAllowlistToken()) { +                boolean mustClearCookie = false; +                if (!parcel.hasClassCookie(Notification.class)) { +                    // This is the "root" notification, and not an "inner" notification (including +                    // publicVersion or anything else that might be embedded in extras). +                    parcel.setClassCookie(Notification.class, this); +                    mustClearCookie = true; +                } +                try { +                    // IMPORTANT: Add marshaling code in writeToParcelImpl as we +                    // want to intercept all pending events written to the parcel. +                    writeToParcelImpl(parcel, flags); +                } finally { +                    if (mustClearCookie) { +                        parcel.removeClassCookie(Notification.class, this); +                    } +                } +            } else { +                // IMPORTANT: Add marshaling code in writeToParcelImpl as we +                // want to intercept all pending events written to the parcel. +                writeToParcelImpl(parcel, flags); +            } +              synchronized (this) {                  // Must be written last!                  parcel.writeArraySet(allPendingIntents); @@ -3206,7 +3258,19 @@ public class Notification implements Parcelable      private void writeToParcelImpl(Parcel parcel, int flags) {          parcel.writeInt(1); -        parcel.writeStrongBinder(mAllowlistToken); +        if (Flags.secureAllowlistToken()) { +            Notification rootNotification = (Notification) parcel.getClassCookie( +                    Notification.class); +            if (rootNotification != null && rootNotification != this) { +                // Always use the same token as the root notification +                parcel.writeStrongBinder(rootNotification.mAllowlistToken); +            } else { +                parcel.writeStrongBinder(mAllowlistToken); +            } +        } else { +            parcel.writeStrongBinder(mAllowlistToken); +        } +          parcel.writeLong(when);          parcel.writeLong(creationTime);          if (mSmallIcon == null && icon != 0) { @@ -3599,18 +3663,23 @@ public class Notification implements Parcelable       * Sets the token used for background operations for the pending intents associated with this       * notification.       * -     * This token is automatically set during deserialization for you, you usually won't need to -     * call this unless you want to change the existing token, if any. +     * Note: Should <em>only</em> be invoked by NotificationManagerService, since this is normally +     * populated by unparceling (and also used there). Any other usage is suspect.       *       * @hide       */ -    public void clearAllowlistToken() { -        mAllowlistToken = null; +    public void overrideAllowlistToken(IBinder token) { +        mAllowlistToken = token;          if (publicVersion != null) { -            publicVersion.clearAllowlistToken(); +            publicVersion.overrideAllowlistToken(token);          }      } +    /** @hide */ +    public IBinder getAllowlistToken() { +        return mAllowlistToken; +    } +      /**       * @hide       */ @@ -4316,14 +4385,16 @@ public class Notification implements Parcelable          /**           * Add a timestamp pertaining to the notification (usually the time the event occurred).           * -         * For apps targeting {@link android.os.Build.VERSION_CODES#N} and above, this time is not -         * shown anymore by default and must be opted into by using -         * {@link android.app.Notification.Builder#setShowWhen(boolean)} -         *           * @see Notification#when           */          @NonNull          public Builder setWhen(long when) { +            if (updateRankingTime()) { +                // don't show a timestamp that's decades old +                if (mN.extras.getBoolean(EXTRA_SHOW_WHEN, true) && when == 0) { +                    return this; +                } +            }              mN.when = when;              return this;          } @@ -4331,8 +4402,6 @@ public class Notification implements Parcelable          /**           * Control whether the timestamp set with {@link #setWhen(long) setWhen} is shown           * in the content view. -         * For apps targeting {@link android.os.Build.VERSION_CODES#N} and above, this defaults to -         * {@code false}. For earlier apps, the default is {@code true}.           */          @NonNull          public Builder setShowWhen(boolean show) { @@ -5505,7 +5574,8 @@ public class Notification implements Parcelable              boolean hasSecondLine = showProgress;              if (p.hasTitle()) {                  contentView.setViewVisibility(p.mTitleViewId, View.VISIBLE); -                contentView.setTextViewText(p.mTitleViewId, ensureColorSpanContrast(p.mTitle, p)); +                contentView.setTextViewText(p.mTitleViewId, +                        ensureColorSpanContrastOrStripStyling(p.mTitle, p));                  setTextViewColorPrimary(contentView, p.mTitleViewId, p);              } else if (p.mTitleViewId != R.id.title) {                  // This alternate title view ID is not cleared by resetStandardTemplate @@ -5515,7 +5585,8 @@ public class Notification implements Parcelable              if (p.mText != null && p.mText.length() != 0                      && (!showProgress || p.mAllowTextWithProgress)) {                  contentView.setViewVisibility(p.mTextViewId, View.VISIBLE); -                contentView.setTextViewText(p.mTextViewId, ensureColorSpanContrast(p.mText, p)); +                contentView.setTextViewText(p.mTextViewId, +                        ensureColorSpanContrastOrStripStyling(p.mText, p));                  setTextViewColorSecondary(contentView, p.mTextViewId, p);                  hasSecondLine = true;              } else if (p.mTextViewId != R.id.text) { @@ -5804,7 +5875,7 @@ public class Notification implements Parcelable                  headerText = mN.extras.getCharSequence(EXTRA_INFO_TEXT);              }              if (!TextUtils.isEmpty(headerText)) { -                contentView.setTextViewText(R.id.header_text, ensureColorSpanContrast( +                contentView.setTextViewText(R.id.header_text, ensureColorSpanContrastOrStripStyling(                          processLegacyText(headerText), p));                  setTextViewColorSecondary(contentView, R.id.header_text, p);                  contentView.setViewVisibility(R.id.header_text, View.VISIBLE); @@ -5826,8 +5897,9 @@ public class Notification implements Parcelable                  return false;              }              if (!TextUtils.isEmpty(p.mHeaderTextSecondary)) { -                contentView.setTextViewText(R.id.header_text_secondary, ensureColorSpanContrast( -                        processLegacyText(p.mHeaderTextSecondary), p)); +                contentView.setTextViewText(R.id.header_text_secondary, +                        ensureColorSpanContrastOrStripStyling( +                                processLegacyText(p.mHeaderTextSecondary), p));                  setTextViewColorSecondary(contentView, R.id.header_text_secondary, p);                  contentView.setViewVisibility(R.id.header_text_secondary, View.VISIBLE);                  if (hasTextToLeft) { @@ -6048,7 +6120,7 @@ public class Notification implements Parcelable                  big.setViewVisibility(R.id.notification_material_reply_text_1_container,                          View.VISIBLE);                  big.setTextViewText(R.id.notification_material_reply_text_1, -                        ensureColorSpanContrast(replyText[0].getText(), p)); +                        ensureColorSpanContrastOrStripStyling(replyText[0].getText(), p));                  setTextViewColorSecondary(big, R.id.notification_material_reply_text_1, p);                  big.setViewVisibility(R.id.notification_material_reply_progress,                          showSpinner ? View.VISIBLE : View.GONE); @@ -6060,7 +6132,7 @@ public class Notification implements Parcelable                          && p.maxRemoteInputHistory > 1) {                      big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE);                      big.setTextViewText(R.id.notification_material_reply_text_2, -                            ensureColorSpanContrast(replyText[1].getText(), p)); +                            ensureColorSpanContrastOrStripStyling(replyText[1].getText(), p));                      setTextViewColorSecondary(big, R.id.notification_material_reply_text_2, p);                      if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2].getText()) @@ -6068,7 +6140,7 @@ public class Notification implements Parcelable                          big.setViewVisibility(                                  R.id.notification_material_reply_text_3, View.VISIBLE);                          big.setTextViewText(R.id.notification_material_reply_text_3, -                                ensureColorSpanContrast(replyText[2].getText(), p)); +                                ensureColorSpanContrastOrStripStyling(replyText[2].getText(), p));                          setTextViewColorSecondary(big, R.id.notification_material_reply_text_3, p);                      }                  } @@ -6500,21 +6572,37 @@ public class Notification implements Parcelable                                      mContext, getColors(p).getBackgroundColor(), mInNightMode),                              R.dimen.notification_action_disabled_container_alpha);                  } -                if (isLegacy()) { -                    title = ContrastColorUtil.clearColorSpans(title); +                if (Flags.cleanUpSpansAndNewLines()) { +                    if (!isLegacy()) { +                        // Check for a full-length span color to use as the button fill color. +                        Integer fullLengthColor = getFullLengthSpanColor(title); +                        if (fullLengthColor != null) { +                            // Ensure the custom button fill has 1.3:1 contrast w/ notification bg. +                            int notifBackgroundColor = getColors(p).getBackgroundColor(); +                            buttonFillColor = ensureButtonFillContrast( +                                    fullLengthColor, notifBackgroundColor); +                        } +                    }                  } else { -                    // Check for a full-length span color to use as the button fill color. -                    Integer fullLengthColor = getFullLengthSpanColor(title); -                    if (fullLengthColor != null) { -                        // Ensure the custom button fill has 1.3:1 contrast w/ notification bg. -                        int notifBackgroundColor = getColors(p).getBackgroundColor(); -                        buttonFillColor = ensureButtonFillContrast( -                                fullLengthColor, notifBackgroundColor); +                    if (isLegacy()) { +                        title = ContrastColorUtil.clearColorSpans(title); +                    } else { +                        // Check for a full-length span color to use as the button fill color. +                        Integer fullLengthColor = getFullLengthSpanColor(title); +                        if (fullLengthColor != null) { +                            // Ensure the custom button fill has 1.3:1 contrast w/ notification bg. +                            int notifBackgroundColor = getColors(p).getBackgroundColor(); +                            buttonFillColor = ensureButtonFillContrast( +                                    fullLengthColor, notifBackgroundColor); +                        } +                        // Remove full-length color spans +                        // and ensure text contrast with the button fill. +                        title = ContrastColorUtil.ensureColorSpanContrast(title, buttonFillColor);                      } -                    // Remove full-length color spans and ensure text contrast with the button fill. -                    title = ContrastColorUtil.ensureColorSpanContrast(title, buttonFillColor);                  } -                final CharSequence label = ensureColorSpanContrast(title, p); + + +                final CharSequence label = ensureColorSpanContrastOrStripStyling(title, p);                  if (p.mCallStyleActions && evenlyDividedCallStyleActionLayout()) {                      if (CallStyle.DEBUG_NEW_ACTION_LAYOUT) {                          Log.d(TAG, "new action layout enabled, gluing instead of setting text"); @@ -6554,7 +6642,7 @@ public class Notification implements Parcelable                      button.setIntDimen(R.id.action0, "setMinimumWidth", minWidthDimen);                  }              } else { -                button.setTextViewText(R.id.action0, ensureColorSpanContrast( +                button.setTextViewText(R.id.action0, ensureColorSpanContrastOrStripStyling(                          action.title, p));                  button.setTextColor(R.id.action0, getStandardActionColor(p));              } @@ -6629,6 +6717,26 @@ public class Notification implements Parcelable          }          /** +         * @hide +         */ +        public CharSequence ensureColorSpanContrastOrStripStyling(CharSequence cs, +                StandardTemplateParams p) { +            return ensureColorSpanContrastOrStripStyling(cs, getBackgroundColor(p)); +        } + +        /** +         * @hide +         */ +        public CharSequence ensureColorSpanContrastOrStripStyling(CharSequence cs, +                int buttonFillColor) { +            if (Flags.cleanUpSpansAndNewLines()) { +                return stripStyling(cs); +            } + +            return ContrastColorUtil.ensureColorSpanContrast(cs, buttonFillColor); +        } + +        /**           * Ensures contrast on color spans against a background color.           * Note that any full-length color spans will be removed instead of being contrasted.           * @@ -7853,8 +7961,9 @@ public class Notification implements Parcelable              RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource(),                      p, null /* result */);              if (mSummaryTextSet) { -                contentView.setTextViewText(R.id.text, mBuilder.ensureColorSpanContrast( -                        mBuilder.processLegacyText(mSummaryText), p)); +                contentView.setTextViewText(R.id.text, +                        mBuilder.ensureColorSpanContrastOrStripStyling( +                                mBuilder.processLegacyText(mSummaryText), p));                  mBuilder.setTextViewColorSecondary(contentView, R.id.text, p);                  contentView.setViewVisibility(R.id.text, View.VISIBLE);              } @@ -8017,6 +8126,9 @@ public class Notification implements Parcelable           */          public BigTextStyle bigText(CharSequence cs) {              mBigText = safeCharSequence(cs); +            if (Flags.cleanUpSpansAndNewLines()) { +                mBigText = cleanUpNewLines(mBigText); +            }              return this;          } @@ -8517,7 +8629,7 @@ public class Notification implements Parcelable              for (int i = 0; i < N; i++) {                  final Message m = messages.get(i);                  if (ensureContrast) { -                    m.ensureColorContrast(backgroundColor); +                    m.ensureColorContrastOrStripStyling(backgroundColor);                  }                  bundles[i] = m.toBundle();              } @@ -8543,7 +8655,9 @@ public class Notification implements Parcelable              } else {                  title = sender;              } - +            if (Flags.cleanUpSpansAndNewLines()) { +                title = stripStyling(title); +            }              if (title != null) {                  extras.putCharSequence(EXTRA_TITLE, title);              } @@ -8995,6 +9109,17 @@ public class Notification implements Parcelable              }              /** +             * Strip styling or updates TextAppearance spans in message text. +             * @hide +             */ +            public void ensureColorContrastOrStripStyling(int backgroundColor) { +                if (Flags.cleanUpSpansAndNewLines()) { +                    mText = stripStyling(mText); +                } else { +                    ensureColorContrast(backgroundColor); +                } +            } +            /**               * Updates TextAppearance spans in the message text so it has sufficient contrast               * against its background.               * @hide @@ -9324,7 +9449,8 @@ public class Notification implements Parcelable                  if (!TextUtils.isEmpty(str)) {                      contentView.setViewVisibility(rowIds[i], View.VISIBLE);                      contentView.setTextViewText(rowIds[i], -                            mBuilder.ensureColorSpanContrast(mBuilder.processLegacyText(str), p)); +                            mBuilder.ensureColorSpanContrastOrStripStyling( +                                    mBuilder.processLegacyText(str), p));                      mBuilder.setTextViewColorSecondary(contentView, rowIds[i], p);                      contentView.setViewPadding(rowIds[i], 0, topPadding, 0, 0);                      if (first) { diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 02d694436bfe..257aff04a09f 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -1603,8 +1603,18 @@ public class WallpaperManager {              @SetWallpaperFlags int which, boolean originalBitmap) {          checkExactlyOneWallpaperFlagSet(which);          try { -            return sGlobals.mService.getBitmapCrops(displaySizes, which, originalBitmap, -                    mContext.getUserId()); +            List<Rect> result = sGlobals.mService.getBitmapCrops( +                    displaySizes, which, originalBitmap, mContext.getUserId()); +            if (result != null) return result; +            // mService.getBitmapCrops returns null if the requested wallpaper is an ImageWallpaper, +            // but there are no crop hints and the bitmap size is unknown to the service (this +            // mostly happens for the default wallpaper). In that case, fetch the bitmap dimensions +            // and use the other getBitmapCrops API with no cropHints to figure out the crops. +            Rect bitmapDimensions = peekBitmapDimensions(which, true); +            if (bitmapDimensions == null) return List.of(); +            Point bitmapSize = new Point(bitmapDimensions.width(), bitmapDimensions.height()); +            return getBitmapCrops(bitmapSize, displaySizes, null); +          } catch (RemoteException e) {              throw e.rethrowFromSystemServer();          } diff --git a/core/java/android/app/admin/AccountTypePolicyKey.java b/core/java/android/app/admin/AccountTypePolicyKey.java index 51f313755e59..02e492bb06aa 100644 --- a/core/java/android/app/admin/AccountTypePolicyKey.java +++ b/core/java/android/app/admin/AccountTypePolicyKey.java @@ -54,7 +54,7 @@ public final class AccountTypePolicyKey extends PolicyKey {      @TestApi      public AccountTypePolicyKey(@NonNull String key, @NonNull String accountType) {          super(key); -        if (Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              PolicySizeVerifier.enforceMaxStringLength(accountType, "accountType");          }          mAccountType = Objects.requireNonNull((accountType)); diff --git a/core/java/android/app/admin/BundlePolicyValue.java b/core/java/android/app/admin/BundlePolicyValue.java index cb5e9861141d..c993671f4fc1 100644 --- a/core/java/android/app/admin/BundlePolicyValue.java +++ b/core/java/android/app/admin/BundlePolicyValue.java @@ -31,7 +31,7 @@ public final class BundlePolicyValue extends PolicyValue<Bundle> {      public BundlePolicyValue(Bundle value) {          super(value); -        if (Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              PolicySizeVerifier.enforceMaxBundleFieldsLength(value);          }      } diff --git a/core/java/android/app/admin/ComponentNamePolicyValue.java b/core/java/android/app/admin/ComponentNamePolicyValue.java index a957dbf132bb..a7a2f7d27e0d 100644 --- a/core/java/android/app/admin/ComponentNamePolicyValue.java +++ b/core/java/android/app/admin/ComponentNamePolicyValue.java @@ -31,7 +31,7 @@ public final class ComponentNamePolicyValue extends PolicyValue<ComponentName> {      public ComponentNamePolicyValue(@NonNull ComponentName value) {          super(value); -        if (Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              PolicySizeVerifier.enforceMaxComponentNameLength(value);          }      } diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index f21e11ab35cc..c7b0be7553c2 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -244,6 +244,10 @@ public class DeviceAdminReceiver extends BroadcastReceiver {       * {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}. You will generally handle       * this in {@link DeviceAdminReceiver#onProfileProvisioningComplete}.       * +     * <p>The intent for this action may include the following extras: +     * <ul> +     *     <li>{@link DevicePolicyManager#EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE} +     *       * @see DevicePolicyManager#ACTION_PROVISIONING_SUCCESSFUL       */      @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @@ -801,6 +805,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver {       * {@link DevicePolicyManager#ACTION_PROVISIONING_SUCCESSFUL} will also be sent to the same       * application.       * +     * <p>The {@code Intent} may include any of the extras specified for +     * {@link #ACTION_PROFILE_PROVISIONING_COMPLETE}. +     *       * @param context The running context as per {@link #onReceive}.       * @param intent The received intent as per {@link #onReceive}.       */ diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index ea6f45e8e201..9058713ecfa1 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -54,6 +54,7 @@ import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;  import static android.Manifest.permission.SET_TIME;  import static android.Manifest.permission.SET_TIME_ZONE;  import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED; +import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_INTERNAL_BUG_FIX_ENABLED;  import static android.app.admin.flags.Flags.FLAG_DEVICE_THEFT_API_ENABLED;  import static android.app.admin.flags.Flags.FLAG_ESIM_MANAGEMENT_ENABLED;  import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED; @@ -191,32 +192,134 @@ import java.util.concurrent.ExecutionException;  import java.util.concurrent.Executor;  import java.util.function.Consumer; -// TODO(b/172376923) - add CarDevicePolicyManager examples below (or remove reference to it).  /** - * Public interface for managing policies enforced on a device. Most clients of this class must be - * registered with the system as a <a href="{@docRoot}guide/topics/admin/device-admin.html">device - * administrator</a>. Additionally, a device administrator may be registered as either a profile or - * device owner. A given method is accessible to all device administrators unless the documentation - * for that method specifies that it is restricted to either device or profile owners. Any - * application calling an api may only pass as an argument a device administrator component it - * owns. Otherwise, a {@link SecurityException} will be thrown. + * Manages device policy and restrictions applied to the user of the device or + * apps running on the device.   * - * <p><b>Note: </b>on - * {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}, some methods can - * throw an {@link UnsafeStateException} exception (for example, if the vehicle is moving), so - * callers running on automotive builds should always check for that exception, otherwise they - * might crash. + * <p>This class contains three types of methods: + * <ol><li>Those aimed at <a href="#managingapps">managing apps</a> + * <li>Those aimed at the <a href="#roleholder">Device Policy Management Role Holder</a> + * <li>Those aimed at <a href="#querying">apps which wish to respect device policy</a> + * </ol>   * - * <div class="special reference"> - * <h3>Developer Guides</h3> - * <p> - * For more information about managing policies for device administration, read the <a href= - * "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a> developer - * guide. </div> + * <p>The intended caller for each API is indicated in its Javadoc. + * + * <p id="managingapps"><b>Managing Apps</b> + * <p>Apps can be made capable of setting device policy ("Managing Apps") either by + * being set as a <a href="#deviceadmin">Device Administrator</a>, being set as a + * <a href="#devicepolicycontroller">Device Policy Controller</a>, or by holding the + * appropriate <a href="#permissions">Permissions</a>. + * + * <p id="deviceadmin">A <b>Device Administrator</b> is an app which is able to enforce device + * policies that it has declared in its device admin XML file. An app can prompt the user to give it + * device administator privileges using the {@link #ACTION_ADD_DEVICE_ADMIN} action. + * + * <p>For more information about Device Administration, read the + * <a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a> + * developer guide. + * + * <p id="devicepolicycontroller">Through <a href="#managed_provisioning">Managed Provisioning</a>, + * Device Administrator apps can also be recognised as <b> + Device Policy Controllers</b>. Device Policy Controllers can be one of + * two types: + * <ul> + * <li>A <i id="deviceowner">Device Owner</i>, which only ever exists on the + * {@link UserManager#isSystemUser System User} or {@link UserManager#isMainUser Main User}, is + * the most powerful type of Device Policy Controller and can affect policy across the device. + * <li>A <i id="profileowner">Profile Owner<i>, which can exist on any user, can + * affect policy on the user it is on, and when it is running on + * {@link UserManager#isProfile a profile} has + * <a href="#profile-on-parent">limited</a> ability to affect policy on its + * {@link UserManager#getProfileParent parent}. + * </ul> + * + * <p>Additional capabilities can be provided to Device Policy Controllers in + * the following circumstances: + * <ul> + * <li>A Profile Owner on an <a href="#organization-owned">organization owned</a> device has access + * to additional abilities, both <a href="#profile-on-parent-organization-owned">affecting policy on the profile's</a> + * {@link UserManager#getProfileParent parent} and also the profile itself. + * <li>A Profile Owner running on the {@link UserManager#isSystemUser System User} has access to + * additional capabilities which affect the {@link UserManager#isSystemUser System User} and + * also the whole device. + * <li>A Profile Owner running on an <a href="#affiliated">affiliated</a> user has + * capabilities similar to that of a <a href="#deviceowner">Device Owner</a> + * </ul> + * + * <p>For more information, see <a href="{@docRoot}work/dpc/build-dpc">Building a Device Policy + * Controller</a>. + * + * <p><a href="#permissions">Permissions</a> are generally only given to apps + * fulfilling particular key roles on the device (such as managing {@link DeviceLockManager +device locks}). + * + * <p id="roleholder"><b>Device Policy Management Role Holder</b> + * <p>One app on the device fulfills the {@link RoleManager#ROLE_DEVICE_POLICY_MANAGEMENT Device +Policy Management Role} and is trusted with managing the overall state of + * Device Policy. This has access to much more powerful methods than + * <a href="#managingapps">managing apps</a>. + * + * <p id="querying"><b>Querying Device Policy</b> + * <p>In most cases, regular apps do not need to concern themselves with device + * policy, and restrictions will be enforced automatically. There are some cases + * where an app may wish to query device policy to provide a better user + * experience. Only a small number of policies allow apps to query them directly. + * These APIs will typically have no special required permissions. + * + * <p id="managedprovisioning"><b>Managed Provisioning</b> + * <p>Managed Provisioning is the process of recognising an app as a + * <a href="#deviceowner">Device Owner</a> or <a href="#profileowner">Profile Owner</a>. It + * involves presenting education and consent screens to the user to ensure they + * are aware of the capabilities this grants the <a href="#devicepolicycontroller">Device Policy + * Controller</a> + * + * <p>For more information on provisioning, see <a href="{@docRoot}work/dpc/build-dpc">Building a + * Device Policy Controller</a>. + * + * <p id="managed_profile">A <b>Managed Profile</b> enables data separation. For example to use + * a device both for personal and corporate usage. The managed profile and its + * {@link UserManager#getProfileParent parent} share a launcher. + * + * <p id="affiliated"><b>Affiliation</b> + * <p>Using the {@link #setAffiliationIds} method, a + * <a href="#deviceowner">Device Owner</a> can set a list of affiliation ids for the + * {@link UserManager#isSystemUser System User}. Any <a href="#profileowner">Profile Owner</a> on + * the same device can also call {@link #setAffiliationIds} to set affiliation ids + * for the {@link UserManager user} it is on. When there is the same ID + * present in both lists, the user is said to be "affiliated" and we can refer to + * the <a href="#profileowner">Profile Owner</a> as a "profile owner on an affiliated + * user" or an "affiliated profile owner". + * + * Becoming affiliated grants the <a href="#profileowner">Profile Owner</a> capabilities similar to + * that of the <a href="#deviceowner">Device Owner</a>. It also allows use of the + * {@link #bindDeviceAdminServiceAsUser} APIs for direct communication between the + * <a href="#deviceowner">Device Owner</a> and + * affiliated <a href="#profileowner">Profile Owners</a>. + * + * <p id="organization-owned"><b>Organization Owned</b></p> + * An organization owned device is one which is not owned by the person making use of the device and + * is instead owned by an organization such as their employer or education provider. These devices + * are recognised as being organization owned either by the presence of a + * <a href="#deviceowner">device owner</a> or of a + * {@link #isOrganizationOwnedDeviceWithManagedProfile profile which has a profile owner is marked + * as organization owned}. + * + * <p id="profile-on-parent-organization-owned">Profile owners running on an + * <a href="organization-owned">organization owned</a> device can exercise additional capabilities + * using the {@link #getParentProfileInstance(ComponentName)} API which apply to the parent user. + * Each API will indicate if it is usable in this way. + * + * <p id="automotive"><b>Android Automotive</b> + * <p>On {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE + * "Android Automotive builds"}, some methods can throw + * {@link UnsafeStateException "an exception"} if an action is unsafe (for example, if the vehicle + * is moving). Callers running on + * {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE + * "Android Automotive builds"} should always check for this exception.   */ +  @SystemService(Context.DEVICE_POLICY_SERVICE)  @RequiresFeature(PackageManager.FEATURE_DEVICE_ADMIN) -@SuppressLint("UseIcu")  public class DevicePolicyManager {      /** @hide */ @@ -256,7 +359,7 @@ public class DevicePolicyManager {       * Fetch the current value of mService.  This is used in the binder cache lambda       * expressions.       */ -    private final IDevicePolicyManager getService() { +    private IDevicePolicyManager getService() {          return mService;      } @@ -264,7 +367,7 @@ public class DevicePolicyManager {       * Fetch the current value of mParentInstance.  This is used in the binder cache       * lambda expressions.       */ -    private final boolean isParentInstance() { +    private boolean isParentInstance() {          return mParentInstance;      } @@ -272,7 +375,7 @@ public class DevicePolicyManager {       * Fetch the current value of mContext.  This is used in the binder cache lambda       * expressions.       */ -    private final Context getContext() { +    private Context getContext() {          return mContext;      } @@ -283,39 +386,80 @@ public class DevicePolicyManager {      }      /** -     * Activity action: Starts the provisioning flow which sets up a managed profile. -     * -     * <p>A managed profile allows data separation for example for the usage of a -     * device as a personal and corporate device. The user which provisioning is started from and -     * the managed profile share a launcher. -     * -     * <p>This intent will typically be sent by a mobile device management application (MDM). -     * Provisioning adds a managed profile and sets the MDM as the profile owner who has full -     * control over the profile. +     * Activity action: Starts the provisioning flow which sets up a +     * <a href="#managed-profile">managed profile</a>.       *       * <p>It is possible to check if provisioning is allowed or not by querying the method       * {@link #isProvisioningAllowed(String)}.       * -     * <p>In version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this intent must contain the -     * extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}. -     * As of {@link android.os.Build.VERSION_CODES#M}, it should contain the extra -     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} instead, although specifying only -     * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is still supported. -     * -     * <p>The intent may also contain the following extras: -     * <ul> -     * <li>{@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}, optional </li> -     * <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional, supported from -     * {@link android.os.Build.VERSION_CODES#N}</li> -     * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li> -     * <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li> -     * <li>{@link #EXTRA_PROVISIONING_SKIP_USER_CONSENT}, optional</li> -     * <li>{@link #EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION}, optional</li> -     * <li>{@link #EXTRA_PROVISIONING_DISCLAIMERS}, optional</li> -     * </ul> -     * -     * <p>When managed provisioning has completed, broadcasts are sent to the application specified -     * in the provisioning intent. The +     * <p>The intent may contain the following extras: +     * +     * <table> +     *  <thead> +     *      <tr> +     *          <th>Extra</th> +     *          <th></th> +     *          <th>Supported Versions</th> +     *      </tr> +     *  </thead> +     *  <tbody> +     *      <tr> +     *          <td>{@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}</td> +     *          <td colspan="2"></td> +     *      </tr> +     *      <tr> +     *          <td>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}</td> +     *          <td></td> +     *          <td>{@link android.os.Build.VERSION_CODES#N}+</td> +     *      </tr> +     *      <tr> +     *          <td>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}</td> +     *          <td colspan="2"></td> +     *      </tr> +     *      <tr> +     *          <td>{@link #EXTRA_PROVISIONING_LOGO_URI}</td> +     *          <td colspan="2"></td> +     *      </tr> +     *      <tr> +     *          <td>{@link #EXTRA_PROVISIONING_SKIP_USER_CONSENT}</td> +     *          <td colspan="2"><b>Can only be used by an existing device owner trying to create a +     *          managed profile</b></td> +     *      </tr> +     *      <tr> +     *          <td>{@link #EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION}</td> +     *          <td colspan="2"></td> +     *      </tr> +     *      <tr> +     *          <td>{@link #EXTRA_PROVISIONING_DISCLAIMERS}</td> +     *          <td colspan="2"></td> +     *      </tr> +     *      <tr> +     *          <td>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}</td> +     *          <td> +     *              <b>Required if {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} is not +     *              specified. Must match the package name of the calling application.</b> +     *          </td> +     *          <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}+</td> +     *      </tr> +     *      <tr> +     *          <td>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}</td> +     *          <td> +     *              <b>Required if {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} is not +     *              specified. Package name must match the package name of the calling +     *              application.</b> +     *          </td> +     *          <td>{@link android.os.Build.VERSION_CODES#M}+</td> +     *      </tr> +     *      <tr> +     *          <td>{@link #EXTRA_PROVISIONING_ALLOW_OFFLINE}</td> +     *          <td colspan="2">On {@link android.os.Build.VERSION_CODES#TIRAMISU}+, when set to +     *          true this will <b>force</b> offline provisioning instead of allowing it</td> +     *      </tr> +     *  </tbody> +     * </table> +     * +     * <p>When <a href="#managedprovisioning">managed provisioning</a> has completed, broadcasts +     * are sent to the application specified in the provisioning intent. The       * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} broadcast is sent in the       * managed profile and the {@link #ACTION_MANAGED_PROFILE_PROVISIONED} broadcast is sent in       * the primary profile. @@ -324,25 +468,25 @@ public class DevicePolicyManager {       * completed, along with the above broadcast, activity intent       * {@link #ACTION_PROVISIONING_SUCCESSFUL} will also be sent to the profile owner.       * -     * <p>If provisioning fails, the managedProfile is removed so the device returns to its +     * <p>If provisioning fails, the managed profile is removed so the device returns to its       * previous state.       *       * <p>If launched with {@link android.app.Activity#startActivityForResult(Intent, int)} a -     * result code of {@link android.app.Activity#RESULT_OK} implies that the synchronous part of +     * result code of {@link android.app.Activity#RESULT_OK} indicates that the synchronous part of       * the provisioning flow was successful, although this doesn't guarantee the full flow will -     * succeed. Conversely a result code of {@link android.app.Activity#RESULT_CANCELED} implies -     * that the user backed-out of provisioning, or some precondition for provisioning wasn't met. +     * succeed. Conversely a result code of {@link android.app.Activity#RESULT_CANCELED} indicates +     * that the user backed-out of provisioning or some precondition for provisioning wasn't met.       * -     * <p>If a device policy management role holder (DPMRH) updater is present on the device, an -     * internet connection attempt must be made prior to launching this intent. If internet -     * connection could not be established, provisioning will fail unless {@link +     * <p>If a <a href="#roleholder">device policy management role holder</a> updater is present on +     * the device, an internet connection attempt must be made prior to launching this intent. If +     * an internet connection can not be established, provisioning will fail unless {@link       * #EXTRA_PROVISIONING_ALLOW_OFFLINE} is explicitly set to {@code true}, in which case -     * provisioning will continue without using the DPMRH. If an internet connection has been -     * established, the DPMRH updater will be launched, which will update the DPMRH if it's not -     * present on the device, or if it's present and not valid. -     * -     * <p>If a DPMRH is present on the device and valid, the provisioning flow will be deferred to -     * it. +     * provisioning will continue without using the +     * <a href="#roleholder">device policy management role holder</a>. If an internet connection +     * has been established, the <a href="#roleholder">device policy management role holder</a> +     * updater will be launched, which may update the +     * <a href="#roleholder">device policy management role holder</a> before continuing +     * provisioning.       */      @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)      public static final String ACTION_PROVISION_MANAGED_PROFILE @@ -821,31 +965,25 @@ public class DevicePolicyManager {              "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";      /** -     * A boolean extra indicating whether offline provisioning is allowed. -     * -     * <p>For the online provisioning flow, there will be an attempt to download and install -     * the latest version of the device policy management role holder. The platform will then -     * delegate provisioning to the device policy management role holder via role holder-specific -     * provisioning actions. -     * -     * <p>For the offline provisioning flow, the provisioning flow will always be handled by -     * the platform. +     * A boolean extra indicating whether offline provisioning should be used.       * -     * <p>If this extra is set to {@code false}, the provisioning flow will enforce that an -     * internet connection is established, which will start the online provisioning flow. If an -     * internet connection cannot be established, provisioning will fail. -     * -     * <p>If this extra is set to {@code true}, the provisioning flow will still try to connect to -     * the internet, but if it fails it will start the offline provisioning flow. +     * <p>The default value is {@code false}.       * -     * <p>For T if this extra is set to {@code true}, the provisioning flow will be forced through -     * the platform and there will be no attempt to download and install the device policy -     * management role holder. +     * <p>Usually during the <a href="#managedprovisioning">provisioning flow</a>, there will be +     * an attempt to download and install the latest version of the <a href="#roleholder">device +     * policy management role holder</a>. The platform will then +     * delegate provisioning to the <a href="#roleholder">device +     *      * policy management role holder</a>.       * -     * <p>The default value is {@code false}. +     * <p>When this extra is set to {@code true}, the +     * <a href="#managedprovisioning">provisioning flow</a> will always be handled by the platform +     * and the <a href="#roleholder">device policy management role holder</a>'s part skipped.       * -     * <p>This extra is respected when provided via the provisioning intent actions such as {@link -     * #ACTION_PROVISION_MANAGED_PROFILE}. +     * <p>On Android versions prior to {@link Build.VERSION_CODES#TIRAMISU}, when this extra is +     * {@code false}, the <a href="#managedprovisioning">provisioning flow</a> will enforce that an +     * internet connection is established, or otherwise fail. When this extra is {@code true}, a +     * connection will still be attempted but when it cannot be established provisioning will +     * continue offline.       */      public static final String EXTRA_PROVISIONING_ALLOW_OFFLINE =              "android.app.extra.PROVISIONING_ALLOW_OFFLINE"; @@ -1056,64 +1194,40 @@ public class DevicePolicyManager {      public static final long DEFAULT_STRONG_AUTH_TIMEOUT_MS = 72 * 60 * 60 * 1000; // 72h      /** -     * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that -     * allows a mobile device management application or NFC programmer application which starts -     * managed provisioning to pass data to the management application instance after provisioning. +     * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that is +     * passed directly to the <a href="#devicepolicycontroller">Device Policy Controller</a> +     * after <a href="#managed-provisioning">provisioning</a>. +     *       * <p> -     * If used with {@link #ACTION_PROVISION_MANAGED_PROFILE} it can be used by the application that -     * sends the intent to pass data to itself on the newly created profile. -     * If used with {@link #ACTION_PROVISION_MANAGED_DEVICE} it allows passing data to the same -     * instance of the app on the primary user.       * Starting from {@link android.os.Build.VERSION_CODES#M}, if used with       * {@link #MIME_TYPE_PROVISIONING_NFC} as part of NFC managed device provisioning, the NFC       * message should contain a stringified {@link java.util.Properties} instance, whose string       * properties will be converted into a {@link android.os.PersistableBundle} and passed to the       * management application after provisioning. -     * -     * <p>Admin apps will receive this extra in their {@link #ACTION_GET_PROVISIONING_MODE} and -     * {@link #ACTION_ADMIN_POLICY_COMPLIANCE} intent handlers. Additionally, {@link -     * #ACTION_GET_PROVISIONING_MODE} may also return this extra which will then be sent over to -     * {@link #ACTION_ADMIN_POLICY_COMPLIANCE}, alongside the original values that were passed to -     * {@link #ACTION_GET_PROVISIONING_MODE}. -     * -     * <p> -     * In both cases the application receives the data in -     * {@link DeviceAdminReceiver#onProfileProvisioningComplete} via an intent with the action -     * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}. The bundle is not changed -     * during the managed provisioning.       */      public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE =              "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";      /** -     * A String extra holding the package name of the mobile device management application that -     * will be set as the profile owner or device owner. -     * -     * <p>If an application starts provisioning directly via an intent with action -     * {@link #ACTION_PROVISION_MANAGED_PROFILE} this package has to match the package name of the -     * application that started provisioning. The package will be set as profile owner in that case. -     * -     * <p>This package is set as device owner when device owner provisioning is started by an NFC -     * message containing an NFC record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}. +     * A String extra holding the package name of the application that +     * will be set as <a href="#devicepolicycontroller">Device Policy Controller</a>.       * -     * <p> When this extra is set, the application must have exactly one device admin receiver. -     * This receiver will be set as the profile or device owner and active admin. +     * <p>When this extra is set, the application must have exactly one +     * {@link DeviceAdminReceiver device admin receiver}. This receiver will be set as the +     * <a href="#devicepolicycontroller">Device Policy Controller</a>.       * -     * @see DeviceAdminReceiver -     * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still -     * supported, but only if there is only one device admin receiver in the package that requires -     * the permission {@link android.Manifest.permission#BIND_DEVICE_ADMIN}. +     * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}.       */      @Deprecated      public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME          = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";      /** -     * A ComponentName extra indicating the device admin receiver of the mobile device management -     * application that will be set as the profile owner or device owner and active admin. +     * A ComponentName extra indicating the {@link DeviceAdminReceiver device admin receiver} of +     * the application that will be set as the <a href="#devicepolicycontroller"> +     *     Device Policy Controller</a>.       *       * <p>If an application starts provisioning directly via an intent with action -     * {@link #ACTION_PROVISION_MANAGED_PROFILE} or       * {@link #ACTION_PROVISION_MANAGED_DEVICE} the package name of this       * component has to match the package name of the application that started provisioning.       * @@ -1122,35 +1236,28 @@ public class DevicePolicyManager {       * message containing an NFC record with MIME type       * {@link #MIME_TYPE_PROVISIONING_NFC}. For the NFC record, the component name must be       * flattened to a string, via {@link ComponentName#flattenToShortString()}. -     * -     * @see DeviceAdminReceiver       */      public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME          = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";      /**       * An {@link android.accounts.Account} extra holding the account to migrate during managed -     * profile provisioning. If the account supplied is present in the primary user, it will be -     * copied, along with its credentials to the managed profile and removed from the primary user. +     * profile provisioning.       * -     * Use with {@link #ACTION_PROVISION_MANAGED_PROFILE}, with managed account provisioning, or -     * return as an extra to the intent result from the {@link #ACTION_GET_PROVISIONING_MODE} -     * activity. +     * <p>If the account supplied is present in the user, it will be copied, along with its +     * credentials to the managed profile and removed from the user.       */ -      public static final String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE          = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";      /** -     * Boolean extra to indicate that the migrated account should be kept. This is used in -     * conjunction with {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}. If it's set to {@code true}, -     * the account will not be removed from the primary user after it is migrated to the newly -     * created user or profile. +     * Boolean extra to indicate that the +     * {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE migrated account} should be kept.       * -     * <p> Defaults to {@code false} +     * <p>If it's set to {@code true}, the account will not be removed from the user after it is +     * migrated to the newly created user or profile.       * -     * <p> Use with {@link #ACTION_PROVISION_MANAGED_PROFILE} or set as an extra to the -     * intent result of the {@link #ACTION_GET_PROVISIONING_MODE} activity. +     * <p>Defaults to {@code false}       *       * @see #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE       */ @@ -1589,17 +1696,14 @@ public class DevicePolicyManager {              "android.app.action.PROVISIONING_SUCCESSFUL";      /** -     * A boolean extra indicating whether device encryption can be skipped as part of device owner -     * or managed profile provisioning. +     * A boolean extra indicating whether device encryption can be skipped as part of +     * <a href="#managed-provisioning>provisioning</a>.       *       * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} or an intent with action       * {@link #ACTION_PROVISION_MANAGED_DEVICE} that starts device owner provisioning.       *       * <p>From {@link android.os.Build.VERSION_CODES#N} onwards, this is also supported for an       * intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE}. -     * -     * <p>This extra can also be returned by the admin app when performing the admin-integrated -     * provisioning flow as a result of the {@link #ACTION_GET_PROVISIONING_MODE} activity.       */      public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION =               "android.app.extra.PROVISIONING_SKIP_ENCRYPTION"; @@ -1607,23 +1711,22 @@ public class DevicePolicyManager {      /**       * A {@link Uri} extra pointing to a logo image. This image will be shown during the       * provisioning. If this extra is not passed, a default image will be shown. -     * <h5>The following URI schemes are accepted:</h5> +     * +     * <p><b>The following URI schemes are accepted:</b>       * <ul>       * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>       * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})</li>       * </ul>       * -     * <p> It is the responsibility of the caller to provide an image with a reasonable +     * <p>It is the responsibility of the caller to provide an image with a reasonable       * pixel density for the device.       * -     * <p> If a content: URI is passed, the intent should have the flag +     * <p>If a content: URI is passed, the intent should also have the flag       * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} and the uri should be added to the -     * {@link android.content.ClipData} of the intent too. +     * {@link android.content.ClipData} of the intent.       * -     * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE} or -     * {@link #ACTION_PROVISION_MANAGED_DEVICE} -     * -     * @deprecated Logo customization is no longer supported in the provisioning flow. +     * @deprecated Logo customization is no longer supported in the +     *             <a href="#managedprovisioning">provisioning flow</a>.       */      @Deprecated      public static final String EXTRA_PROVISIONING_LOGO_URI = @@ -1631,7 +1734,8 @@ public class DevicePolicyManager {      /**       * A {@link Bundle}[] extra consisting of list of disclaimer headers and disclaimer contents. -     * Each {@link Bundle} must have both {@link #EXTRA_PROVISIONING_DISCLAIMER_HEADER} +     * +     * <p>Each {@link Bundle} must have both {@link #EXTRA_PROVISIONING_DISCLAIMER_HEADER}       * as disclaimer header, and {@link #EXTRA_PROVISIONING_DISCLAIMER_CONTENT} as disclaimer       * content.       * @@ -1652,20 +1756,21 @@ public class DevicePolicyManager {      /**       * A String extra of localized disclaimer header.       * -     * <p> The extra is typically the company name of mobile device management application (MDM) +     * <p>The extra is typically the company name of mobile device management application (MDM)       * or the organization name.       * -     * <p> Use in Bundle {@link #EXTRA_PROVISIONING_DISCLAIMERS} -     * -     * <p> System app, i.e. application with {@link ApplicationInfo#FLAG_SYSTEM}, can also insert a -     * disclaimer by declaring an application-level meta-data in {@code AndroidManifest.xml}. -     * Must use it with {@link #EXTRA_PROVISIONING_DISCLAIMER_CONTENT}. Here is the example: +     * <p>{@link ApplicationInfo#FLAG_SYSTEM System apps} can also insert a disclaimer by declaring +     * an application-level meta-data in {@code AndroidManifest.xml}.       * +     * <p>For example:       * <pre>       *  <meta-data       *      android:name="android.app.extra.PROVISIONING_DISCLAIMER_HEADER"       *      android:resource="@string/disclaimer_header"       * /></pre> +     * +     * <p>This must be accompanied with another extra using the key +     * {@link #EXTRA_PROVISIONING_DISCLAIMER_CONTENT}.       */      public static final String EXTRA_PROVISIONING_DISCLAIMER_HEADER =              "android.app.extra.PROVISIONING_DISCLAIMER_HEADER"; @@ -1679,35 +1784,35 @@ public class DevicePolicyManager {       * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})</li>       * </ul>       * -     * <p> Styled text is supported in the disclaimer content. The content is parsed by -     * {@link android.text.Html#fromHtml(String)} and displayed in a -     * {@link android.widget.TextView}. +     * <p>Styled text is supported. This is parsed by {@link android.text.Html#fromHtml(String)} +     * and displayed in a {@link android.widget.TextView}.       * -     * <p> If a <code>content:</code> URI is passed, URI is passed, the intent should have the flag -     * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} and the uri should be added to the -     * {@link android.content.ClipData} of the intent too. +     * <p>If a <code>content:</code> URI is passed, the intent should also have the +     * flag {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} and the uri should be added to the +     * {@link android.content.ClipData} of the intent.       * -     * <p> Use in Bundle {@link #EXTRA_PROVISIONING_DISCLAIMERS} -     * -     * <p> System app, i.e. application with {@link ApplicationInfo#FLAG_SYSTEM}, can also insert a +     * <p>{@link ApplicationInfo#FLAG_SYSTEM System apps} can also insert a       * disclaimer by declaring an application-level meta-data in {@code AndroidManifest.xml}. -     * Must use it with {@link #EXTRA_PROVISIONING_DISCLAIMER_HEADER}. Here is the example: +     * +     * <p>For example:       *       * <pre>       *  <meta-data       *      android:name="android.app.extra.PROVISIONING_DISCLAIMER_CONTENT"       *      android:resource="@string/disclaimer_content"       * /></pre> +     * +     * <p>This must be accompanied with another extra using the key +     * {@link #EXTRA_PROVISIONING_DISCLAIMER_HEADER}.       */      public static final String EXTRA_PROVISIONING_DISCLAIMER_CONTENT =              "android.app.extra.PROVISIONING_DISCLAIMER_CONTENT";      /** -     * A boolean extra indicating if the user consent steps from the provisioning flow should be -     * skipped. If unspecified, defaults to {@code false}. +     * A boolean extra indicating if the user consent steps from the +     * <a href="#managed-provisioning">provisioning flow</a> should be skipped.       * -     * It can only be used by an existing device owner trying to create a managed profile via -     * {@link #ACTION_PROVISION_MANAGED_PROFILE}. Otherwise it is ignored. +     * <p>If unspecified, defaults to {@code false}.       *       * @deprecated this extra is no longer relevant as device owners cannot create managed profiles       */ @@ -7055,9 +7160,10 @@ public class DevicePolicyManager {      public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0;      /** -     * Disable all keyguard widgets. Has no effect starting from -     * {@link android.os.Build.VERSION_CODES#LOLLIPOP} since keyguard widget is only supported -     * on Android versions lower than 5.0. +     * Disable all keyguard widgets. Has no effect between {@link +     * android.os.Build.VERSION_CODES#LOLLIPOP} and {@link +     * android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} (both inclusive), since keyguard widget is +     * only supported on Android versions lower than 5.0 and versions higher than 14.       */      public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1 << 0; @@ -7156,7 +7262,8 @@ public class DevicePolicyManager {      public static final int ORG_OWNED_PROFILE_KEYGUARD_FEATURES_PARENT_ONLY =              DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA                      | DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS -                    | DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL; +                    | DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL +                    | DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL;      /**       * Keyguard features that when set on a normal or organization-owned managed profile, have @@ -8977,6 +9084,10 @@ public class DevicePolicyManager {       * by applications in the managed profile.       * </ul>       * <p> +     * From version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}, the profile owner of a +     * managed profile can also set {@link #KEYGUARD_DISABLE_WIDGETS_ALL} which disables keyguard +     * widgets for the managed profile. +     * <p>       * From version {@link android.os.Build.VERSION_CODES#R} the profile owner of an       * organization-owned managed profile can set:       * <ul> @@ -8985,6 +9096,12 @@ public class DevicePolicyManager {       * <li>{@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS} which affects the parent user when called       * on the parent profile.       * </ul> +     * Starting from version {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} the profile +     * owner of an organization-owned managed profile can set: +     * <ul> +     * <li>{@link #KEYGUARD_DISABLE_WIDGETS_ALL} which affects the parent user when called on the +     * parent profile. +     * </ul>       * {@link #KEYGUARD_DISABLE_TRUST_AGENTS}, {@link #KEYGUARD_DISABLE_FINGERPRINT},       * {@link #KEYGUARD_DISABLE_FACE}, {@link #KEYGUARD_DISABLE_IRIS},       * {@link #KEYGUARD_DISABLE_SECURE_CAMERA} and {@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS} @@ -17560,6 +17677,48 @@ public class DevicePolicyManager {      }      /** +     * Force sets the maximum storage size allowed for policies associated with an admin regardless +     * of the default value set in the system, unlike {@link #setMaxPolicyStorageLimit} which can +     * only set it to a value higher than the default value set by the system.Setting a limit of -1 +     * effectively removes any storage restrictions. +     * +     * @param storageLimit Maximum storage allowed in bytes. Use -1 to disable limits. +     * +     * @hide +     */ +    @TestApi +    @RequiresPermission(permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT) +    @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_INTERNAL_BUG_FIX_ENABLED) +    public void forceSetMaxPolicyStorageLimit(int storageLimit) { +        if (mService != null) { +            try { +                mService.forceSetMaxPolicyStorageLimit(mContext.getPackageName(), storageLimit); +            } catch (RemoteException e) { +                throw e.rethrowFromSystemServer(); +            } +        } +    } + +    /** +     * Retrieves the size of the current policies set by the {@code admin}. +     * +     * @hide +     */ +    @TestApi +    @RequiresPermission(permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT) +    @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_INTERNAL_BUG_FIX_ENABLED) +    public int getPolicySizeForAdmin(@NonNull EnforcingAdmin admin) { +        if (mService != null) { +            try { +                return mService.getPolicySizeForAdmin(mContext.getPackageName(), admin); +            } catch (RemoteException e) { +                throw e.rethrowFromSystemServer(); +            } +        } +        return -1; +    } + +    /**       * @return The headless device owner mode for the current set DO, returns       * {@link DeviceAdminInfo#HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED} if no DO is set.       * diff --git a/core/java/android/app/admin/EnforcingAdmin.java b/core/java/android/app/admin/EnforcingAdmin.java index 7c718f6651a2..f70a53f61671 100644 --- a/core/java/android/app/admin/EnforcingAdmin.java +++ b/core/java/android/app/admin/EnforcingAdmin.java @@ -16,9 +16,13 @@  package android.app.admin; +import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_INTERNAL_BUG_FIX_ENABLED; + +import android.annotation.FlaggedApi;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.SystemApi; +import android.annotation.TestApi;  import android.content.ComponentName;  import android.os.Parcel;  import android.os.Parcelable; @@ -60,6 +64,8 @@ public final class EnforcingAdmin implements Parcelable {       *       * @hide       */ +    @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_INTERNAL_BUG_FIX_ENABLED) +    @TestApi      public EnforcingAdmin(              @NonNull String packageName, @NonNull Authority authority,              @NonNull UserHandle userHandle, @Nullable ComponentName componentName) { @@ -101,6 +107,16 @@ public final class EnforcingAdmin implements Parcelable {          return mUserHandle;      } +    /** +     * Returns the {@link ComponentName} of the admin if applicable. +     * +     * @hide +     */ +    @Nullable +    public ComponentName getComponentName() { +        return mComponentName; +    } +      @Override      public boolean equals(@Nullable Object o) {          if (this == o) return true; diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 2002326d76bd..d1837132e1a4 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -623,8 +623,10 @@ interface IDevicePolicyManager {      int[] getSubscriptionIds(String callerPackageName); -    void setMaxPolicyStorageLimit(String packageName, int storageLimit); -    int getMaxPolicyStorageLimit(String packageName); +    void setMaxPolicyStorageLimit(String callerPackageName, int storageLimit); +    void forceSetMaxPolicyStorageLimit(String callerPackageName, int storageLimit); +    int getMaxPolicyStorageLimit(String callerPackageName); +    int getPolicySizeForAdmin(String callerPackageName, in EnforcingAdmin admin);      int getHeadlessDeviceOwnerMode(String callerPackageName);  } diff --git a/core/java/android/app/admin/LockTaskPolicy.java b/core/java/android/app/admin/LockTaskPolicy.java index a36ea0508a95..68b4ad84d81a 100644 --- a/core/java/android/app/admin/LockTaskPolicy.java +++ b/core/java/android/app/admin/LockTaskPolicy.java @@ -135,7 +135,7 @@ public final class LockTaskPolicy extends PolicyValue<LockTaskPolicy> {      }      private void setPackagesInternal(Set<String> packages) { -        if (Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              for (String p : packages) {                  PolicySizeVerifier.enforceMaxPackageNameLength(p);              } diff --git a/core/java/android/app/admin/PackagePermissionPolicyKey.java b/core/java/android/app/admin/PackagePermissionPolicyKey.java index 389585f036db..1a04f6c908bc 100644 --- a/core/java/android/app/admin/PackagePermissionPolicyKey.java +++ b/core/java/android/app/admin/PackagePermissionPolicyKey.java @@ -59,7 +59,7 @@ public final class PackagePermissionPolicyKey extends PolicyKey {      public PackagePermissionPolicyKey(@NonNull String identifier, @NonNull String packageName,              @NonNull String permissionName) {          super(identifier); -        if (Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              PolicySizeVerifier.enforceMaxPackageNameLength(packageName);              PolicySizeVerifier.enforceMaxStringLength(permissionName, "permissionName");          } diff --git a/core/java/android/app/admin/PackagePolicyKey.java b/core/java/android/app/admin/PackagePolicyKey.java index 68dc797f6513..9e31a23aec91 100644 --- a/core/java/android/app/admin/PackagePolicyKey.java +++ b/core/java/android/app/admin/PackagePolicyKey.java @@ -55,7 +55,7 @@ public final class PackagePolicyKey extends PolicyKey {      @TestApi      public PackagePolicyKey(@NonNull String key, @NonNull String packageName) {          super(key); -        if (Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              PolicySizeVerifier.enforceMaxPackageNameLength(packageName);          }          mPackageName = Objects.requireNonNull((packageName)); diff --git a/core/java/android/app/admin/Provisioning_OWNERS b/core/java/android/app/admin/Provisioning_OWNERS index 8f71fc0c4c05..91b9761f6e71 100644 --- a/core/java/android/app/admin/Provisioning_OWNERS +++ b/core/java/android/app/admin/Provisioning_OWNERS @@ -1,4 +1,4 @@  # Assign bugs to android-enterprise-triage@google.com  ae-provisioning-reviews@google.com -petuska@google.com #{LAST_RESORT_SUGGESTION} +acjohnston@google.com #{LAST_RESORT_SUGGESTION}  file:EnterprisePlatform_OWNERS diff --git a/core/java/android/app/admin/StringPolicyValue.java b/core/java/android/app/admin/StringPolicyValue.java index 8995c0f20de8..6efe9ad0dbed 100644 --- a/core/java/android/app/admin/StringPolicyValue.java +++ b/core/java/android/app/admin/StringPolicyValue.java @@ -30,7 +30,7 @@ public final class StringPolicyValue extends PolicyValue<String> {      public StringPolicyValue(@NonNull String value) {          super(value); -        if (Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              PolicySizeVerifier.enforceMaxStringLength(value, "policyValue");          }      } diff --git a/core/java/android/app/admin/StringSetPolicyValue.java b/core/java/android/app/admin/StringSetPolicyValue.java index f37dfee0f9dc..12b11f4ba687 100644 --- a/core/java/android/app/admin/StringSetPolicyValue.java +++ b/core/java/android/app/admin/StringSetPolicyValue.java @@ -32,7 +32,7 @@ public final class StringSetPolicyValue extends PolicyValue<Set<String>> {      public StringSetPolicyValue(@NonNull Set<String> value) {          super(value); -        if (Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              for (String str : value) {                  PolicySizeVerifier.enforceMaxStringLength(str, "policyValue");              } diff --git a/core/java/android/app/admin/UserRestrictionPolicyKey.java b/core/java/android/app/admin/UserRestrictionPolicyKey.java index ee90ccd9417f..9054287cb7a0 100644 --- a/core/java/android/app/admin/UserRestrictionPolicyKey.java +++ b/core/java/android/app/admin/UserRestrictionPolicyKey.java @@ -45,7 +45,7 @@ public final class UserRestrictionPolicyKey extends PolicyKey {      @TestApi      public UserRestrictionPolicyKey(@NonNull String identifier, @NonNull String restriction) {          super(identifier); -        if (Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              PolicySizeVerifier.enforceMaxStringLength(restriction, "restriction");          }          mRestriction = Objects.requireNonNull(restriction); diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig index fe2f7641cda6..6a07484eebc6 100644 --- a/core/java/android/app/admin/flags/flags.aconfig +++ b/core/java/android/app/admin/flags/flags.aconfig @@ -27,6 +27,17 @@ flag {  }  flag { +  name: "device_policy_size_tracking_internal_bug_fix_enabled" +  namespace: "enterprise" +  description: "Bug fix for tracking the total policy size and have a max threshold" +  bug: "281543351" +  metadata { +      purpose: PURPOSE_BUGFIX +  } +} + + +flag {    name: "onboarding_bugreport_v2_enabled"    is_exported: true    namespace: "enterprise" @@ -232,3 +243,13 @@ flag {      purpose: PURPOSE_BUGFIX    }  } + +flag { +    name: "headless_single_user_bad_device_admin_state_fix" +    namespace: "enterprise" +    description: "Fix the bad state in DPMS caused by an earlier bug related to the headless single user change" +    bug: "332477138" +    metadata { +      purpose: PURPOSE_BUGFIX +    } +} diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index 0214d40f8441..250953e61137 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -74,6 +74,16 @@ flag {  }  flag { +  name: "secure_allowlist_token" +  namespace: "systemui" +  description: "Prevents allowlist_token from leaking out and foreign tokens from being accepted" +  bug: "328254922" +  metadata { +    purpose: PURPOSE_BUGFIX +  } +} + +flag {    name: "update_ranking_time"    namespace: "systemui"    description: "Updates notification sorting criteria to highlight new content while maintaining stability" @@ -109,4 +119,11 @@ flag {    namespace: "systemui"    description: "No notifs can use USAGE_UNKNOWN or USAGE_MEDIA"    bug: "331793339" +} + +flag { +  name: "clean_up_spans_and_new_lines" +  namespace: "systemui" +  description: "Cleans up spans and unnecessary new lines from standard notification templates" +  bug: "313439845"  }
\ No newline at end of file diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java index 631772556879..11d7ff86ce3d 100644 --- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java +++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java @@ -23,7 +23,6 @@ import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.ActivityThread.ActivityClientRecord;  import android.app.ClientTransactionHandler; -import android.content.Context;  import android.content.res.CompatibilityInfo;  import android.content.res.Configuration;  import android.os.IBinder; @@ -60,12 +59,6 @@ public class ActivityConfigurationChangeItem extends ActivityTransactionItem {          Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);      } -    @Nullable -    @Override -    public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { -        return client.getActivity(getActivityToken()); -    } -      // ObjectPoolItem implementation      private ActivityConfigurationChangeItem() {} diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java index 6da871a74383..45bf235de2cd 100644 --- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java +++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java @@ -23,7 +23,6 @@ import android.annotation.Nullable;  import android.app.ActivityThread.ActivityClientRecord;  import android.app.ClientTransactionHandler;  import android.app.ResultInfo; -import android.content.Context;  import android.content.res.CompatibilityInfo;  import android.os.IBinder;  import android.os.Parcel; @@ -88,12 +87,6 @@ public class ActivityRelaunchItem extends ActivityTransactionItem {          client.reportRelaunch(r);      } -    @Nullable -    @Override -    public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { -        return client.getActivity(getActivityToken()); -    } -      // ObjectPoolItem implementation      private ActivityRelaunchItem() {} diff --git a/core/java/android/app/servertransaction/ClientTransactionItem.java b/core/java/android/app/servertransaction/ClientTransactionItem.java index a8d61db1ce3a..99ebe1b975a4 100644 --- a/core/java/android/app/servertransaction/ClientTransactionItem.java +++ b/core/java/android/app/servertransaction/ClientTransactionItem.java @@ -24,7 +24,6 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility.PACK  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.ClientTransactionHandler; -import android.content.Context;  import android.os.IBinder;  import android.os.Parcelable; @@ -54,15 +53,6 @@ public abstract class ClientTransactionItem implements BaseClientRequest, Parcel      }      /** -     * If this {@link ClientTransactionItem} is updating configuration, returns the {@link Context} -     * it is updating; otherwise, returns {@code null}. -     */ -    @Nullable -    public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { -        return null; -    } - -    /**       * Returns the activity token if this transaction item is activity-targeting. Otherwise,       * returns {@code null}.       */ diff --git a/core/java/android/app/servertransaction/ClientTransactionListenerController.java b/core/java/android/app/servertransaction/ClientTransactionListenerController.java index c55b0f110b3b..722d5f0fe462 100644 --- a/core/java/android/app/servertransaction/ClientTransactionListenerController.java +++ b/core/java/android/app/servertransaction/ClientTransactionListenerController.java @@ -16,6 +16,8 @@  package android.app.servertransaction; +import static android.app.WindowConfiguration.areConfigurationsEqualForDisplay; +  import static com.android.window.flags.Flags.activityWindowInfoFlag;  import static com.android.window.flags.Flags.bundleClientTransactionFlag; @@ -24,8 +26,11 @@ import static java.util.Objects.requireNonNull;  import android.annotation.NonNull;  import android.app.Activity;  import android.app.ActivityThread; +import android.content.Context; +import android.content.res.Configuration;  import android.hardware.display.DisplayManagerGlobal;  import android.os.IBinder; +import android.util.ArrayMap;  import android.util.ArraySet;  import android.window.ActivityWindowInfo; @@ -51,6 +56,15 @@ public class ClientTransactionListenerController {      private final ArraySet<BiConsumer<IBinder, ActivityWindowInfo>>              mActivityWindowInfoChangedListeners = new ArraySet<>(); +    /** +     * Keeps track of the Context whose Configuration will get updated, mapping to the config before +     * the change. +     */ +    private final ArrayMap<Context, Configuration> mContextToPreChangedConfigMap = new ArrayMap<>(); + +    /** Whether there is an {@link ClientTransaction} being executed. */ +    private boolean mIsClientTransactionExecuting; +      /** Gets the singleton controller. */      @NonNull      public static ClientTransactionListenerController getInstance() { @@ -126,18 +140,92 @@ public class ClientTransactionListenerController {          }      } -    /** -     * Called when receives a {@link ClientTransaction} that is updating display-related -     * window configuration. -     */ -    public void onDisplayChanged(int displayId) { -        if (!bundleClientTransactionFlag()) { +    /** Called when starts executing a remote {@link ClientTransaction}. */ +    public void onClientTransactionStarted() { +        mIsClientTransactionExecuting = true; +    } + +    /** Called when finishes executing a remote {@link ClientTransaction}. */ +    public void onClientTransactionFinished() { +        notifyDisplayManagerIfNeeded(); +        mIsClientTransactionExecuting = false; +    } + +    /** Called before updating the Configuration of the given {@code context}. */ +    public void onContextConfigurationPreChanged(@NonNull Context context) { +        if (!bundleClientTransactionFlag() || ActivityThread.isSystem()) { +            // Not enable for system server. +            return; +        } +        if (mContextToPreChangedConfigMap.containsKey(context)) { +            // There is an earlier change that hasn't been reported yet.              return;          } -        if (ActivityThread.isSystem()) { +        mContextToPreChangedConfigMap.put(context, +                new Configuration(context.getResources().getConfiguration())); +    } + +    /** Called after updating the Configuration of the given {@code context}. */ +    public void onContextConfigurationPostChanged(@NonNull Context context) { +        if (!bundleClientTransactionFlag() || ActivityThread.isSystem()) {              // Not enable for system server.              return;          } +        if (mIsClientTransactionExecuting) { +            // Wait until #onClientTransactionFinished to prevent it from triggering the same +            // #onDisplayChanged multiple times within the same ClientTransaction. +            return; +        } +        final Configuration preChangedConfig = mContextToPreChangedConfigMap.remove(context); +        if (preChangedConfig != null && shouldReportDisplayChange(context, preChangedConfig)) { +            onDisplayChanged(context.getDisplayId()); +        } +    } + +    /** +     * When {@link Configuration} is changed, we want to trigger display change callback as well, +     * because Display reads some fields from {@link Configuration}. +     */ +    private void notifyDisplayManagerIfNeeded() { +        if (mContextToPreChangedConfigMap.isEmpty()) { +            return; +        } +        // Whether the configuration change should trigger DisplayListener#onDisplayChanged. +        try { +            // Calculate display ids that have config changed. +            final ArraySet<Integer> configUpdatedDisplayIds = new ArraySet<>(); +            final int contextCount = mContextToPreChangedConfigMap.size(); +            for (int i = 0; i < contextCount; i++) { +                final Context context = mContextToPreChangedConfigMap.keyAt(i); +                final Configuration preChangedConfig = mContextToPreChangedConfigMap.valueAt(i); +                if (shouldReportDisplayChange(context, preChangedConfig)) { +                    configUpdatedDisplayIds.add(context.getDisplayId()); +                } +            } + +            // Dispatch the display changed callbacks. +            final int displayCount = configUpdatedDisplayIds.size(); +            for (int i = 0; i < displayCount; i++) { +                final int displayId = configUpdatedDisplayIds.valueAt(i); +                onDisplayChanged(displayId); +            } +        } finally { +            mContextToPreChangedConfigMap.clear(); +        } +    } + +    private boolean shouldReportDisplayChange(@NonNull Context context, +            @NonNull Configuration preChangedConfig) { +        final Configuration postChangedConfig = context.getResources().getConfiguration(); +        return !areConfigurationsEqualForDisplay(postChangedConfig, preChangedConfig); +    } + +    /** +     * Called when receives a {@link Configuration} changed event that is updating display-related +     * window configuration. +     */ +    @VisibleForTesting +    public void onDisplayChanged(int displayId) {          mDisplayManager.handleDisplayChangeFromWindowManager(displayId);      }  } diff --git a/core/java/android/app/servertransaction/ConfigurationChangeItem.java b/core/java/android/app/servertransaction/ConfigurationChangeItem.java index 0e327a7627d1..22da706cc7f4 100644 --- a/core/java/android/app/servertransaction/ConfigurationChangeItem.java +++ b/core/java/android/app/servertransaction/ConfigurationChangeItem.java @@ -18,9 +18,7 @@ package android.app.servertransaction;  import android.annotation.NonNull;  import android.annotation.Nullable; -import android.app.ActivityThread;  import android.app.ClientTransactionHandler; -import android.content.Context;  import android.content.res.CompatibilityInfo;  import android.content.res.Configuration;  import android.os.Parcel; @@ -48,12 +46,6 @@ public class ConfigurationChangeItem extends ClientTransactionItem {          client.handleConfigurationChanged(mConfiguration, mDeviceId);      } -    @Nullable -    @Override -    public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { -        return ActivityThread.currentApplication(); -    } -      // ObjectPoolItem implementation      private ConfigurationChangeItem() {} diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index f02cb212276b..7dcbebaeba0b 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -24,14 +24,12 @@ import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.ActivityClient;  import android.app.ActivityOptions.SceneTransitionInfo; -import android.app.ActivityThread;  import android.app.ActivityThread.ActivityClientRecord;  import android.app.ClientTransactionHandler;  import android.app.IActivityClientController;  import android.app.ProfilerInfo;  import android.app.ResultInfo;  import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context;  import android.content.Intent;  import android.content.pm.ActivityInfo;  import android.content.res.CompatibilityInfo; @@ -121,13 +119,6 @@ public class LaunchActivityItem extends ClientTransactionItem {          client.countLaunchingActivities(-1);      } -    @Nullable -    @Override -    public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { -        // LaunchActivityItem may update the global config with #mCurConfig. -        return ActivityThread.currentApplication(); -    } -      // ObjectPoolItem implementation      private LaunchActivityItem() {} diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java index 0702c4594075..8706edd26406 100644 --- a/core/java/android/app/servertransaction/MoveToDisplayItem.java +++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java @@ -22,7 +22,6 @@ import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.ActivityThread.ActivityClientRecord;  import android.app.ClientTransactionHandler; -import android.content.Context;  import android.content.res.CompatibilityInfo;  import android.content.res.Configuration;  import android.os.IBinder; @@ -59,12 +58,6 @@ public class MoveToDisplayItem extends ActivityTransactionItem {          Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);      } -    @Nullable -    @Override -    public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { -        return client.getActivity(getActivityToken()); -    } -      // ObjectPoolItem implementation      private MoveToDisplayItem() {} diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index c83719149821..480205ebc756 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -16,7 +16,6 @@  package android.app.servertransaction; -import static android.app.WindowConfiguration.areConfigurationsEqualForDisplay;  import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;  import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY;  import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE; @@ -32,17 +31,12 @@ import static android.app.servertransaction.TransactionExecutorHelper.shouldExcl  import static android.app.servertransaction.TransactionExecutorHelper.tId;  import static android.app.servertransaction.TransactionExecutorHelper.transactionToString; -import static com.android.window.flags.Flags.bundleClientTransactionFlag; -  import android.annotation.NonNull;  import android.app.ActivityThread.ActivityClientRecord;  import android.app.ClientTransactionHandler;  import android.content.Context; -import android.content.res.Configuration;  import android.os.IBinder;  import android.os.Trace; -import android.util.ArrayMap; -import android.util.ArraySet;  import android.util.IntArray;  import android.util.Slog; @@ -63,12 +57,6 @@ public class TransactionExecutor {      private final PendingTransactionActions mPendingActions = new PendingTransactionActions();      private final TransactionExecutorHelper mHelper = new TransactionExecutorHelper(); -    /** -     * Keeps track of the Context whose Configuration got updated within a transaction, mapping to -     * the config before the transaction. -     */ -    private final ArrayMap<Context, Configuration> mContextToPreChangedConfigMap = new ArrayMap<>(); -      /** Initialize an instance with transaction handler, that will execute all requested actions. */      public TransactionExecutor(@NonNull ClientTransactionHandler clientTransactionHandler) {          mTransactionHandler = clientTransactionHandler; @@ -104,37 +92,6 @@ public class TransactionExecutor {              Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);          } -        if (!mContextToPreChangedConfigMap.isEmpty()) { -            // Whether this transaction should trigger DisplayListener#onDisplayChanged. -            try { -                // Calculate display ids that have config changed. -                final ArraySet<Integer> configUpdatedDisplayIds = new ArraySet<>(); -                final int contextCount = mContextToPreChangedConfigMap.size(); -                for (int i = 0; i < contextCount; i++) { -                    final Context context = mContextToPreChangedConfigMap.keyAt(i); -                    final Configuration preTransactionConfig = -                            mContextToPreChangedConfigMap.valueAt(i); -                    final Configuration postTransactionConfig = context.getResources() -                            .getConfiguration(); -                    if (!areConfigurationsEqualForDisplay( -                            postTransactionConfig, preTransactionConfig)) { -                        configUpdatedDisplayIds.add(context.getDisplayId()); -                    } -                } - -                // Dispatch the display changed callbacks. -                final ClientTransactionListenerController controller = -                        ClientTransactionListenerController.getInstance(); -                final int displayCount = configUpdatedDisplayIds.size(); -                for (int i = 0; i < displayCount; i++) { -                    final int displayId = configUpdatedDisplayIds.valueAt(i); -                    controller.onDisplayChanged(displayId); -                } -            } finally { -                mContextToPreChangedConfigMap.clear(); -            } -        } -          mPendingActions.clear();          if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");      } @@ -214,20 +171,6 @@ public class TransactionExecutor {              }          } -        final boolean shouldTrackConfigUpdatedContext = -                // No configuration change for local transaction. -                !mTransactionHandler.isExecutingLocalTransaction() -                        && bundleClientTransactionFlag(); -        final Context configUpdatedContext = shouldTrackConfigUpdatedContext -                ? item.getContextToUpdate(mTransactionHandler) -                : null; -        if (configUpdatedContext != null -                && !mContextToPreChangedConfigMap.containsKey(configUpdatedContext)) { -            // Keep track of the first pre-executed config of each changed Context. -            mContextToPreChangedConfigMap.put(configUpdatedContext, -                    new Configuration(configUpdatedContext.getResources().getConfiguration())); -        } -          item.execute(mTransactionHandler, mPendingActions);          item.postExecute(mTransactionHandler, mPendingActions); diff --git a/core/java/android/app/servertransaction/WindowContextInfoChangeItem.java b/core/java/android/app/servertransaction/WindowContextInfoChangeItem.java index cbad92ff3f38..f6a72915e639 100644 --- a/core/java/android/app/servertransaction/WindowContextInfoChangeItem.java +++ b/core/java/android/app/servertransaction/WindowContextInfoChangeItem.java @@ -21,7 +21,6 @@ import static java.util.Objects.requireNonNull;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.ClientTransactionHandler; -import android.content.Context;  import android.content.res.Configuration;  import android.os.IBinder;  import android.os.Parcel; @@ -46,12 +45,6 @@ public class WindowContextInfoChangeItem extends ClientTransactionItem {          client.handleWindowContextInfoChanged(mClientToken, mInfo);      } -    @Nullable -    @Override -    public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { -        return client.getWindowContext(mClientToken); -    } -      // ObjectPoolItem implementation      private WindowContextInfoChangeItem() {} diff --git a/core/java/android/app/servertransaction/WindowStateResizeItem.java b/core/java/android/app/servertransaction/WindowStateResizeItem.java index 1817c5eefb14..da99096f022a 100644 --- a/core/java/android/app/servertransaction/WindowStateResizeItem.java +++ b/core/java/android/app/servertransaction/WindowStateResizeItem.java @@ -22,10 +22,7 @@ import static java.util.Objects.requireNonNull;  import android.annotation.NonNull;  import android.annotation.Nullable; -import android.app.ActivityThread;  import android.app.ClientTransactionHandler; -import android.content.Context; -import android.os.IBinder;  import android.os.Parcel;  import android.os.RemoteException;  import android.os.Trace; @@ -59,10 +56,6 @@ public class WindowStateResizeItem extends ClientTransactionItem {      /** {@code null} if this is not an Activity window. */      @Nullable -    private IBinder mActivityToken; - -    /** {@code null} if this is not an Activity window. */ -    @Nullable      private ActivityWindowInfo mActivityWindowInfo;      @Override @@ -86,14 +79,6 @@ public class WindowStateResizeItem extends ClientTransactionItem {          Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);      } -    @Nullable -    @Override -    public Context getContextToUpdate(@NonNull ClientTransactionHandler client) { -        // TODO(b/260873529): dispatch for mActivityToken as well. -        // WindowStateResizeItem may update the global config with #mConfiguration. -        return ActivityThread.currentApplication(); -    } -      // ObjectPoolItem implementation      private WindowStateResizeItem() {} @@ -103,8 +88,7 @@ public class WindowStateResizeItem extends ClientTransactionItem {              @NonNull ClientWindowFrames frames, boolean reportDraw,              @NonNull MergedConfiguration configuration, @NonNull InsetsState insetsState,              boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId, int syncSeqId, -            boolean dragResizing, @Nullable IBinder activityToken, -            @Nullable ActivityWindowInfo activityWindowInfo) { +            boolean dragResizing, @Nullable ActivityWindowInfo activityWindowInfo) {          WindowStateResizeItem instance =                  ObjectPool.obtain(WindowStateResizeItem.class);          if (instance == null) { @@ -120,7 +104,6 @@ public class WindowStateResizeItem extends ClientTransactionItem {          instance.mDisplayId = displayId;          instance.mSyncSeqId = syncSeqId;          instance.mDragResizing = dragResizing; -        instance.mActivityToken = activityToken;          instance.mActivityWindowInfo = activityWindowInfo != null                  ? new ActivityWindowInfo(activityWindowInfo)                  : null; @@ -140,7 +123,6 @@ public class WindowStateResizeItem extends ClientTransactionItem {          mDisplayId = INVALID_DISPLAY;          mSyncSeqId = -1;          mDragResizing = false; -        mActivityToken = null;          mActivityWindowInfo = null;          ObjectPool.recycle(this);      } @@ -160,7 +142,6 @@ public class WindowStateResizeItem extends ClientTransactionItem {          dest.writeInt(mDisplayId);          dest.writeInt(mSyncSeqId);          dest.writeBoolean(mDragResizing); -        dest.writeStrongBinder(mActivityToken);          dest.writeTypedObject(mActivityWindowInfo, flags);      } @@ -176,7 +157,6 @@ public class WindowStateResizeItem extends ClientTransactionItem {          mDisplayId = in.readInt();          mSyncSeqId = in.readInt();          mDragResizing = in.readBoolean(); -        mActivityToken = in.readStrongBinder();          mActivityWindowInfo = in.readTypedObject(ActivityWindowInfo.CREATOR);      } @@ -209,7 +189,6 @@ public class WindowStateResizeItem extends ClientTransactionItem {                  && mDisplayId == other.mDisplayId                  && mSyncSeqId == other.mSyncSeqId                  && mDragResizing == other.mDragResizing -                && Objects.equals(mActivityToken, other.mActivityToken)                  && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo);      } @@ -226,7 +205,6 @@ public class WindowStateResizeItem extends ClientTransactionItem {          result = 31 * result + mDisplayId;          result = 31 * result + mSyncSeqId;          result = 31 * result + (mDragResizing ? 1 : 0); -        result = 31 * result + Objects.hashCode(mActivityToken);          result = 31 * result + Objects.hashCode(mActivityWindowInfo);          return result;      } @@ -236,7 +214,6 @@ public class WindowStateResizeItem extends ClientTransactionItem {          return "WindowStateResizeItem{window=" + mWindow                  + ", reportDrawn=" + mReportDraw                  + ", configuration=" + mConfiguration -                + ", activityToken=" + mActivityToken                  + ", activityWindowInfo=" + mActivityWindowInfo                  + "}";      } diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig index 451195478760..765c802c2df3 100644 --- a/core/java/android/appwidget/flags.aconfig +++ b/core/java/android/appwidget/flags.aconfig @@ -32,3 +32,10 @@ flag {    description: "Enable support for transporting draw instructions as data parcel"    bug: "286130467"  } + +flag { +  name: "throttle_widget_updates" +  namespace: "app_widgets" +  description: "Throttle the widget view updates to mitigate transaction exceptions" +  bug: "326145514" +} diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index b706cae17547..bad73fc68f3a 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3256,6 +3256,14 @@ public abstract class Context {       *       * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.       * +     * <p>As of {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the system can <a +     * href="{@docRoot}develop/background-work/background-tasks/broadcasts#android-14">place +     * context-registered broadcasts in a queue while the app is in the <a +     * href="{@docRoot}guide/components/activities/process-lifecycle">cached state</a>. +     * When the app leaves the cached state, such as returning to the +     * foreground, the system delivers any queued broadcasts. Multiple instances +     * of certain broadcasts might be merged into one broadcast. +     *       * <p>As of {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, receivers       * registered with this method will correctly respect the       * {@link Intent#setPackage(String)} specified for an Intent being broadcast. @@ -3301,6 +3309,14 @@ public abstract class Context {       *       * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.       * +     * <p>As of {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the system can <a +     * href="{@docRoot}develop/background-work/background-tasks/broadcasts#android-14">place +     * context-registered broadcasts in a queue while the app is in the <a +     * href="{@docRoot}guide/components/activities/process-lifecycle">cached state</a>. +     * When the app leaves the cached state, such as returning to the +     * foreground, the system delivers any queued broadcasts. Multiple instances +     * of certain broadcasts might be merged into one broadcast. +     *       * <p>As of {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, receivers       * registered with this method will correctly respect the       * {@link Intent#setPackage(String)} specified for an Intent being broadcast. @@ -3342,6 +3358,14 @@ public abstract class Context {       *       * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.       * +     * <p>As of {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the system can <a +     * href="{@docRoot}develop/background-work/background-tasks/broadcasts#android-14">place +     * context-registered broadcasts in a queue while the app is in the <a +     * href="{@docRoot}guide/components/activities/process-lifecycle">cached state</a>. +     * When the app leaves the cached state, such as returning to the +     * foreground, the system delivers any queued broadcasts. Multiple instances +     * of certain broadcasts might be merged into one broadcast. +     *       * <p>As of {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, receivers       * registered with this method will correctly respect the       * {@link Intent#setPackage(String)} specified for an Intent being broadcast. @@ -3385,6 +3409,14 @@ public abstract class Context {       *       * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.       * +     * <p>As of {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the system can <a +     * href="{@docRoot}develop/background-work/background-tasks/broadcasts#android-14">place +     * context-registered broadcasts in a queue while the app is in the <a +     * href="{@docRoot}guide/components/activities/process-lifecycle">cached state</a>. +     * When the app leaves the cached state, such as returning to the +     * foreground, the system delivers any queued broadcasts. Multiple instances +     * of certain broadcasts might be merged into one broadcast. +     *       * <p>As of {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, receivers       * registered with this method will correctly respect the       * {@link Intent#setPackage(String)} specified for an Intent being broadcast. diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java index 93fa5d85796f..eb7afb8ea82c 100644 --- a/core/java/android/credentials/CredentialManager.java +++ b/core/java/android/credentials/CredentialManager.java @@ -61,7 +61,9 @@ import java.util.concurrent.Executor;  @SystemService(Context.CREDENTIAL_SERVICE)  @RequiresFeature(PackageManager.FEATURE_CREDENTIALS)  public final class CredentialManager { -    private static final String TAG = "CredentialManager"; +    /** @hide **/ +    @Hide +    public static final String TAG = "CredentialManager";      private static final Bundle OPTIONS_SENDER_BAL_OPTIN = ActivityOptions.makeBasic()              .setPendingIntentBackgroundActivityStartMode(                      ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED).toBundle(); diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java index a51a74075298..d9a18d785537 100644 --- a/core/java/android/ddm/DdmHandleHello.java +++ b/core/java/android/ddm/DdmHandleHello.java @@ -42,12 +42,6 @@ public class DdmHandleHello extends DdmHandle {      private static DdmHandleHello mInstance = new DdmHandleHello(); -    private static final String[] FRAMEWORK_FEATURES = new String[] { -        "opengl-tracing", -        "view-hierarchy", -        "support_boot_stages" -    }; -      /* singleton, do not instantiate */      private DdmHandleHello() {} @@ -193,22 +187,25 @@ public class DdmHandleHello extends DdmHandle {          if (false)              Log.v("ddm-heap", "Got feature list request"); -        int size = 4 + 4 * (vmFeatures.length + FRAMEWORK_FEATURES.length); -        for (int i = vmFeatures.length-1; i >= 0; i--) +        String[] fmFeatures = Debug.getFeatureList(); +        int size = 4 + 4 * (vmFeatures.length + fmFeatures.length); +        for (int i = vmFeatures.length - 1; i >= 0; i--) {              size += vmFeatures[i].length() * 2; -        for (int i = FRAMEWORK_FEATURES.length-1; i>= 0; i--) -            size += FRAMEWORK_FEATURES[i].length() * 2; +        } +        for (int i = fmFeatures.length - 1; i >= 0; i--) { +            size += fmFeatures[i].length() * 2; +        }          ByteBuffer out = ByteBuffer.allocate(size);          out.order(ChunkHandler.CHUNK_ORDER); -        out.putInt(vmFeatures.length + FRAMEWORK_FEATURES.length); +        out.putInt(vmFeatures.length + fmFeatures.length);          for (int i = vmFeatures.length-1; i >= 0; i--) {              out.putInt(vmFeatures[i].length());              putString(out, vmFeatures[i]);          } -        for (int i = FRAMEWORK_FEATURES.length-1; i >= 0; i--) { -            out.putInt(FRAMEWORK_FEATURES[i].length()); -            putString(out, FRAMEWORK_FEATURES[i]); +        for (int i = fmFeatures.length - 1; i >= 0; i--) { +            out.putInt(fmFeatures[i].length()); +            putString(out, fmFeatures[i]);          }          return new Chunk(CHUNK_FEAT, out); diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index dca663d206d3..50d976f683cb 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -1768,9 +1768,12 @@ public abstract class CameraDevice implements AutoCloseable {           * @param sessionConfig The session configuration for which characteristics are fetched.           * @return CameraCharacteristics specific to a given session configuration.           * -         * @throws IllegalArgumentException      if the session configuration is invalid -         * @throws CameraAccessException         if the camera device is no longer connected or has -         *                                       encountered a fatal error +         * @throws IllegalArgumentException if the session configuration is invalid or if +         *                                  {@link #isSessionConfigurationSupported} returns +         *                                  {@code false} for the provided +         *                                  {@link SessionConfiguration} +         * @throws CameraAccessException    if the camera device is no longer connected or has +         *                                  encountered a fatal error           *           * @see CameraCharacteristics#getAvailableSessionCharacteristicsKeys           */ diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 4cd40ea57f0f..90a2cf0ce39e 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -1969,9 +1969,6 @@ public final class CameraManager {          private static final String TAG = "CameraManagerGlobal"; -        private static final String BACK_CAMERA_ID = "0"; -        private static final String FRONT_CAMERA_ID = "1"; -          private final boolean DEBUG = false;          private final int CAMERA_SERVICE_RECONNECT_DELAY_MS = 1000; @@ -2309,11 +2306,6 @@ public final class CameraManager {                  return false;              } -            // External cameras should never be hidden. -            if (!info.mCameraId.equals(FRONT_CAMERA_ID) && !info.mCameraId.equals(BACK_CAMERA_ID)) { -                return false; -            } -              return currentDeviceId != info.mDeviceId;          } diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java index 81d0976c09bb..372839d837f9 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java @@ -104,8 +104,8 @@ public class CameraDeviceSetupImpl extends CameraDevice.CameraDeviceSetup {              }              try { -                return cameraService.isSessionConfigurationWithParametersSupported( -                        mCameraId, config, mContext.getDeviceId(), +                return cameraService.isSessionConfigurationWithParametersSupported(mCameraId, +                        mTargetSdkVersion, config, mContext.getDeviceId(),                          mCameraManager.getDevicePolicyFromContext(mContext));              } catch (ServiceSpecificException e) {                  throw ExceptionUtils.throwAsPublicException(e); diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index ec67212b46b7..89ab105e8ce3 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -364,6 +364,14 @@ public abstract class DisplayManagerInternal {      public abstract List<RefreshRateLimitation> getRefreshRateLimitations(int displayId);      /** +     * Returns if vrr support is enabled for specified display +     * +     * @param displayId The id of the display. +     * @return true if associated display supports dvrr +     */ +    public abstract boolean isVrrSupportEnabled(int displayId); + +    /**       * For the given displayId, updates if WindowManager is responsible for mirroring on that       * display. If {@code false}, then SurfaceFlinger performs no layer mirroring to the       * given display. diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index f785cca4e9f4..a55398ac9752 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -110,6 +110,12 @@ public final class Debug      private static final String DEFAULT_TRACE_BODY = "dmtrace";      private static final String DEFAULT_TRACE_EXTENSION = ".trace"; +    private static final String[] FRAMEWORK_FEATURES = new String[] { +        "opengl-tracing", +        "view-hierarchy", +        "support_boot_stages", +    }; +      /**       * This class is used to retrieved various statistics about the memory mappings for this       * process. The returned info is broken down by dalvik, native, and other. All results are in kB. @@ -1106,6 +1112,17 @@ public final class Debug      }      /** +     * Returns an array of strings that identify Framework features. This is +     * used by DDMS to determine what sorts of operations the Framework can +     * perform. +     * +     * @hide +     */ +    public static String[] getFeatureList() { +        return FRAMEWORK_FEATURES; +    } + +    /**       * Change the JDWP port.       *       * @deprecated no longer needed or useful diff --git a/core/java/android/os/OomKillRecord.java b/core/java/android/os/OomKillRecord.java index ca1d49a93def..78fbce63b00d 100644 --- a/core/java/android/os/OomKillRecord.java +++ b/core/java/android/os/OomKillRecord.java @@ -25,7 +25,7 @@ import com.android.internal.util.FrameworkStatsLog;   * Note that this class fields' should be equivalent to the struct   * <b>OomKill</b> inside   * <pre> - * system/memory/libmeminfo/libmemevents/include/memevents.h + * system/memory/libmeminfo/libmemevents/include/memevents/bpf_types.h   * </pre>   *   * @hide @@ -36,14 +36,27 @@ public final class OomKillRecord {      private int mUid;      private String mProcessName;      private short mOomScoreAdj; +    private long mTotalVmInKb; +    private long mAnonRssInKb; +    private long mFileRssInKb; +    private long mShmemRssInKb; +    private long mPgTablesInKb;      public OomKillRecord(long timeStampInMillis, int pid, int uid, -                            String processName, short oomScoreAdj) { +                            String processName, short oomScoreAdj, +                            long totalVmInKb, long anonRssInKb, +                            long fileRssInKb, long shmemRssInKb, +                            long pgTablesInKb) {          this.mTimeStampInMillis = timeStampInMillis;          this.mPid = pid;          this.mUid = uid;          this.mProcessName = processName;          this.mOomScoreAdj = oomScoreAdj; +        this.mTotalVmInKb = totalVmInKb; +        this.mAnonRssInKb = anonRssInKb; +        this.mFileRssInKb = fileRssInKb; +        this.mShmemRssInKb = shmemRssInKb; +        this.mPgTablesInKb = pgTablesInKb;      }      /** @@ -55,7 +68,8 @@ public final class OomKillRecord {          FrameworkStatsLog.write(                  FrameworkStatsLog.KERNEL_OOM_KILL_OCCURRED,                  mUid, mPid, mOomScoreAdj, mTimeStampInMillis, -                mProcessName); +                mProcessName, mTotalVmInKb, mAnonRssInKb, +                mFileRssInKb, mShmemRssInKb, mPgTablesInKb);      }      public long getTimestampMilli() { diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 35a3a5f32648..136c45d1695f 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -863,6 +863,28 @@ public final class Parcel {      }      /** @hide */ +    public void removeClassCookie(Class clz, Object expectedCookie) { +        if (mClassCookies != null) { +            Object removedCookie = mClassCookies.remove(clz); +            if (removedCookie != expectedCookie) { +                Log.wtf(TAG, "Expected to remove " + expectedCookie + " (with key=" + clz +                        + ") but instead removed " + removedCookie); +            } +        } else { +            Log.wtf(TAG, "Expected to remove " + expectedCookie + " (with key=" + clz +                    + ") but no cookies were present"); +        } +    } + +    /** +     * Whether {@link #setClassCookie} has been called with the specified {@code clz}. +     * @hide +     */ +    public boolean hasClassCookie(Class clz) { +        return mClassCookies != null && mClassCookies.containsKey(clz); +    } + +    /** @hide */      public final void adoptClassCookies(Parcel from) {          mClassCookies = from.mClassCookies;      } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index f172c3e52415..857a85d99fa6 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -705,7 +705,7 @@ public class UserManager {       * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_BLUETOOTH}       * can set this restriction using the DevicePolicyManager APIs mentioned below.       * -     * <p>Default is <code>true</code> for managed profiles and false otherwise. +     * <p>Default is <code>true</code> for managed and private profiles, false otherwise.       *       * <p>When a device upgrades to {@link android.os.Build.VERSION_CODES#O}, the system sets it       * for all existing managed profiles. diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index ec3c9789f655..23ece310b926 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -155,14 +155,3 @@ flag {      description: "Use runtime permission state to determine appop state"      bug: "266164193"  } - -flag { -    name: "ignore_apex_permissions" -    is_fixed_read_only: true -    namespace: "permissions" -    description: "Ignore APEX pacakges for permissions on V+" -    bug: "301320911" -    metadata { -        purpose: PURPOSE_BUGFIX -    } -} diff --git a/core/java/android/service/credentials/CredentialProviderInfoFactory.java b/core/java/android/service/credentials/CredentialProviderInfoFactory.java index c6d3d9b6da84..92f2c321c1db 100644 --- a/core/java/android/service/credentials/CredentialProviderInfoFactory.java +++ b/core/java/android/service/credentials/CredentialProviderInfoFactory.java @@ -65,7 +65,7 @@ import java.util.Set;   * @hide   */  public final class CredentialProviderInfoFactory { -    private static final String TAG = "CredentialProviderInfoFactory"; +    private static final String TAG = CredentialManager.TAG;      private static final String TAG_CREDENTIAL_PROVIDER = "credential-provider";      private static final String TAG_CAPABILITIES = "capabilities"; diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java index ea7efc79de87..c1ed19fef032 100644 --- a/core/java/android/util/PackageUtils.java +++ b/core/java/android/util/PackageUtils.java @@ -203,9 +203,8 @@ public final class PackageUtils {          }          File f = new File(filePath); -        try { -            DigestInputStream digestInputStream = new DigestInputStream(new FileInputStream(f), -                    messageDigest); +        try (DigestInputStream digestInputStream = new DigestInputStream(new FileInputStream(f), +                messageDigest)) {              while (digestInputStream.read(fileBuffer) != -1);          } catch (IOException e) {              e.printStackTrace(); diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java index f4dadbb0d25a..beb4d95263be 100644 --- a/core/java/android/view/HandwritingInitiator.java +++ b/core/java/android/view/HandwritingInitiator.java @@ -17,6 +17,7 @@  package android.view;  import static com.android.text.flags.Flags.handwritingCursorPosition; +import static com.android.text.flags.Flags.handwritingUnsupportedMessage;  import android.annotation.FlaggedApi;  import android.annotation.NonNull; @@ -607,7 +608,9 @@ public class HandwritingInitiator {              final View candidateView = findBestCandidateView(hoverX, hoverY, /* isHover */ true);              if (candidateView != null) { -                mCachedHoverTarget = new WeakReference<>(candidateView); +                if (!handwritingUnsupportedMessage()) { +                    mCachedHoverTarget = new WeakReference<>(candidateView); +                }                  return candidateView;              }          } diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java index 253073a83827..69228cafa34b 100644 --- a/core/java/android/view/HapticFeedbackConstants.java +++ b/core/java/android/view/HapticFeedbackConstants.java @@ -83,11 +83,7 @@ public class HapticFeedbackConstants {       */      public static final int TEXT_HANDLE_MOVE = 9; -    /** -     * The user unlocked the device -     * @hide -     */ -    public static final int ENTRY_BUMP = 10; +    // REMOVED: ENTRY_BUMP = 10      /**       * The user has moved the dragged object within a droppable area. @@ -230,6 +226,22 @@ public class HapticFeedbackConstants {      public static final int LONG_PRESS_POWER_BUTTON = 10003;      /** +     * A haptic effect to signal the confirmation of a user biometric authentication +     * (e.g. fingerprint reading). +     * This is a private constant to be used only by system apps. +     * @hide +     */ +    public static final int BIOMETRIC_CONFIRM = 10004; + +    /** +     * A haptic effect to signal the rejection of a user biometric authentication attempt +     * (e.g. fingerprint reading). +     * This is a private constant to be used only by system apps. +     * @hide +     */ +    public static final int BIOMETRIC_REJECT = 10005; + +    /**       * Flag for {@link View#performHapticFeedback(int, int)       * View.performHapticFeedback(int, int)}: Ignore the setting in the       * view for whether to perform haptic feedback, do it always. diff --git a/core/java/android/view/ImeBackAnimationController.java b/core/java/android/view/ImeBackAnimationController.java index d14e858d9fa1..665fac18be99 100644 --- a/core/java/android/view/ImeBackAnimationController.java +++ b/core/java/android/view/ImeBackAnimationController.java @@ -28,6 +28,7 @@ import android.annotation.NonNull;  import android.annotation.Nullable;  import android.graphics.Insets;  import android.util.Log; +import android.view.animation.BackGestureInterpolator;  import android.view.animation.Interpolator;  import android.view.animation.PathInterpolator;  import android.window.BackEvent; @@ -44,7 +45,7 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {      private static final int POST_COMMIT_DURATION_MS = 200;      private static final int POST_COMMIT_CANCEL_DURATION_MS = 50;      private static final float PEEK_FRACTION = 0.1f; -    private static final Interpolator STANDARD_DECELERATE = new PathInterpolator(0f, 0f, 0f, 1f); +    private static final Interpolator BACK_GESTURE = new BackGestureInterpolator();      private static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(              0.05f, 0.7f, 0.1f, 1f);      private static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(0.3f, 0f, 1f, 1f); @@ -140,7 +141,7 @@ public class ImeBackAnimationController implements OnBackAnimationCallback {              float hiddenY = mWindowInsetsAnimationController.getHiddenStateInsets().bottom;              float shownY = mWindowInsetsAnimationController.getShownStateInsets().bottom;              float imeHeight = shownY - hiddenY; -            float interpolatedProgress = STANDARD_DECELERATE.getInterpolation(progress); +            float interpolatedProgress = BACK_GESTURE.getInterpolation(progress);              int newY = (int) (imeHeight - interpolatedProgress * (imeHeight * PEEK_FRACTION));              mWindowInsetsAnimationController.setInsetsAndAlpha(Insets.of(0, 0, 0, newY), 1f,                      progress); diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index b52003f437da..1f6cecafd68f 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -22,7 +22,6 @@ import static android.view.InsetsControllerProto.CONTROL;  import static android.view.InsetsControllerProto.STATE;  import static android.view.InsetsSource.ID_IME;  import static android.view.InsetsSource.ID_IME_CAPTION_BAR; -import static android.view.ViewRootImpl.CAPTION_ON_SHELL;  import static android.view.WindowInsets.Type.FIRST;  import static android.view.WindowInsets.Type.LAST;  import static android.view.WindowInsets.Type.all; @@ -685,9 +684,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation                  @Override                  public void onIdNotFoundInState2(int index1, InsetsSource source1) { -                    if (!CAPTION_ON_SHELL && source1.getType() == captionBar()) { -                        return; -                    }                      if (source1.getId() == ID_IME_CAPTION_BAR) {                          return;                      } @@ -848,15 +844,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation      }      public boolean onStateChanged(InsetsState state) { -        boolean stateChanged = false; -        if (!CAPTION_ON_SHELL) { -            stateChanged = !mState.equals(state, true /* excludesCaptionBar */, -                    false /* excludesInvisibleIme */) -                    || captionInsetsUnchanged(); -        } else { -            stateChanged = !mState.equals(state, false /* excludesCaptionBar */, -                    false /* excludesInvisibleIme */); -        } +        boolean stateChanged = !mState.equals(state, false /* excludesCaptionBar */, +                false /* excludesInvisibleIme */);          if (!stateChanged && mLastDispatchedState.equals(state)) {              return false;          } @@ -924,21 +913,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation          }      } -    private boolean captionInsetsUnchanged() { -        if (CAPTION_ON_SHELL) { -            return false; -        } -        final InsetsSource source = mState.peekSource(ID_CAPTION_BAR); -        if (source == null && mCaptionInsetsHeight == 0) { -            return false; -        } -        if (source != null && mCaptionInsetsHeight == source.getFrame().height()) { -            return false; -        } - -        return true; -    } -      /**       * @see InsetsState#calculateInsets(Rect, InsetsState, boolean, int, int, int, int, int,       *      android.util.SparseIntArray) @@ -1889,24 +1863,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation      }      @Override -    public void setCaptionInsetsHeight(int height) { -        // This method is to be removed once the caption is moved to the shell. -        if (CAPTION_ON_SHELL) { -            return; -        } -        if (mCaptionInsetsHeight != height) { -            mCaptionInsetsHeight = height; -            if (mCaptionInsetsHeight != 0) { -                mState.getOrCreateSource(ID_CAPTION_BAR, captionBar()).setFrame( -                        mFrame.left, mFrame.top, mFrame.right, mFrame.top + mCaptionInsetsHeight); -            } else { -                mState.removeSource(ID_CAPTION_BAR); -            } -            mHost.notifyInsetsChanged(); -        } -    } - -    @Override      public void setImeCaptionBarInsetsHeight(int height) {          if (!ENABLE_HIDE_IME_CAPTION_BAR) {              return; diff --git a/core/java/android/view/PendingInsetsController.java b/core/java/android/view/PendingInsetsController.java index 00a58063f078..5f461c56baff 100644 --- a/core/java/android/view/PendingInsetsController.java +++ b/core/java/android/view/PendingInsetsController.java @@ -45,7 +45,6 @@ public class PendingInsetsController implements WindowInsetsController {      private InsetsController mReplayedInsetsController;      private ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners              = new ArrayList<>(); -    private int mCaptionInsetsHeight = 0;      private int mImeCaptionBarInsetsHeight = 0;      private WindowInsetsAnimationControlListener mLoggingListener;      private @InsetsType int mRequestedVisibleTypes = WindowInsets.Type.defaultVisible(); @@ -99,11 +98,6 @@ public class PendingInsetsController implements WindowInsetsController {      }      @Override -    public void setCaptionInsetsHeight(int height) { -        mCaptionInsetsHeight = height; -    } - -    @Override      public void setImeCaptionBarInsetsHeight(int height) {          mImeCaptionBarInsetsHeight = height;      } @@ -187,9 +181,6 @@ public class PendingInsetsController implements WindowInsetsController {              controller.setSystemBarsAppearanceFromResource(                      mAppearanceFromResource, mAppearanceFromResourceMask);          } -        if (mCaptionInsetsHeight != 0) { -            controller.setCaptionInsetsHeight(mCaptionInsetsHeight); -        }          if (mImeCaptionBarInsetsHeight != 0) {              controller.setImeCaptionBarInsetsHeight(mImeCaptionBarInsetsHeight);          } diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index 17d14042e468..7dc151d8f9ee 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -288,7 +288,7 @@ public final class PointerIcon implements Parcelable {          if (bitmap == null) {              throw new IllegalArgumentException("bitmap must not be null");          } -        validateHotSpot(bitmap, hotSpotX, hotSpotY); +        validateHotSpot(bitmap, hotSpotX, hotSpotY, false /* isScaled */);          PointerIcon icon = new PointerIcon(TYPE_CUSTOM);          icon.mBitmap = bitmap; @@ -521,7 +521,9 @@ public final class PointerIcon implements Parcelable {          BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;          final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable); -        validateHotSpot(bitmap, hotSpotX, hotSpotY); +        // The bitmap and hotspot are loaded from the context, which means it is implicitly scaled +        // to the current display density, so treat this as a scaled icon when verifying hotspot. +        validateHotSpot(bitmap, hotSpotX, hotSpotY, true /* isScaled */);          // Set the properties now that we have successfully loaded the icon.          mBitmap = bitmap;          mHotSpotX = hotSpotX; @@ -535,11 +537,16 @@ public final class PointerIcon implements Parcelable {                  + ", hotspotX=" + mHotSpotX + ", hotspotY=" + mHotSpotY + "}";      } -    private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY) { -        if (hotSpotX < 0 || hotSpotX >= bitmap.getWidth()) { +    private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY, +            boolean isScaled) { +        // Be more lenient when checking the hotspot for scaled icons to account for the restriction +        // that bitmaps must have an integer size. +        if (hotSpotX < 0 || (isScaled ? (int) hotSpotX > bitmap.getWidth() +                : hotSpotX >= bitmap.getWidth())) {              throw new IllegalArgumentException("x hotspot lies outside of the bitmap area");          } -        if (hotSpotY < 0 || hotSpotY >= bitmap.getHeight()) { +        if (hotSpotY < 0 || (isScaled ? (int) hotSpotY > bitmap.getHeight() +                : hotSpotY >= bitmap.getHeight())) {              throw new IllegalArgumentException("y hotspot lies outside of the bitmap area");          }      } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index eb7de93b83f3..cacf0d201b06 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -43,6 +43,7 @@ import static android.view.flags.Flags.sensitiveContentAppProtection;  import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly;  import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly;  import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly; +import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly;  import static android.view.flags.Flags.toolkitFrameRateViewEnablingReadOnly;  import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;  import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; @@ -2443,6 +2444,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,              toolkitFrameRateSmallUsesPercentReadOnly();      private static final boolean sToolkitFrameRateViewEnablingReadOnlyFlagValue =              toolkitFrameRateViewEnablingReadOnly(); +    private static boolean sToolkitFrameRateVelocityMappingReadOnlyFlagValue = +            toolkitFrameRateVelocityMappingReadOnly();      // Used to set frame rate compatibility.      @Surface.FrameRateCompatibility int mFrameRateCompatibility = @@ -5739,6 +5742,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,       */      private static final float FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD = 0.07f; +    private static final float MAX_FRAME_RATE = 140; +      private static final int INFREQUENT_UPDATE_INTERVAL_MILLIS = 100;      private static final int INFREQUENT_UPDATE_COUNTS = 2; @@ -20824,12 +20829,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,              return;          } -        // For VRR to vote the preferred frame rate -        if (sToolkitSetFrameRateReadOnlyFlagValue -                && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { -            votePreferredFrameRate(); -        } -          // Reset content capture caches          mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK;          mContentCaptureSessionCached = false; @@ -20932,11 +20931,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,       */      protected void damageInParent() {          if (mParent != null && mAttachInfo != null) { -            // For VRR to vote the preferred frame rate -            if (sToolkitSetFrameRateReadOnlyFlagValue -                    && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { -                votePreferredFrameRate(); -            }              mParent.onDescendantInvalidated(this, this);          }      } @@ -23624,12 +23618,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,              return renderNode;          } -        mPrivateFlags4 = (mPrivateFlags4 & ~PFLAG4_HAS_MOVED) | PFLAG4_HAS_DRAWN; +        // For VRR to vote the preferred frame rate          if (sToolkitSetFrameRateReadOnlyFlagValue                  && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { +            votePreferredFrameRate();              updateInfrequentCount();          } +        mPrivateFlags4 = (mPrivateFlags4 & ~PFLAG4_HAS_MOVED) | PFLAG4_HAS_DRAWN; +          if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0                  || !renderNode.hasDisplayList()                  || (mRecreateDisplayList)) { @@ -23694,6 +23691,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,              mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;              mPrivateFlags &= ~PFLAG_DIRTY_MASK;          } + +        mFrameContentVelocity = -1;          return renderNode;      } @@ -24792,8 +24791,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,          final int privateFlags = mPrivateFlags;          mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; -        mFrameContentVelocity = -1; -          /*           * Draw traversal performs several drawing steps which must be executed           * in the appropriate order: @@ -33888,32 +33885,42 @@ public class View implements Drawable.Callback, KeyEvent.Callback,          return mLastFrameRateCategory;      } -    private void votePreferredFrameRate() { +    /** +     * Used to vote the preferred frame rate and frame rate category to ViewRootImpl +     * +     * @hide +     */ +    protected void votePreferredFrameRate() {          // use toolkitSetFrameRate flag to gate the change          ViewRootImpl viewRootImpl = getViewRootImpl();          int width = mRight - mLeft;          int height = mBottom - mTop; -        float alpha = mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; -        int visibility = mViewFlags & VISIBILITY_MASK; -        if (viewRootImpl != null && (width != 0 && height != 0) -                && alpha != 0 && visibility == View.VISIBLE -        ) { +        if (viewRootImpl != null && (width != 0 && height != 0)) {              if (mAttachInfo.mViewVelocityApi) {                  float velocity = mFrameContentVelocity;                  int mask = PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN; -                if (velocity < 0f && (mPrivateFlags4 & mask) == mask) { +                float frameRate = 0; + +                if (velocity < 0f +                        && (mPrivateFlags4 & mask) == mask +                        && mParent instanceof View +                        && ((View) mParent).mFrameContentVelocity <= 0 +                ) {                      // This current calculation is very simple. If something on the screen moved,                      // then it votes for the highest velocity. If it doesn't move, then return 0.                      velocity = Float.POSITIVE_INFINITY; +                    frameRate = MAX_FRAME_RATE;                  }                  if (velocity > 0f) { -                    float frameRate = convertVelocityToFrameRate(velocity); +                    if (sToolkitFrameRateVelocityMappingReadOnlyFlagValue) { +                        frameRate = convertVelocityToFrameRate(velocity); +                    }                      viewRootImpl.votePreferredFrameRate(frameRate, FRAME_RATE_COMPATIBILITY_GTE);                      return;                  }              } -            if (!willNotDraw()) { +            if (!willNotDraw() && isDirty()) {                  if (sToolkitMetricsForFrameRateDecisionFlagValue) {                      float sizePercentage = width * height / mAttachInfo.mDisplayPixelCount;                      viewRootImpl.recordViewPercentage(sizePercentage); @@ -33962,7 +33969,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,          float density = mAttachInfo.mDensity;          float velocityDps = velocityPps / density;          // Choose a frame rate in increments of 10fps -        return Math.min(140f, 60f + (10f * (float) Math.floor(velocityDps / 300f))); +        return Math.min(MAX_FRAME_RATE, 60f + (10f * (float) Math.floor(velocityDps / 300f)));      }      /** diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index c5a4d677e70e..cd0602cd0e36 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -257,7 +257,6 @@ import com.android.internal.inputmethod.ImeTracing;  import com.android.internal.inputmethod.InputMethodDebug;  import com.android.internal.os.IResultReceiver;  import com.android.internal.os.SomeArgs; -import com.android.internal.policy.DecorView;  import com.android.internal.policy.PhoneFallbackEventHandler;  import com.android.internal.view.BaseSurfaceHolder;  import com.android.internal.view.RootViewSurfaceTaker; @@ -335,13 +334,6 @@ public final class ViewRootImpl implements ViewParent,      private static final boolean USE_ASYNC_PERFORM_HAPTIC_FEEDBACK = true;      /** -     * Whether the caption is drawn by the shell. -     * @hide -     */ -    public static final boolean CAPTION_ON_SHELL = -            SystemProperties.getBoolean("persist.wm.debug.caption_on_shell", true); - -    /**       * Whether the client (system UI) is handling the transient gesture and the corresponding       * animation.       * @hide @@ -3176,22 +3168,6 @@ public final class ViewRootImpl implements ViewParent,          Trace.traceEnd(Trace.TRACE_TAG_VIEW);      } -    private boolean updateCaptionInsets() { -        if (CAPTION_ON_SHELL) { -            return false; -        } -        if (!(mView instanceof DecorView)) return false; -        final int captionInsetsHeight = ((DecorView) mView).getCaptionInsetsHeight(); -        final Rect captionFrame = new Rect(); -        if (captionInsetsHeight != 0) { -            captionFrame.set(mWinFrame.left, mWinFrame.top, mWinFrame.right, -                            mWinFrame.top + captionInsetsHeight); -        } -        if (mAttachInfo.mCaptionInsets.equals(captionFrame)) return false; -        mAttachInfo.mCaptionInsets.set(captionFrame); -        return true; -    } -      private boolean shouldDispatchCutout() {          return mWindowAttributes.layoutInDisplayCutoutMode                          == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS @@ -3645,9 +3621,6 @@ public final class ViewRootImpl implements ViewParent,                      mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars;                      dispatchApplyInsets = true;                  } -                if (updateCaptionInsets()) { -                    dispatchApplyInsets = true; -                }                  if (dispatchApplyInsets || mLastSystemUiVisibility !=                          mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) {                      mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; @@ -4227,6 +4200,7 @@ public final class ViewRootImpl implements ViewParent,                  ? mFrameRateCategoryLowCount - 1 : mFrameRateCategoryLowCount;          mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;          mPreferredFrameRate = -1; +        mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;          mIsFrameRateConflicted = false;      } @@ -12496,6 +12470,7 @@ public final class ViewRootImpl implements ViewParent,      private void setPreferredFrameRateCategory(int preferredFrameRateCategory) {          if (!shouldSetFrameRateCategory()                  || (mFrameRateCompatibility == FRAME_RATE_COMPATIBILITY_GTE +                && mPreferredFrameRate > 0                  && sToolkitFrameRateVelocityMappingReadOnlyFlagValue)) {              return;          } diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java index 1ffffb303e71..19c98a2f12b7 100644 --- a/core/java/android/view/WindowInsetsController.java +++ b/core/java/android/view/WindowInsetsController.java @@ -284,15 +284,6 @@ public interface WindowInsetsController {      @Appearance int getSystemBarsAppearance();      /** -     * Notify the caption insets height change. The information will be used on the client side to, -     * make sure the InsetsState has the correct caption insets. -     * -     * @param height the height of caption bar insets. -     * @hide -     */ -    void setCaptionInsetsHeight(int height); - -    /**       * Sets the insets height for the IME caption bar, which corresponds to the       * "fake" IME navigation bar.       * diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 59cb45019e83..afe5b7e15793 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1565,8 +1565,9 @@ public interface WindowManager extends ViewManager {       *     android:value="true|false"/>       * </activity>       * </pre> +     * +     * @hide       */ -    @FlaggedApi(Flags.FLAG_UNTRUSTED_EMBEDDING_STATE_SHARING)      String PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING =              "android.window.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING"; diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig index eefc72b82c24..334965abd8c9 100644 --- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig +++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig @@ -80,6 +80,16 @@ flag {  }  flag { +    name: "migrate_enable_shortcuts" +    namespace: "accessibility" +    description: "Refactors deprecated code to use AccessibilityManager#enableShortcutsForTargets." +    bug: "332006721" +    metadata { +        purpose: PURPOSE_BUGFIX +    } +} + +flag {      name: "motion_event_observing"      is_exported: true      namespace: "accessibility" diff --git a/core/java/android/view/animation/BackGestureInterpolator.java b/core/java/android/view/animation/BackGestureInterpolator.java new file mode 100644 index 000000000000..c1595db98998 --- /dev/null +++ b/core/java/android/view/animation/BackGestureInterpolator.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.animation; +/** + * Decelerating interpolator with a very slight acceleration phase at the beginning. + * @hide + */ +public class BackGestureInterpolator extends PathInterpolator { +    public BackGestureInterpolator() { +        super(0.1f, 0.1f, 0f, 1f); +    } +} diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index 65984f55ded2..ead8887fda35 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -45,8 +45,10 @@ import android.util.Log;  import android.view.View;  import android.view.WindowManager;  import android.view.accessibility.IAccessibilityManager; +import android.widget.flags.Flags;  import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy; @@ -205,27 +207,41 @@ public class Toast {          INotificationManager service = getService();          String pkg = mContext.getOpPackageName();          TN tn = mTN; -        tn.mNextView = new WeakReference<>(mNextView); +        if (Flags.toastNoWeakref()) { +            tn.mNextView = mNextView; +        } else { +            tn.mNextViewWeakRef = new WeakReference<>(mNextView); +        }          final boolean isUiContext = mContext.isUiContext();          final int displayId = mContext.getDisplayId(); +        boolean wasEnqueued = false;          try {              if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) {                  if (mNextView != null) {                      // It's a custom toast -                    service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); +                    wasEnqueued = service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, +                            displayId);                  } else {                      // It's a text toast                      ITransientNotificationCallback callback =                              new CallbackBinder(mCallbacks, mHandler); -                    service.enqueueTextToast(pkg, mToken, mText, mDuration, isUiContext, displayId, -                            callback); +                    wasEnqueued = service.enqueueTextToast(pkg, mToken, mText, mDuration, +                            isUiContext, displayId, callback);                  }              } else { -                service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, displayId); +                wasEnqueued = service.enqueueToast(pkg, mToken, tn, mDuration, isUiContext, +                        displayId);              }          } catch (RemoteException e) {              // Empty +        } finally { +            if (Flags.toastNoWeakref()) { +                if (!wasEnqueued) { +                    tn.mNextViewWeakRef = null; +                    tn.mNextView = null; +                } +            }          }      } @@ -581,6 +597,16 @@ public class Toast {          }      } +    /** +     * Get the Toast.TN ITransientNotification object +     * @return TN +     * @hide +     */ +    @VisibleForTesting +    public TN getTn() { +        return mTN; +    } +      // =======================================================================================      // All the gunk below is the interaction with the Notification Service, which handles      // the proper ordering of these system-wide. @@ -599,7 +625,11 @@ public class Toast {          return sService;      } -    private static class TN extends ITransientNotification.Stub { +    /** +     * @hide +     */ +    @VisibleForTesting +    public static class TN extends ITransientNotification.Stub {          @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)          private final WindowManager.LayoutParams mParams; @@ -620,7 +650,9 @@ public class Toast {          @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)          View mView;          @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) -        WeakReference<View> mNextView; +        WeakReference<View> mNextViewWeakRef; +        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) +        View mNextView;          int mDuration;          WindowManager mWM; @@ -662,14 +694,22 @@ public class Toast {                              handleHide();                              // Don't do this in handleHide() because it is also invoked by                              // handleShow() -                            mNextView = null; +                            if (Flags.toastNoWeakref()) { +                                mNextView = null; +                            } else { +                                mNextViewWeakRef = null; +                            }                              break;                          }                          case CANCEL: {                              handleHide();                              // Don't do this in handleHide() because it is also invoked by                              // handleShow() -                            mNextView = null; +                            if (Flags.toastNoWeakref()) { +                                mNextView = null; +                            } else { +                                mNextViewWeakRef = null; +                            }                              try {                                  getService().cancelToast(mPackageName, mToken);                              } catch (RemoteException e) { @@ -716,21 +756,43 @@ public class Toast {          }          public void handleShow(IBinder windowToken) { -            if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView -                    + " mNextView=" + mNextView); +            if (Flags.toastNoWeakref()) { +                if (localLOGV) { +                    Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView +                            + " mNextView=" + mNextView); +                } +            } else { +                if (localLOGV) { +                    Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView +                            + " mNextView=" + mNextViewWeakRef); +                } +            }              // If a cancel/hide is pending - no need to show - at this point              // the window token is already invalid and no need to do any work.              if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) {                  return;              } -            if (mNextView != null && mView != mNextView.get()) { -                // remove the old view if necessary -                handleHide(); -                mView = mNextView.get(); -                if (mView != null) { -                    mPresenter.show(mView, mToken, windowToken, mDuration, mGravity, mX, mY, -                            mHorizontalMargin, mVerticalMargin, -                            new CallbackBinder(getCallbacks(), mHandler)); +            if (Flags.toastNoWeakref()) { +                if (mNextView != null && mView != mNextView) { +                    // remove the old view if necessary +                    handleHide(); +                    mView = mNextView; +                    if (mView != null) { +                        mPresenter.show(mView, mToken, windowToken, mDuration, mGravity, mX, mY, +                                mHorizontalMargin, mVerticalMargin, +                                new CallbackBinder(getCallbacks(), mHandler)); +                    } +                } +            } else { +                if (mNextViewWeakRef != null && mView != mNextViewWeakRef.get()) { +                    // remove the old view if necessary +                    handleHide(); +                    mView = mNextViewWeakRef.get(); +                    if (mView != null) { +                        mPresenter.show(mView, mToken, windowToken, mDuration, mGravity, mX, mY, +                                mHorizontalMargin, mVerticalMargin, +                                new CallbackBinder(getCallbacks(), mHandler)); +                    }                  }              }          } @@ -745,6 +807,23 @@ public class Toast {                  mView = null;              }          } + +        /** +         * Get the next view to show for enqueued toasts +         * Custom toast views are deprecated. +         * @see #setView(View) +         * +         * @return next view +         * @hide +         */ +        @VisibleForTesting +        public View getNextView() { +            if (Flags.toastNoWeakref()) { +                return mNextView; +            } else { +                return (mNextViewWeakRef != null) ? mNextViewWeakRef.get() : null; +            } +        }      }      /** diff --git a/core/java/android/widget/flags/notification_widget_flags.aconfig b/core/java/android/widget/flags/notification_widget_flags.aconfig index e60fa157e8e4..515fa55b7b90 100644 --- a/core/java/android/widget/flags/notification_widget_flags.aconfig +++ b/core/java/android/widget/flags/notification_widget_flags.aconfig @@ -25,4 +25,14 @@ flag {    metadata {      purpose: PURPOSE_BUGFIX    } -}
\ No newline at end of file +} + +flag { +  name: "toast_no_weakref" +  namespace: "systemui" +  description: "Do not use WeakReference for custom view Toast" +  bug: "321732224" +  metadata { +    purpose: PURPOSE_BUGFIX +  } +} diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java index 4816f35e6a07..b1cf8340cc25 100644 --- a/core/java/android/window/BackNavigationInfo.java +++ b/core/java/android/window/BackNavigationInfo.java @@ -72,8 +72,17 @@ public final class BackNavigationInfo implements Parcelable {      /**       * Key to access the boolean value passed in {#mOnBackNavigationDone} result bundle       * that represents if back navigation has been triggered. +     * @hide +     */ +    public static final String KEY_NAVIGATION_FINISHED = "NavigationFinished"; + +    /** +     * Key to access the boolean value passed in {#mOnBackNavigationDone} result bundle +     * that represents if back gesture has been triggered. +     * @hide       */ -    public static final String KEY_TRIGGER_BACK = "TriggerBack"; +    public static final String KEY_GESTURE_FINISHED = "GestureFinished"; +      /**       * Defines the type of back destinations a back even can lead to. This is used to define the @@ -192,7 +201,21 @@ public final class BackNavigationInfo implements Parcelable {      public void onBackNavigationFinished(boolean triggerBack) {          if (mOnBackNavigationDone != null) {              Bundle result = new Bundle(); -            result.putBoolean(KEY_TRIGGER_BACK, triggerBack); +            result.putBoolean(KEY_NAVIGATION_FINISHED, triggerBack); +            mOnBackNavigationDone.sendResult(result); +        } +    } + +    /** +     * Callback to be called when the back gesture is finished in order to notify the server that +     * it can ask app to start rendering. +     * @hide +     * @param triggerBack Boolean indicating if back gesture has been triggered. +     */ +    public void onBackGestureFinished(boolean triggerBack) { +        if (mOnBackNavigationDone != null) { +            Bundle result = new Bundle(); +            result.putBoolean(KEY_GESTURE_FINISHED, triggerBack);              mOnBackNavigationDone.sendResult(result);          }      } diff --git a/core/java/android/window/RemoteTransitionStub.java b/core/java/android/window/RemoteTransitionStub.java new file mode 100644 index 000000000000..c9932ab31469 --- /dev/null +++ b/core/java/android/window/RemoteTransitionStub.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import android.os.IBinder; +import android.os.RemoteException; +import android.view.SurfaceControl; + +/** + * Utility base implementation of {@link IRemoteTransition} that users can extend to avoid stubbing. + * + * @hide + */ +public abstract class RemoteTransitionStub extends IRemoteTransition.Stub { +    @Override +    public void mergeAnimation(IBinder transition, TransitionInfo info, +            SurfaceControl.Transaction t, IBinder mergeTarget, +            IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {} + +    @Override +    public void onTransitionConsumed(IBinder transition, boolean aborted) +            throws RemoteException {} +} diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index 5227724e705e..994e73288e93 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -538,6 +538,11 @@ public final class TransitionInfo implements Parcelable {          // If the change has no parent (it is root), then it is independent          if (change.getParent() == null) return true; +        if (change.getLastParent() != null && !change.getLastParent().equals(change.getParent())) { +            // If the change has been reparented, then it's independent. +            return true; +        } +          // non-visibility changes will just be folded into the parent change, so they aren't          // independent either.          if (change.getMode() == TRANSIT_CHANGE) return false; diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 76a34aec7e58..4148e00e6302 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -88,6 +88,19 @@ public final class WindowContainerTransaction implements Parcelable {      }      /** +     * Clear the transaction object. +     * This is equivalent to a new empty {@link WindowContainerTransaction} in content. +     * +     * @hide +     */ +    public void clear() { +        mChanges.clear(); +        mHierarchyOps.clear(); +        mErrorCallbackToken = null; +        mTaskFragmentOrganizer = null; +    } + +    /**       * Resize a container.       */      @NonNull diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java index bcbac9319887..47a4052df95c 100644 --- a/core/java/android/window/WindowOnBackInvokedDispatcher.java +++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java @@ -36,6 +36,8 @@ import android.view.ImeBackAnimationController;  import androidx.annotation.VisibleForTesting; +import com.android.internal.annotations.GuardedBy; +  import java.io.PrintWriter;  import java.lang.ref.WeakReference;  import java.util.ArrayList; @@ -75,14 +77,17 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {      @Nullable      private ImeBackAnimationController mImeBackAnimationController; +    @GuardedBy("mLock")      /** Convenience hashmap to quickly decide if a callback has been added. */      private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>();      /** Holds all callbacks by priorities. */      @VisibleForTesting +    @GuardedBy("mLock")      public final TreeMap<Integer, ArrayList<OnBackInvokedCallback>>              mOnBackInvokedCallbacks = new TreeMap<>();      private Checker mChecker; +    private final Object mLock = new Object();      public WindowOnBackInvokedDispatcher(@NonNull Context context) {          mChecker = new Checker(context); @@ -94,20 +99,24 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {       */      public void attachToWindow(@NonNull IWindowSession windowSession, @NonNull IWindow window,              @Nullable ImeBackAnimationController imeBackAnimationController) { -        mWindowSession = windowSession; -        mWindow = window; -        mImeBackAnimationController = imeBackAnimationController; -        if (!mAllCallbacks.isEmpty()) { -            setTopOnBackInvokedCallback(getTopCallback()); +        synchronized (mLock) { +            mWindowSession = windowSession; +            mWindow = window; +            mImeBackAnimationController = imeBackAnimationController; +            if (!mAllCallbacks.isEmpty()) { +                setTopOnBackInvokedCallback(getTopCallback()); +            }          }      }      /** Detaches the dispatcher instance from its window. */      public void detachFromWindow() { -        clear(); -        mWindow = null; -        mWindowSession = null; -        mImeBackAnimationController = null; +        synchronized (mLock) { +            clear(); +            mWindow = null; +            mWindowSession = null; +            mImeBackAnimationController = null; +        }      }      // TODO: Take an Executor for the callback to run on. @@ -125,65 +134,71 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {       */      public void registerOnBackInvokedCallbackUnchecked(              @NonNull OnBackInvokedCallback callback, @Priority int priority) { -        if (mImeDispatcher != null) { -            mImeDispatcher.registerOnBackInvokedCallback(priority, callback); -            return; -        } -        if (!mOnBackInvokedCallbacks.containsKey(priority)) { -            mOnBackInvokedCallbacks.put(priority, new ArrayList<>()); -        } -        if (callback instanceof ImeOnBackInvokedDispatcher.DefaultImeOnBackAnimationCallback) { -            callback = mImeBackAnimationController; -        } -        ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority); +        synchronized (mLock) { +            if (mImeDispatcher != null) { +                mImeDispatcher.registerOnBackInvokedCallback(priority, callback); +                return; +            } +            if (!mOnBackInvokedCallbacks.containsKey(priority)) { +                mOnBackInvokedCallbacks.put(priority, new ArrayList<>()); +            } +            if (callback instanceof ImeOnBackInvokedDispatcher.DefaultImeOnBackAnimationCallback) { +                callback = mImeBackAnimationController; +            } +            ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority); -        // If callback has already been added, remove it and re-add it. -        if (mAllCallbacks.containsKey(callback)) { -            if (DEBUG) { -                Log.i(TAG, "Callback already added. Removing and re-adding it."); +            // If callback has already been added, remove it and re-add it. +            if (mAllCallbacks.containsKey(callback)) { +                if (DEBUG) { +                    Log.i(TAG, "Callback already added. Removing and re-adding it."); +                } +                Integer prevPriority = mAllCallbacks.get(callback); +                mOnBackInvokedCallbacks.get(prevPriority).remove(callback);              } -            Integer prevPriority = mAllCallbacks.get(callback); -            mOnBackInvokedCallbacks.get(prevPriority).remove(callback); -        } -        OnBackInvokedCallback previousTopCallback = getTopCallback(); -        callbacks.add(callback); -        mAllCallbacks.put(callback, priority); -        if (previousTopCallback == null -                || (previousTopCallback != callback -                        && mAllCallbacks.get(previousTopCallback) <= priority)) { -            setTopOnBackInvokedCallback(callback); +            OnBackInvokedCallback previousTopCallback = getTopCallback(); +            callbacks.add(callback); +            mAllCallbacks.put(callback, priority); +            if (previousTopCallback == null +                    || (previousTopCallback != callback +                    && mAllCallbacks.get(previousTopCallback) <= priority)) { +                setTopOnBackInvokedCallback(callback); +            }          }      }      @Override      public void unregisterOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback) { -        if (mImeDispatcher != null) { -            mImeDispatcher.unregisterOnBackInvokedCallback(callback); -            return; -        } -        if (callback instanceof ImeOnBackInvokedDispatcher.DefaultImeOnBackAnimationCallback) { -            callback = mImeBackAnimationController; -        } -        if (!mAllCallbacks.containsKey(callback)) { -            if (DEBUG) { -                Log.i(TAG, "Callback not found. returning..."); +        synchronized (mLock) { +            if (mImeDispatcher != null) { +                mImeDispatcher.unregisterOnBackInvokedCallback(callback); +                return; +            } +            if (callback instanceof ImeOnBackInvokedDispatcher.DefaultImeOnBackAnimationCallback) { +                callback = mImeBackAnimationController; +            } +            if (!mAllCallbacks.containsKey(callback)) { +                if (DEBUG) { +                    Log.i(TAG, "Callback not found. returning..."); +                } +                return; +            } +            OnBackInvokedCallback previousTopCallback = getTopCallback(); +            Integer priority = mAllCallbacks.get(callback); +            ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority); +            callbacks.remove(callback); +            if (callbacks.isEmpty()) { +                mOnBackInvokedCallbacks.remove(priority); +            } +            mAllCallbacks.remove(callback); +            // Re-populate the top callback to WM if the removed callback was previously the top +            // one. +            if (previousTopCallback == callback) { +                // We should call onBackCancelled() when an active callback is removed from +                // dispatcher. +                sendCancelledIfInProgress(callback); +                setTopOnBackInvokedCallback(getTopCallback());              } -            return; -        } -        OnBackInvokedCallback previousTopCallback = getTopCallback(); -        Integer priority = mAllCallbacks.get(callback); -        ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority); -        callbacks.remove(callback); -        if (callbacks.isEmpty()) { -            mOnBackInvokedCallbacks.remove(priority); -        } -        mAllCallbacks.remove(callback); -        // Re-populate the top callback to WM if the removed callback was previously the top one. -        if (previousTopCallback == callback) { -            // We should call onBackCancelled() when an active callback is removed from dispatcher. -            sendCancelledIfInProgress(callback); -            setTopOnBackInvokedCallback(getTopCallback());          }      } @@ -191,15 +206,21 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {       * Indicates if the dispatcher is actively dispatching to a callback.       */      public boolean isDispatching() { -        return mIsDispatching; +        synchronized (mLock) { +            return mIsDispatching; +        }      }      private void onStartDispatching() { -        mIsDispatching = true; +        synchronized (mLock) { +            mIsDispatching = true; +        }      }      private void onStopDispatching() { -        mIsDispatching = false; +        synchronized (mLock) { +            mIsDispatching = false; +        }      }      private void sendCancelledIfInProgress(@NonNull OnBackInvokedCallback callback) { @@ -223,27 +244,29 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {      /** Clears all registered callbacks on the instance. */      public void clear() { -        if (mImeDispatcher != null) { -            mImeDispatcher.clear(); -            mImeDispatcher = null; -        } -        if (!mAllCallbacks.isEmpty()) { -            OnBackInvokedCallback topCallback = getTopCallback(); -            if (topCallback != null) { -                sendCancelledIfInProgress(topCallback); -            } else { -                // Should not be possible -                Log.e(TAG, "There is no topCallback, even if mAllCallbacks is not empty"); +        synchronized (mLock) { +            if (mImeDispatcher != null) { +                mImeDispatcher.clear(); +                mImeDispatcher = null; +            } +            if (!mAllCallbacks.isEmpty()) { +                OnBackInvokedCallback topCallback = getTopCallback(); +                if (topCallback != null) { +                    sendCancelledIfInProgress(topCallback); +                } else { +                    // Should not be possible +                    Log.e(TAG, "There is no topCallback, even if mAllCallbacks is not empty"); +                } +                // Clear binder references in WM. +                setTopOnBackInvokedCallback(null);              } -            // Clear binder references in WM. -            setTopOnBackInvokedCallback(null); -        } -        // We should also stop running animations since all callbacks have been removed. -        // note: mSpring.skipToEnd(), in ProgressAnimator.reset(), requires the main handler. -        Handler.getMain().post(mProgressAnimator::reset); -        mAllCallbacks.clear(); -        mOnBackInvokedCallbacks.clear(); +            // We should also stop running animations since all callbacks have been removed. +            // note: mSpring.skipToEnd(), in ProgressAnimator.reset(), requires the main handler. +            Handler.getMain().post(mProgressAnimator::reset); +            mAllCallbacks.clear(); +            mOnBackInvokedCallbacks.clear(); +        }      }      private void setTopOnBackInvokedCallback(@Nullable OnBackInvokedCallback callback) { @@ -275,13 +298,15 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {      }      public OnBackInvokedCallback getTopCallback() { -        if (mAllCallbacks.isEmpty()) { -            return null; -        } -        for (Integer priority : mOnBackInvokedCallbacks.descendingKeySet()) { -            ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority); -            if (!callbacks.isEmpty()) { -                return callbacks.get(callbacks.size() - 1); +        synchronized (mLock) { +            if (mAllCallbacks.isEmpty()) { +                return null; +            } +            for (Integer priority : mOnBackInvokedCallbacks.descendingKeySet()) { +                ArrayList<OnBackInvokedCallback> callbacks = mOnBackInvokedCallbacks.get(priority); +                if (!callbacks.isEmpty()) { +                    return callbacks.get(callbacks.size() - 1); +                }              }          }          return null; @@ -315,16 +340,18 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {      public void dump(String prefix, PrintWriter writer) {          String innerPrefix = prefix + "    ";          writer.println(prefix + "WindowOnBackDispatcher:"); -        if (mAllCallbacks.isEmpty()) { -            writer.println(prefix + "<None>"); -            return; -        } +        synchronized (mLock) { +            if (mAllCallbacks.isEmpty()) { +                writer.println(prefix + "<None>"); +                return; +            } -        writer.println(innerPrefix + "Top Callback: " + getTopCallback()); -        writer.println(innerPrefix + "Callbacks: "); -        mAllCallbacks.forEach((callback, priority) -> { -            writer.println(innerPrefix + "  Callback: " + callback + " Priority=" + priority); -        }); +            writer.println(innerPrefix + "Top Callback: " + getTopCallback()); +            writer.println(innerPrefix + "Callbacks: "); +            mAllCallbacks.forEach((callback, priority) -> { +                writer.println(innerPrefix + "  Callback: " + callback + " Priority=" + priority); +            }); +        }      }      static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub { diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java index 4a3aba13fd54..a868d487b82f 100644 --- a/core/java/android/window/WindowTokenClient.java +++ b/core/java/android/window/WindowTokenClient.java @@ -25,6 +25,7 @@ import android.annotation.NonNull;  import android.annotation.Nullable;  import android.app.ActivityThread;  import android.app.ResourcesManager; +import android.app.servertransaction.ClientTransactionListenerController;  import android.content.Context;  import android.content.res.CompatibilityInfo;  import android.content.res.Configuration; @@ -137,12 +138,24 @@ public class WindowTokenClient extends Binder {       *                                 should be dispatched to listeners.       */      @AnyThread -    public void onConfigurationChanged(Configuration newConfig, int newDisplayId, +    public void onConfigurationChanged(@NonNull Configuration newConfig, int newDisplayId,              boolean shouldReportConfigChange) {          final Context context = mContextRef.get();          if (context == null) {              return;          } +        final ClientTransactionListenerController controller = +                ClientTransactionListenerController.getInstance(); +        controller.onContextConfigurationPreChanged(context); +        try { +            onConfigurationChangedInner(context, newConfig, newDisplayId, shouldReportConfigChange); +        } finally { +            controller.onContextConfigurationPostChanged(context); +        } +    } + +    private void onConfigurationChangedInner(@NonNull Context context, +            @NonNull Configuration newConfig, int newDisplayId, boolean shouldReportConfigChange) {          CompatibilityInfo.applyOverrideScaleIfNeeded(newConfig);          final boolean displayChanged;          final boolean shouldUpdateResources; diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java index ddb8ee0df668..06ae11fee847 100644 --- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java +++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java @@ -135,7 +135,7 @@ public class AccessibilityShortcutController {              DialogStatus.SHOWN,      })      /** Denotes the user shortcut type. */ -    @interface DialogStatus { +    public @interface DialogStatus {          int NOT_SHOWN = 0;          int SHOWN  = 1;      } @@ -366,7 +366,7 @@ public class AccessibilityShortcutController {                                  // to the Settings.                                  final ComponentName configDefaultService =                                          ComponentName.unflattenFromString(defaultService); -                                if (Flags.a11yQsShortcut()) { +                                if (Flags.migrateEnableShortcuts()) {                                      am.enableShortcutsForTargets(true, HARDWARE,                                              Set.of(configDefaultService.flattenToString()), userId);                                  } else { @@ -384,7 +384,7 @@ public class AccessibilityShortcutController {                                              mContext,                                              HARDWARE,                                              userId); -                            if (Flags.a11yQsShortcut()) { +                            if (Flags.migrateEnableShortcuts()) {                                  am.enableShortcutsForTargets(                                          false, HARDWARE, targetServices, userId);                              } else { diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java index f0885922e670..66faa318666d 100644 --- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java @@ -117,7 +117,7 @@ public abstract class AccessibilityTarget implements TargetOperations, OnTargetS      @Override      public void onCheckedChanged(boolean isChecked) {          setShortcutEnabled(isChecked); -        if (Flags.a11yQsShortcut()) { +        if (Flags.migrateEnableShortcuts()) {              final AccessibilityManager am =                      getContext().getSystemService(AccessibilityManager.class);              am.enableShortcutsForTargets( diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java index 2a52264515fc..8aba36bec6f5 100644 --- a/core/java/com/android/internal/os/BatteryStatsHistory.java +++ b/core/java/com/android/internal/os/BatteryStatsHistory.java @@ -582,23 +582,6 @@ public class BatteryStatsHistory {       * @param maxHistoryFiles      the largest number of history buffer files to keep       * @param maxHistoryBufferSize the most amount of RAM to used for buffering of history steps       */ -    public BatteryStatsHistory(File systemDir, int maxHistoryFiles, int maxHistoryBufferSize, -            HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, -            MonotonicClock monotonicClock) { -        this(systemDir, maxHistoryFiles, maxHistoryBufferSize, -                stepDetailsCalculator, clock, monotonicClock, new TraceDelegate(), -                new EventLogger()); -    } - -    public BatteryStatsHistory(File systemDir, int maxHistoryFiles, int maxHistoryBufferSize, -            HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, -            MonotonicClock monotonicClock, TraceDelegate tracer, EventLogger eventLogger) { -        this(Parcel.obtain(), systemDir, maxHistoryFiles, maxHistoryBufferSize, -                stepDetailsCalculator, clock, monotonicClock, tracer, eventLogger); -        initHistoryBuffer(); -    } - -    @VisibleForTesting      public BatteryStatsHistory(Parcel historyBuffer, File systemDir,              int maxHistoryFiles, int maxHistoryBufferSize,              HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, @@ -607,12 +590,11 @@ public class BatteryStatsHistory {                  clock, monotonicClock, tracer, eventLogger, null);      } -    private BatteryStatsHistory(Parcel historyBuffer, File systemDir, +    private BatteryStatsHistory(@Nullable Parcel historyBuffer, @Nullable File systemDir,              int maxHistoryFiles, int maxHistoryBufferSize, -            HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, -            MonotonicClock monotonicClock, TraceDelegate tracer, EventLogger eventLogger, -            BatteryStatsHistory writableHistory) { -        mHistoryBuffer = historyBuffer; +            @NonNull HistoryStepDetailsCalculator stepDetailsCalculator, @NonNull Clock clock, +            @NonNull MonotonicClock monotonicClock, @NonNull TraceDelegate tracer, +            @NonNull EventLogger eventLogger, @Nullable BatteryStatsHistory writableHistory) {          mSystemDir = systemDir;          mMaxHistoryBufferSize = maxHistoryBufferSize;          mStepDetailsCalculator = stepDetailsCalculator; @@ -625,9 +607,16 @@ public class BatteryStatsHistory {              mMutable = false;          } +        if (historyBuffer != null) { +            mHistoryBuffer = historyBuffer; +        } else { +            mHistoryBuffer = Parcel.obtain(); +            initHistoryBuffer(); +        } +          if (writableHistory != null) {              mHistoryDir = writableHistory.mHistoryDir; -        } else { +        } else if (systemDir != null) {              mHistoryDir = new BatteryHistoryDirectory(new File(systemDir, HISTORY_DIR),                      monotonicClock, maxHistoryFiles);              mHistoryDir.load(); @@ -636,35 +625,11 @@ public class BatteryStatsHistory {                  activeFile = mHistoryDir.makeBatteryHistoryFile();              }              setActiveFile(activeFile); +        } else { +            mHistoryDir = null;          }      } -    public BatteryStatsHistory(int maxHistoryBufferSize, -            HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, -            MonotonicClock monotonicClock) { -        this(maxHistoryBufferSize, stepDetailsCalculator, clock, monotonicClock, -                new TraceDelegate(), new EventLogger()); -    } - -    @VisibleForTesting -    public BatteryStatsHistory(int maxHistoryBufferSize, -            HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, -            MonotonicClock monotonicClock, TraceDelegate traceDelegate, -            EventLogger eventLogger) { -        mMaxHistoryBufferSize = maxHistoryBufferSize; -        mStepDetailsCalculator = stepDetailsCalculator; -        mTracer = traceDelegate; -        mClock = clock; -        mMonotonicClock = monotonicClock; -        mEventLogger = eventLogger; - -        mHistoryBuffer = Parcel.obtain(); -        mSystemDir = null; -        mHistoryDir = null; -        mWritableHistory = null; -        initHistoryBuffer(); -    } -      /**       * Used when BatteryStatsHistory object is created from deserialization of a BatteryUsageStats       * parcel. diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java index eef6ce7619e8..07fa679a428a 100644 --- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java +++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java @@ -229,6 +229,17 @@ public final class LongArrayMultiStateCounter implements Parcelable {      }      /** +     * Copies time-in-state and timestamps from the supplied counter. +     */ +    public void copyStatesFrom(LongArrayMultiStateCounter counter) { +        if (mStateCount != counter.mStateCount) { +            throw new IllegalArgumentException( +                    "State count is not the same: " + mStateCount + " vs. " + counter.mStateCount); +        } +        native_copyStatesFrom(mNativeObject, counter.mNativeObject); +    } + +    /**       * Sets the new values for the given state.       */      public void setValues(int state, long[] values) { @@ -376,6 +387,10 @@ public final class LongArrayMultiStateCounter implements Parcelable {      private static native void native_setState(long nativeObject, int state, long timestampMs);      @CriticalNative +    private static native void native_copyStatesFrom(long nativeObjectTarget, +            long nativeObjectSource); + +    @CriticalNative      private static native void native_setValues(long nativeObject, int state,              long longArrayContainerNativeObject); diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index ab982f5b67cf..9646ae957720 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -18,6 +18,7 @@ package com.android.internal.os;  import android.annotation.LongDef; +import android.annotation.Nullable;  import android.annotation.StringDef;  import android.annotation.XmlRes;  import android.compat.annotation.UnsupportedAppUsage; @@ -352,19 +353,39 @@ public class PowerProfile {       * WARNING: use only for testing!       */      @VisibleForTesting -    public void forceInitForTesting(Context context, @XmlRes int xmlId) { +    public void initForTesting(XmlPullParser parser) { +        initForTesting(parser, null); +    } + +    /** +     * Reinitialize the PowerProfile with the provided XML, using optional Resources for fallback +     * configuration settings. +     * WARNING: use only for testing! +     */ +    @VisibleForTesting +    public void initForTesting(XmlPullParser parser, @Nullable Resources resources) {          synchronized (sLock) {              sPowerItemMap.clear();              sPowerArrayMap.clear();              sModemPowerProfile.clear(); -            initLocked(context, xmlId); + +            try { +                readPowerValuesFromXml(parser, resources); +            } finally { +                if (parser instanceof XmlResourceParser) { +                    ((XmlResourceParser) parser).close(); +                } +            } +            initLocked();          }      }      @GuardedBy("sLock")      private void initLocked(Context context, @XmlRes int xmlId) {          if (sPowerItemMap.size() == 0 && sPowerArrayMap.size() == 0) { -            readPowerValuesFromXml(context, xmlId); +            final Resources resources = context.getResources(); +            XmlResourceParser parser = resources.getXml(xmlId); +            readPowerValuesFromXml(parser, resources);          }          initLocked();      } @@ -377,9 +398,8 @@ public class PowerProfile {          initModem();      } -    private void readPowerValuesFromXml(Context context, @XmlRes int xmlId) { -        final Resources resources = context.getResources(); -        XmlResourceParser parser = resources.getXml(xmlId); +    private static void readPowerValuesFromXml(XmlPullParser parser, +            @Nullable Resources resources) {          boolean parsingArray = false;          ArrayList<Double> array = new ArrayList<>();          String arrayName = null; @@ -430,9 +450,17 @@ public class PowerProfile {          } catch (IOException e) {              throw new RuntimeException(e);          } finally { -            parser.close(); +            if (parser instanceof XmlResourceParser) { +                ((XmlResourceParser) parser).close(); +            }          } +        if (resources != null) { +            getDefaultValuesFromConfig(resources); +        } +    } + +    private static void getDefaultValuesFromConfig(Resources resources) {          // Now collect other config variables.          int[] configResIds = new int[]{                  com.android.internal.R.integer.config_bluetooth_idle_cur_ma, diff --git a/core/java/com/android/internal/os/PowerStats.java b/core/java/com/android/internal/os/PowerStats.java index 56263fb924ea..7c7c7b8fa51d 100644 --- a/core/java/com/android/internal/os/PowerStats.java +++ b/core/java/com/android/internal/os/PowerStats.java @@ -47,7 +47,7 @@ public final class PowerStats {      private static final BatteryStatsHistory.VarintParceler VARINT_PARCELER =              new BatteryStatsHistory.VarintParceler(); -    private static final byte PARCEL_FORMAT_VERSION = 1; +    private static final byte PARCEL_FORMAT_VERSION = 2;      private static final int PARCEL_FORMAT_VERSION_MASK = 0x000000FF;      private static final int PARCEL_FORMAT_VERSION_SHIFT = @@ -57,7 +57,12 @@ public final class PowerStats {              Integer.numberOfTrailingZeros(STATS_ARRAY_LENGTH_MASK);      public static final int MAX_STATS_ARRAY_LENGTH =              (1 << Integer.bitCount(STATS_ARRAY_LENGTH_MASK)) - 1; -    private static final int UID_STATS_ARRAY_LENGTH_MASK = 0x00FF0000; +    private static final int STATE_STATS_ARRAY_LENGTH_MASK = 0x00FF0000; +    private static final int STATE_STATS_ARRAY_LENGTH_SHIFT = +            Integer.numberOfTrailingZeros(STATE_STATS_ARRAY_LENGTH_MASK); +    public static final int MAX_STATE_STATS_ARRAY_LENGTH = +            (1 << Integer.bitCount(STATE_STATS_ARRAY_LENGTH_MASK)) - 1; +    private static final int UID_STATS_ARRAY_LENGTH_MASK = 0xFF000000;      private static final int UID_STATS_ARRAY_LENGTH_SHIFT =              Integer.numberOfTrailingZeros(UID_STATS_ARRAY_LENGTH_MASK);      public static final int MAX_UID_STATS_ARRAY_LENGTH = @@ -74,6 +79,10 @@ public final class PowerStats {          private static final String XML_ATTR_ID = "id";          private static final String XML_ATTR_NAME = "name";          private static final String XML_ATTR_STATS_ARRAY_LENGTH = "stats-array-length"; +        private static final String XML_TAG_STATE = "state"; +        private static final String XML_ATTR_STATE_KEY = "key"; +        private static final String XML_ATTR_STATE_LABEL = "label"; +        private static final String XML_ATTR_STATE_STATS_ARRAY_LENGTH = "state-stats-array-length";          private static final String XML_ATTR_UID_STATS_ARRAY_LENGTH = "uid-stats-array-length";          private static final String XML_TAG_EXTRAS = "extras"; @@ -85,7 +94,24 @@ public final class PowerStats {          public final int powerComponentId;          public final String name; +        /** +         * Stats for the power component, such as the total usage time. +         */          public final int statsArrayLength; + +        /** +         * Map of device state codes to their corresponding human-readable labels. +         */ +        public final SparseArray<String> stateLabels; + +        /** +         * Stats for a specific state of the power component, e.g. "mobile radio in the 5G mode" +         */ +        public final int stateStatsArrayLength; + +        /** +         * Stats for the usage of this power component by a specific UID (app) +         */          public final int uidStatsArrayLength;          /** @@ -95,17 +121,25 @@ public final class PowerStats {          public final PersistableBundle extras;          public Descriptor(@BatteryConsumer.PowerComponent int powerComponentId, -                int statsArrayLength, int uidStatsArrayLength, @NonNull PersistableBundle extras) { +                int statsArrayLength, @Nullable SparseArray<String> stateLabels, +                int stateStatsArrayLength, int uidStatsArrayLength, +                @NonNull PersistableBundle extras) {              this(powerComponentId, BatteryConsumer.powerComponentIdToString(powerComponentId), -                    statsArrayLength, uidStatsArrayLength, extras); +                    statsArrayLength, stateLabels, stateStatsArrayLength, uidStatsArrayLength, +                    extras);          }          public Descriptor(int customPowerComponentId, String name, int statsArrayLength, +                @Nullable SparseArray<String> stateLabels, int stateStatsArrayLength,                  int uidStatsArrayLength, PersistableBundle extras) {              if (statsArrayLength > MAX_STATS_ARRAY_LENGTH) {                  throw new IllegalArgumentException(                          "statsArrayLength is too high. Max = " + MAX_STATS_ARRAY_LENGTH);              } +            if (stateStatsArrayLength > MAX_STATE_STATS_ARRAY_LENGTH) { +                throw new IllegalArgumentException( +                        "stateStatsArrayLength is too high. Max = " + MAX_STATE_STATS_ARRAY_LENGTH); +            }              if (uidStatsArrayLength > MAX_UID_STATS_ARRAY_LENGTH) {                  throw new IllegalArgumentException(                          "uidStatsArrayLength is too high. Max = " + MAX_UID_STATS_ARRAY_LENGTH); @@ -113,11 +147,25 @@ public final class PowerStats {              this.powerComponentId = customPowerComponentId;              this.name = name;              this.statsArrayLength = statsArrayLength; +            this.stateLabels = stateLabels != null ? stateLabels : new SparseArray<>(); +            this.stateStatsArrayLength = stateStatsArrayLength;              this.uidStatsArrayLength = uidStatsArrayLength;              this.extras = extras;          }          /** +         * Returns the label associated with the give state key, e.g. "5G-high" for the +         * state of Mobile Radio representing the 5G mode and high signal power. +         */ +        public String getStateLabel(int key) { +            String label = stateLabels.get(key); +            if (label != null) { +                return label; +            } +            return name + "-" + Integer.toHexString(key); +        } + +        /**           * Writes the Descriptor into the parcel.           */          public void writeSummaryToParcel(Parcel parcel) { @@ -125,11 +173,18 @@ public final class PowerStats {                               & PARCEL_FORMAT_VERSION_MASK)                              | ((statsArrayLength << STATS_ARRAY_LENGTH_SHIFT)                                 & STATS_ARRAY_LENGTH_MASK) +                            | ((stateStatsArrayLength << STATE_STATS_ARRAY_LENGTH_SHIFT) +                               & STATE_STATS_ARRAY_LENGTH_MASK)                              | ((uidStatsArrayLength << UID_STATS_ARRAY_LENGTH_SHIFT)                                 & UID_STATS_ARRAY_LENGTH_MASK);              parcel.writeInt(firstWord);              parcel.writeInt(powerComponentId);              parcel.writeString(name); +            parcel.writeInt(stateLabels.size()); +            for (int i = 0, size = stateLabels.size(); i < size; i++) { +                parcel.writeInt(stateLabels.keyAt(i)); +                parcel.writeString(stateLabels.valueAt(i)); +            }              extras.writeToParcel(parcel, 0);          } @@ -148,13 +203,22 @@ public final class PowerStats {              }              int statsArrayLength =                      (firstWord & STATS_ARRAY_LENGTH_MASK) >>> STATS_ARRAY_LENGTH_SHIFT; +            int stateStatsArrayLength = +                    (firstWord & STATE_STATS_ARRAY_LENGTH_MASK) >>> STATE_STATS_ARRAY_LENGTH_SHIFT;              int uidStatsArrayLength =                      (firstWord & UID_STATS_ARRAY_LENGTH_MASK) >>> UID_STATS_ARRAY_LENGTH_SHIFT;              int powerComponentId = parcel.readInt();              String name = parcel.readString(); +            int stateLabelCount = parcel.readInt(); +            SparseArray<String> stateLabels = new SparseArray<>(stateLabelCount); +            for (int i = stateLabelCount; i > 0; i--) { +                int key = parcel.readInt(); +                String label = parcel.readString(); +                stateLabels.put(key, label); +            }              PersistableBundle extras = parcel.readPersistableBundle(); -            return new Descriptor(powerComponentId, name, statsArrayLength, uidStatsArrayLength, -                    extras); +            return new Descriptor(powerComponentId, name, statsArrayLength, stateLabels, +                    stateStatsArrayLength, uidStatsArrayLength, extras);          }          @Override @@ -163,11 +227,13 @@ public final class PowerStats {              if (!(o instanceof Descriptor)) return false;              Descriptor that = (Descriptor) o;              return powerComponentId == that.powerComponentId -                   && statsArrayLength == that.statsArrayLength -                   && uidStatsArrayLength == that.uidStatsArrayLength -                   && Objects.equals(name, that.name) -                   && extras.size() == that.extras.size()        // Unparcel the Parcel if not yet -                   && Bundle.kindofEquals(extras, +                    && statsArrayLength == that.statsArrayLength +                    && stateLabels.contentEquals(that.stateLabels) +                    && stateStatsArrayLength == that.stateStatsArrayLength +                    && uidStatsArrayLength == that.uidStatsArrayLength +                    && Objects.equals(name, that.name) +                    && extras.size() == that.extras.size()        // Unparcel the Parcel if not yet +                    && Bundle.kindofEquals(extras,                      that.extras);  // Since the Parcel is now unparceled, do a deep comparison          } @@ -179,7 +245,14 @@ public final class PowerStats {              serializer.attributeInt(null, XML_ATTR_ID, powerComponentId);              serializer.attribute(null, XML_ATTR_NAME, name);              serializer.attributeInt(null, XML_ATTR_STATS_ARRAY_LENGTH, statsArrayLength); +            serializer.attributeInt(null, XML_ATTR_STATE_STATS_ARRAY_LENGTH, stateStatsArrayLength);              serializer.attributeInt(null, XML_ATTR_UID_STATS_ARRAY_LENGTH, uidStatsArrayLength); +            for (int i = stateLabels.size() - 1; i >= 0; i--) { +                serializer.startTag(null, XML_TAG_STATE); +                serializer.attributeInt(null, XML_ATTR_STATE_KEY, stateLabels.keyAt(i)); +                serializer.attribute(null, XML_ATTR_STATE_LABEL, stateLabels.valueAt(i)); +                serializer.endTag(null, XML_TAG_STATE); +            }              try {                  serializer.startTag(null, XML_TAG_EXTRAS);                  extras.saveToXml(serializer); @@ -199,6 +272,8 @@ public final class PowerStats {              int powerComponentId = -1;              String name = null;              int statsArrayLength = 0; +            SparseArray<String> stateLabels = new SparseArray<>(); +            int stateStatsArrayLength = 0;              int uidStatsArrayLength = 0;              PersistableBundle extras = null;              int eventType = parser.getEventType(); @@ -212,9 +287,16 @@ public final class PowerStats {                              name = parser.getAttributeValue(null, XML_ATTR_NAME);                              statsArrayLength = parser.getAttributeInt(null,                                      XML_ATTR_STATS_ARRAY_LENGTH); +                            stateStatsArrayLength = parser.getAttributeInt(null, +                                    XML_ATTR_STATE_STATS_ARRAY_LENGTH);                              uidStatsArrayLength = parser.getAttributeInt(null,                                      XML_ATTR_UID_STATS_ARRAY_LENGTH);                              break; +                        case XML_TAG_STATE: +                            int value = parser.getAttributeInt(null, XML_ATTR_STATE_KEY); +                            String label = parser.getAttributeValue(null, XML_ATTR_STATE_LABEL); +                            stateLabels.put(value, label); +                            break;                          case XML_TAG_EXTRAS:                              extras = PersistableBundle.restoreFromXml(parser);                              break; @@ -225,11 +307,11 @@ public final class PowerStats {              if (powerComponentId == -1) {                  return null;              } else if (powerComponentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) { -                return new Descriptor(powerComponentId, name, statsArrayLength, uidStatsArrayLength, -                        extras); +                return new Descriptor(powerComponentId, name, statsArrayLength, +                        stateLabels, stateStatsArrayLength, uidStatsArrayLength, extras);              } else if (powerComponentId < BatteryConsumer.POWER_COMPONENT_COUNT) { -                return new Descriptor(powerComponentId, statsArrayLength, uidStatsArrayLength, -                        extras); +                return new Descriptor(powerComponentId, statsArrayLength, stateLabels, +                        stateStatsArrayLength, uidStatsArrayLength, extras);              } else {                  Slog.e(TAG, "Unrecognized power component: " + powerComponentId);                  return null; @@ -247,12 +329,14 @@ public final class PowerStats {                  extras.size();  // Unparcel              }              return "PowerStats.Descriptor{" -                   + "powerComponentId=" + powerComponentId -                   + ", name='" + name + '\'' -                   + ", statsArrayLength=" + statsArrayLength -                   + ", uidStatsArrayLength=" + uidStatsArrayLength -                   + ", extras=" + extras -                   + '}'; +                    + "powerComponentId=" + powerComponentId +                    + ", name='" + name + '\'' +                    + ", statsArrayLength=" + statsArrayLength +                    + ", stateStatsArrayLength=" + stateStatsArrayLength +                    + ", stateLabels=" + stateLabels +                    + ", uidStatsArrayLength=" + uidStatsArrayLength +                    + ", extras=" + extras +                    + '}';          }      } @@ -293,6 +377,12 @@ public final class PowerStats {      public long[] stats;      /** +     * Device-wide mode stats, used when the power component can operate in different modes, +     * e.g. RATs such as LTE and 5G. +     */ +    public final SparseArray<long[]> stateStats = new SparseArray<>(); + +    /**       * Per-UID CPU stats.       */      public final SparseArray<long[]> uidStats = new SparseArray<>(); @@ -313,6 +403,15 @@ public final class PowerStats {          parcel.writeInt(descriptor.powerComponentId);          parcel.writeLong(durationMs);          VARINT_PARCELER.writeLongArray(parcel, stats); + +        if (descriptor.stateStatsArrayLength != 0) { +            parcel.writeInt(stateStats.size()); +            for (int i = 0; i < stateStats.size(); i++) { +                parcel.writeInt(stateStats.keyAt(i)); +                VARINT_PARCELER.writeLongArray(parcel, stateStats.valueAt(i)); +            } +        } +          parcel.writeInt(uidStats.size());          for (int i = 0; i < uidStats.size(); i++) {              parcel.writeInt(uidStats.keyAt(i)); @@ -347,6 +446,17 @@ public final class PowerStats {              stats.durationMs = parcel.readLong();              stats.stats = new long[descriptor.statsArrayLength];              VARINT_PARCELER.readLongArray(parcel, stats.stats); + +            if (descriptor.stateStatsArrayLength != 0) { +                int count = parcel.readInt(); +                for (int i = 0; i < count; i++) { +                    int state = parcel.readInt(); +                    long[] stateStats = new long[descriptor.stateStatsArrayLength]; +                    VARINT_PARCELER.readLongArray(parcel, stateStats); +                    stats.stateStats.put(state, stateStats); +                } +            } +              int uidCount = parcel.readInt();              for (int i = 0; i < uidCount; i++) {                  int uid = parcel.readInt(); @@ -376,6 +486,14 @@ public final class PowerStats {          if (stats.length > 0) {              sb.append("=").append(Arrays.toString(stats));          } +        if (descriptor.stateStatsArrayLength != 0) { +            for (int i = 0; i < stateStats.size(); i++) { +                sb.append(" ["); +                sb.append(descriptor.getStateLabel(stateStats.keyAt(i))); +                sb.append("]="); +                sb.append(Arrays.toString(stateStats.valueAt(i))); +            } +        }          for (int i = 0; i < uidStats.size(); i++) {              sb.append(uidPrefix)                      .append(UserHandle.formatUid(uidStats.keyAt(i))) @@ -391,6 +509,18 @@ public final class PowerStats {          pw.println("PowerStats: " + descriptor.name + " (" + descriptor.powerComponentId + ')');          pw.increaseIndent();          pw.print("duration", durationMs).println(); +        if (descriptor.statsArrayLength != 0) { +            pw.print("stats", Arrays.toString(stats)).println(); +        } +        if (descriptor.stateStatsArrayLength != 0) { +            for (int i = 0; i < stateStats.size(); i++) { +                pw.print("state "); +                pw.print(descriptor.getStateLabel(stateStats.keyAt(i))); +                pw.print(": "); +                pw.print(Arrays.toString(stateStats.valueAt(i))); +                pw.println(); +            } +        }          for (int i = 0; i < uidStats.size(); i++) {              pw.print("UID ");              pw.print(uidStats.keyAt(i)); diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java index e12becd87e12..97ce96ec30f6 100644 --- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java @@ -238,6 +238,7 @@ public class ParsingPackageUtils {       */      public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7;      public static final int PARSE_APK_IN_APEX = 1 << 9; +    public static final int PARSE_APEX = 1 << 10;      public static final int PARSE_CHATTY = 1 << 31; @@ -339,6 +340,9 @@ public class ParsingPackageUtils {          if ((flags & PARSE_APK_IN_APEX) != 0) {              liteParseFlags |= PARSE_APK_IN_APEX;          } +        if ((flags & PARSE_APEX) != 0) { +            liteParseFlags |= PARSE_APEX; +        }          final ParseResult<PackageLite> liteResult =                  ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, liteParseFlags);          if (liteResult.isError()) { @@ -530,7 +534,7 @@ public class ParsingPackageUtils {          afterParseBaseApplication(pkg); -        final ParseResult<ParsingPackage> result = validateBaseApkTags(input, pkg); +        final ParseResult<ParsingPackage> result = validateBaseApkTags(input, pkg, flags);          if (result.isError()) {              return result;          } @@ -1012,10 +1016,11 @@ public class ParsingPackageUtils {              }          } -        return validateBaseApkTags(input, pkg); +        return validateBaseApkTags(input, pkg, flags);      } -    private ParseResult<ParsingPackage> validateBaseApkTags(ParseInput input, ParsingPackage pkg) { +    private ParseResult<ParsingPackage> validateBaseApkTags(ParseInput input, ParsingPackage pkg, +            int flags) {          if (!ParsedAttributionUtils.isCombinationValid(pkg.getAttributions())) {              return input.error(                      INSTALL_PARSE_FAILED_BAD_MANIFEST, @@ -1047,6 +1052,16 @@ public class ParsingPackageUtils {              adjustPackageToBeUnresizeableAndUnpipable(pkg);          } +        // An Apex package shouldn't have permission declarations +        final boolean isApex = (flags & PARSE_APEX) != 0; +        if (isApex && !pkg.getPermissions().isEmpty()) { +            return input.error( +                    INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, +                    pkg.getPackageName() +                            + " is an APEX package and shouldn't declare permissions." +            ); +        } +          return input.success(pkg);      } diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java index 684864638e90..c6e8bf75dbcd 100644 --- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java +++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java @@ -56,7 +56,6 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame      // during a configuration change.      private int mLastContentWidth;      private int mLastContentHeight; -    private int mLastCaptionHeight;      private int mLastXOffset;      private int mLastYOffset; @@ -269,7 +268,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame              final boolean firstCall = mLastContentWidth == 0;              // The current content buffer is drawn here.              mLastContentWidth = xSize; -            mLastContentHeight = ySize - mLastCaptionHeight; +            mLastContentHeight = ySize;              mLastXOffset = xOffset;              mLastYOffset = yOffset; @@ -278,12 +277,11 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame                      mLastXOffset,                      mLastYOffset,                      mLastXOffset + mLastContentWidth, -                    mLastYOffset + mLastCaptionHeight + mLastContentHeight); +                    mLastYOffset + mLastContentHeight);              // If this was the first call and redrawLocked got already called prior              // to us, we should re-issue a redrawLocked now. -            return firstCall -                    && (mLastCaptionHeight != 0 || !mDecorView.isShowingCaption()); +            return firstCall;          }      } @@ -303,22 +301,9 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame       */      private void redrawLocked(Rect newBounds, boolean fullscreen) { -        // While a configuration change is taking place the view hierarchy might become -        // inaccessible. For that case we remember the previous metrics to avoid flashes. -        // Note that even when there is no visible caption, the caption child will exist. -        final int captionHeight = mDecorView.getCaptionHeight(); - -        // The caption height will probably never dynamically change while we are resizing. -        // Once set to something other then 0 it should be kept that way. -        if (captionHeight != 0) { -            // Remember the height of the caption. -            mLastCaptionHeight = captionHeight; -        } -          // Make sure that the other thread has already prepared the render draw calls for the          // content. If any size is 0, we have to wait for it to be drawn first. -        if ((mLastCaptionHeight == 0 && mDecorView.isShowingCaption()) || -                mLastContentWidth == 0 || mLastContentHeight == 0) { +        if (mLastContentWidth == 0 || mLastContentHeight == 0) {              return;          } @@ -337,13 +322,13 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame                  ? mUserCaptionBackgroundDrawable : mCaptionBackgroundDrawable;          if (drawable != null) { -            drawable.setBounds(0, 0, left + width, top + mLastCaptionHeight); +            drawable.setBounds(0, 0, left + width, top);              drawable.draw(canvas);          }          // The backdrop: clear everything with the background. Clipping is done elsewhere.          if (mResizingBackgroundDrawable != null) { -            mResizingBackgroundDrawable.setBounds(0, mLastCaptionHeight, left + width, top + height); +            mResizingBackgroundDrawable.setBounds(0, 0, left + width, top + height);              mResizingBackgroundDrawable.draw(canvas);          }          mFrameAndBackdropNode.endRecording(); diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index a65a1bb18303..ab372522fce4 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -26,9 +26,6 @@ import static android.view.View.MeasureSpec.EXACTLY;  import static android.view.View.MeasureSpec.getMode;  import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;  import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; -import static android.view.ViewRootImpl.CAPTION_ON_SHELL; -import static android.view.Window.DECOR_CAPTION_SHADE_DARK; -import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT;  import static android.view.WindowInsetsController.APPEARANCE_FORCE_LIGHT_NAVIGATION_BARS;  import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;  import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; @@ -38,9 +35,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;  import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;  import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;  import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; -import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; -import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;  import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;  import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL; @@ -83,7 +77,6 @@ import android.view.Menu;  import android.view.MenuItem;  import android.view.MotionEvent;  import android.view.PendingInsetsController; -import android.view.ThreadedRenderer;  import android.view.View;  import android.view.ViewGroup;  import android.view.ViewOutlineProvider; @@ -116,7 +109,6 @@ import com.android.internal.view.menu.ContextMenuBuilder;  import com.android.internal.view.menu.MenuHelper;  import com.android.internal.widget.ActionBarContextView;  import com.android.internal.widget.BackgroundFallback; -import com.android.internal.widget.DecorCaptionView;  import com.android.internal.widget.floatingtoolbar.FloatingToolbar;  import java.util.List; @@ -189,8 +181,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind      private final Rect mFrameOffsets = new Rect(); -    private boolean mHasCaption = false; -      private boolean mChanging;      private Drawable mMenuBackground; @@ -247,11 +237,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind      private Rect mTempRect; -    // This is the caption view for the window, containing the caption and window control -    // buttons. The visibility of this decor depends on the workspace and the window type. -    // If the window type does not require such a view, this member might be null. -    private DecorCaptionView mDecorCaptionView; -      private boolean mWindowResizeCallbacksAdded = false;      private Drawable.Callback mLastBackgroundDrawableCb = null;      private BackdropFrameRenderer mBackdropFrameRenderer = null; @@ -524,24 +509,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind      @Override      public boolean onInterceptTouchEvent(MotionEvent event) {          int action = event.getAction(); -        if (mHasCaption && isShowingCaption()) { -            // Don't dispatch ACTION_DOWN to the captionr if the window is resizable and the event -            // was (starting) outside the window. Window resizing events should be handled by -            // WindowManager. -            // TODO: Investigate how to handle the outside touch in window manager -            //       without generating these events. -            //       Currently we receive these because we need to enlarge the window's -            //       touch region so that the monitor channel receives the events -            //       in the outside touch area. -            if (action == MotionEvent.ACTION_DOWN) { -                final int x = (int) event.getX(); -                final int y = (int) event.getY(); -                if (isOutOfInnerBounds(x, y)) { -                    return true; -                } -            } -        } -          if (mFeatureId >= 0) {              if (action == MotionEvent.ACTION_DOWN) {                  int x = (int)event.getX(); @@ -1041,7 +1008,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind      @Override      public void onWindowSystemUiVisibilityChanged(int visible) {          updateColorViews(null /* insets */, true /* animate */); -        updateDecorCaptionStatus(getResources().getConfiguration());          if (mStatusGuard != null && mStatusGuard.getVisibility() == VISIBLE) {              updateStatusGuardColor(); @@ -1214,11 +1180,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind                      mLastTopInset, false /* matchVertical */, statusBarNeedsLeftInset,                      statusBarSideInset, animate && !disallowAnimate,                      mForceWindowDrawsBarBackgrounds, requestedVisibleTypes); - -            if (mHasCaption) { -                mDecorCaptionView.getCaption().setBackgroundColor(statusBarColor); -                updateDecorCaptionShade(); -            }          }          // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS or @@ -1483,7 +1444,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind                  mWindow.getAttributes().flags, force);          boolean show = state.attributes.isVisible(state.present, color,                  mWindow.getAttributes().flags, force); -        boolean showView = show && !isResizing() && !mHasCaption && size > 0; +        boolean showView = show && !isResizing() && size > 0;          boolean visibilityChanged = false;          View view = state.view; @@ -1950,9 +1911,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind      @Override      public void onRootViewScrollYChanged(int rootScrollY) {          mRootScrollY = rootScrollY; -        if (mDecorCaptionView != null) { -            mDecorCaptionView.onRootViewScrollYChanged(rootScrollY); -        }          updateColorViewTranslations();      } @@ -2141,31 +2099,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind              .addOnPreDrawListener(mFloatingToolbarPreDrawListener);      } -    /** -     * Informs the decor if the caption is attached and visible. -     * @param attachedAndVisible true when the decor is visible. -     * Note that this will even be called if there is no caption. -     **/ -    void enableCaption(boolean attachedAndVisible) { -        if (mHasCaption != attachedAndVisible) { -            mHasCaption = attachedAndVisible; -            if (getForeground() != null) { -                drawableChanged(); -            } -            notifyCaptionHeightChanged(); -        } -    } - -    /** -     * An interface to be called when the caption visibility or height changed, to report the -     * corresponding insets change to the InsetsController. -     */ -    public void notifyCaptionHeightChanged() { -        if (!CAPTION_ON_SHELL) { -            getWindowInsetsController().setCaptionInsetsHeight(getCaptionInsetsHeight()); -        } -    } -      void setWindow(PhoneWindow phoneWindow) {          mWindow = phoneWindow;          Context context = getContext(); @@ -2191,8 +2124,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind      protected void onConfigurationChanged(Configuration newConfig) {          super.onConfigurationChanged(newConfig); -        updateDecorCaptionStatus(newConfig); -          initializeElevation();      } @@ -2214,29 +2145,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind                  & View.SYSTEM_UI_FLAG_FULLSCREEN));      } -    private void updateDecorCaptionStatus(Configuration config) { -        final boolean displayWindowDecor = config.windowConfiguration.hasWindowDecorCaption() -                && !isFillingScreen(config); -        if (mDecorCaptionView == null && displayWindowDecor) { -            // Configuration now requires a caption. -            final LayoutInflater inflater = mWindow.getLayoutInflater(); -            mDecorCaptionView = createDecorCaptionView(inflater); -            if (mDecorCaptionView != null) { -                if (mDecorCaptionView.getParent() == null) { -                    addView(mDecorCaptionView, 0, -                            new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); -                } -                removeView(mContentRoot); -                mDecorCaptionView.addView(mContentRoot, -                        new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT)); -            } -        } else if (mDecorCaptionView != null) { -            // We might have to change the kind of surface before we do anything else. -            mDecorCaptionView.onConfigurationChanged(displayWindowDecor); -            enableCaption(displayWindowDecor); -        } -    } -      void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {          if (mBackdropFrameRenderer != null) {              loadBackgroundDrawablesIfNeeded(); @@ -2246,20 +2154,10 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind                      getCurrentColor(mNavigationColorViewState));          } -        mDecorCaptionView = createDecorCaptionView(inflater);          final View root = inflater.inflate(layoutResource, null); -        if (mDecorCaptionView != null) { -            if (mDecorCaptionView.getParent() == null) { -                addView(mDecorCaptionView, -                        new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); -            } -            mDecorCaptionView.addView(root, -                    new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT)); -        } else { -            // Put it below the color views. -            addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); -        } +        // Put it below the color views. +        addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));          mContentRoot = (ViewGroup) root;          initializeElevation();      } @@ -2285,89 +2183,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind          }      } -    // Free floating overlapping windows require a caption. -    private DecorCaptionView createDecorCaptionView(LayoutInflater inflater) { -        DecorCaptionView decorCaptionView = null; -        for (int i = getChildCount() - 1; i >= 0 && decorCaptionView == null; i--) { -            View view = getChildAt(i); -            if (view instanceof DecorCaptionView) { -                // The decor was most likely saved from a relaunch - so reuse it. -                decorCaptionView = (DecorCaptionView) view; -                removeViewAt(i); -            } -        } -        final WindowManager.LayoutParams attrs = mWindow.getAttributes(); -        final boolean isApplication = attrs.type == TYPE_BASE_APPLICATION || -                attrs.type == TYPE_APPLICATION || attrs.type == TYPE_DRAWN_APPLICATION; -        final WindowConfiguration winConfig = getResources().getConfiguration().windowConfiguration; -        // Only a non floating application window on one of the allowed workspaces can get a caption -        if (!mWindow.isFloating() && isApplication && winConfig.hasWindowDecorCaption() -                && !CAPTION_ON_SHELL) { -            // Dependent on the brightness of the used title we either use the -            // dark or the light button frame. -            if (decorCaptionView == null) { -                decorCaptionView = inflateDecorCaptionView(inflater); -            } -            decorCaptionView.setPhoneWindow(mWindow, true /*showDecor*/); -        } else { -            decorCaptionView = null; -        } - -        // Tell the decor if it has a visible caption. -        enableCaption(decorCaptionView != null); -        return decorCaptionView; -    } - -    private DecorCaptionView inflateDecorCaptionView(LayoutInflater inflater) { -        final Context context = getContext(); -        // We make a copy of the inflater, so it has the right context associated with it. -        inflater = inflater.from(context); -        final DecorCaptionView view = (DecorCaptionView) inflater.inflate(R.layout.decor_caption, -                null); -        setDecorCaptionShade(view); -        return view; -    } - -    private void setDecorCaptionShade(DecorCaptionView view) { -        final int shade = mWindow.getDecorCaptionShade(); -        switch (shade) { -            case DECOR_CAPTION_SHADE_LIGHT: -                setLightDecorCaptionShade(view); -                break; -            case DECOR_CAPTION_SHADE_DARK: -                setDarkDecorCaptionShade(view); -                break; -            default: { -                if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0) { -                    setDarkDecorCaptionShade(view); -                } else { -                    setLightDecorCaptionShade(view); -                } -                break; -            } -        } -    } - -    void updateDecorCaptionShade() { -        if (mDecorCaptionView != null) { -            setDecorCaptionShade(mDecorCaptionView); -        } -    } - -    private void setLightDecorCaptionShade(DecorCaptionView view) { -        view.findViewById(R.id.maximize_window).setBackgroundResource( -                R.drawable.decor_maximize_button_light); -        view.findViewById(R.id.close_window).setBackgroundResource( -                R.drawable.decor_close_button_light); -    } - -    private void setDarkDecorCaptionShade(DecorCaptionView view) { -        view.findViewById(R.id.maximize_window).setBackgroundResource( -                R.drawable.decor_maximize_button_dark); -        view.findViewById(R.id.close_window).setBackgroundResource( -                R.drawable.decor_close_button_dark); -    } -      /**       * Returns the color used to fill areas the app has not rendered content to yet when the       * user is resizing the window of an activity in multi-window mode. @@ -2405,17 +2220,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind      }      void clearContentView() { -        if (mDecorCaptionView != null) { -            mDecorCaptionView.removeContentView(); -        } else { -            // This window doesn't have caption, so we need to remove everything except our views -            // we might have added. -            for (int i = getChildCount() - 1; i >= 0; i--) { -                View v = getChildAt(i); -                if (v != mStatusColorViewState.view && v != mNavigationColorViewState.view -                        && v != mStatusGuard) { -                    removeViewAt(i); -                } +        for (int i = getChildCount() - 1; i >= 0; i--) { +            View v = getChildAt(i); +            if (v != mStatusColorViewState.view && v != mNavigationColorViewState.view +                    && v != mStatusGuard) { +                removeViewAt(i);              }          }      } @@ -2439,23 +2248,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind          if (mBackdropFrameRenderer != null) {              return;          } -        final ThreadedRenderer renderer = getThreadedRenderer(); -        if (renderer != null && !CAPTION_ON_SHELL) { -            loadBackgroundDrawablesIfNeeded(); -            WindowInsets rootInsets = getRootWindowInsets(); -            mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer, -                    initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable, -                    mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState), -                    getCurrentColor(mNavigationColorViewState), fullscreen, -                    rootInsets.getInsets(WindowInsets.Type.systemBars())); - -            // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time. -            // If we want to get the shadow shown while resizing, we would need to elevate a new -            // element which owns the caption and has the elevation. -            updateElevation(); - -            updateColorViews(null /* insets */, false); -        }          getViewRootImpl().requestInvalidateRootRenderNode();      } @@ -2576,23 +2368,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind          }      } -    boolean isShowingCaption() { -        return mDecorCaptionView != null && mDecorCaptionView.isCaptionShowing(); -    } - -    int getCaptionHeight() { -        return isShowingCaption() ? mDecorCaptionView.getCaptionHeight() : 0; -    } - -    /** -     * @hide -     * @return the height of insets covering the top of window content area. -     */ -    public int getCaptionInsetsHeight() { -        if (!mWindow.isOverlayWithDecorCaptionEnabled()) return 0; -        return getCaptionHeight(); -    } -      /**       * Converts a DIP measure into physical pixels.       * @param dip The dip value. diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index e6a2a6c375f7..18413530d575 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -363,8 +363,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {      private boolean mIsStartingWindow;      private int mTheme = -1; -    private int mDecorCaptionShade = DECOR_CAPTION_SHADE_AUTO; -      private boolean mUseDecorContext = false;      /** @see ViewRootImpl#mActivityConfigCallback */ @@ -4048,14 +4046,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {      @Override      public void setDecorCaptionShade(int decorCaptionShade) { -        mDecorCaptionShade = decorCaptionShade; -        if (mDecor != null) { -            mDecor.updateDecorCaptionShade(); -        } -    } - -    int getDecorCaptionShade() { -        return mDecorCaptionShade; +        // TODO(b/328668781): Make proper treatment to this public API per the outcome of the bug.      }      @Override diff --git a/core/java/com/android/internal/power/ModemPowerProfile.java b/core/java/com/android/internal/power/ModemPowerProfile.java index b15c10e6ba20..64d3139561b6 100644 --- a/core/java/com/android/internal/power/ModemPowerProfile.java +++ b/core/java/com/android/internal/power/ModemPowerProfile.java @@ -17,14 +17,16 @@  package com.android.internal.power;  import android.annotation.IntDef; -import android.content.res.XmlResourceParser; +import android.os.BatteryStats;  import android.telephony.ModemActivityInfo;  import android.telephony.ServiceState;  import android.telephony.TelephonyManager; +import android.util.Log;  import android.util.Slog;  import android.util.SparseArray;  import android.util.SparseDoubleArray; +import com.android.internal.os.PowerProfile;  import com.android.internal.util.XmlUtils;  import org.xmlpull.v1.XmlPullParser; @@ -95,6 +97,8 @@ public class ModemPowerProfile {       */      public static final int MODEM_DRAIN_TYPE_TX = 0x3000_0000; +    private static final int IGNORE = -1; +      @IntDef(prefix = {"MODEM_DRAIN_TYPE_"}, value = {              MODEM_DRAIN_TYPE_SLEEP,              MODEM_DRAIN_TYPE_IDLE, @@ -256,7 +260,7 @@ public class ModemPowerProfile {      /**       * Generates a ModemPowerProfile object from the <modem /> element of a power_profile.xml       */ -    public void parseFromXml(XmlResourceParser parser) throws IOException, +    public void parseFromXml(XmlPullParser parser) throws IOException,              XmlPullParserException {          final int depth = parser.getDepth();          while (XmlUtils.nextElementWithin(parser, depth)) { @@ -286,7 +290,7 @@ public class ModemPowerProfile {      }      /** Parse the <active /> XML element */ -    private void parseActivePowerConstantsFromXml(XmlResourceParser parser) +    private void parseActivePowerConstantsFromXml(XmlPullParser parser)              throws IOException, XmlPullParserException {          // Parse attributes to get the type of active modem usage the power constants are for.          final int ratType; @@ -339,7 +343,7 @@ public class ModemPowerProfile {          }      } -    private static int getTypeFromAttribute(XmlResourceParser parser, String attr, +    private static int getTypeFromAttribute(XmlPullParser parser, String attr,              SparseArray<String> names) {          final String value = XmlUtils.readStringAttribute(parser, attr);          if (value == null) { @@ -382,6 +386,84 @@ public class ModemPowerProfile {          }      } +    public static long getAverageBatteryDrainKey(@ModemDrainType int drainType, +            @BatteryStats.RadioAccessTechnology int rat, @ServiceState.FrequencyRange int freqRange, +            int txLevel) { +        long key = PowerProfile.SUBSYSTEM_MODEM; + +        // Attach Modem drain type to the key if specified. +        if (drainType != IGNORE) { +            key |= drainType; +        } + +        // Attach RadioAccessTechnology to the key if specified. +        switch (rat) { +            case IGNORE: +                // do nothing +                break; +            case BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER: +                key |= MODEM_RAT_TYPE_DEFAULT; +                break; +            case BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE: +                key |= MODEM_RAT_TYPE_LTE; +                break; +            case BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR: +                key |= MODEM_RAT_TYPE_NR; +                break; +            default: +                Log.w(TAG, "Unexpected RadioAccessTechnology : " + rat); +        } + +        // Attach NR Frequency Range to the key if specified. +        switch (freqRange) { +            case IGNORE: +                // do nothing +                break; +            case ServiceState.FREQUENCY_RANGE_UNKNOWN: +                key |= MODEM_NR_FREQUENCY_RANGE_DEFAULT; +                break; +            case ServiceState.FREQUENCY_RANGE_LOW: +                key |= MODEM_NR_FREQUENCY_RANGE_LOW; +                break; +            case ServiceState.FREQUENCY_RANGE_MID: +                key |= MODEM_NR_FREQUENCY_RANGE_MID; +                break; +            case ServiceState.FREQUENCY_RANGE_HIGH: +                key |= MODEM_NR_FREQUENCY_RANGE_HIGH; +                break; +            case ServiceState.FREQUENCY_RANGE_MMWAVE: +                key |= MODEM_NR_FREQUENCY_RANGE_MMWAVE; +                break; +            default: +                Log.w(TAG, "Unexpected NR frequency range : " + freqRange); +        } + +        // Attach transmission level to the key if specified. +        switch (txLevel) { +            case IGNORE: +                // do nothing +                break; +            case 0: +                key |= MODEM_TX_LEVEL_0; +                break; +            case 1: +                key |= MODEM_TX_LEVEL_1; +                break; +            case 2: +                key |= MODEM_TX_LEVEL_2; +                break; +            case 3: +                key |= MODEM_TX_LEVEL_3; +                break; +            case 4: +                key |= MODEM_TX_LEVEL_4; +                break; +            default: +                Log.w(TAG, "Unexpected transmission level : " + txLevel); +        } +        return key; +    } +      /**       * Returns the average battery drain in milli-amps of the modem for a given drain type.       * Returns {@link Double.NaN} if a suitable value is not found for the given key. @@ -444,6 +526,7 @@ public class ModemPowerProfile {          }          return sb.toString();      } +      private static void appendFieldToString(StringBuilder sb, String fieldName,              SparseArray<String> names, int key) {          sb.append(fieldName); diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index f5b1a47e917e..f931a762871c 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -28,6 +28,7 @@ import android.media.INearbyMediaDevicesProvider;  import android.media.MediaRoute2Info;  import android.os.Bundle;  import android.os.ParcelFileDescriptor; +import android.os.UserHandle;  import android.view.KeyEvent;  import android.service.notification.StatusBarNotification; @@ -384,9 +385,11 @@ oneway interface IStatusBar      /**       * Shows the media output switcher dialog.       * -     * @param packageName of the session for which the output switcher is shown. +     * @param targetPackageName The package name for which to show the output switcher. +     * @param targetUserHandle The UserHandle on which the package for which to show the output +     *     switcher is running.       */ -    void showMediaOutputSwitcher(String packageName); +    void showMediaOutputSwitcher(String targetPackageName, in UserHandle targetUserHandle);      /** Enters desktop mode from the current focused app.      * diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java index cb1abf13c109..bdb33c4b151c 100644 --- a/core/java/com/android/internal/view/menu/ListMenuItemView.java +++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java @@ -16,12 +16,10 @@  package com.android.internal.view.menu; -import android.app.AppGlobals;  import android.content.Context;  import android.content.res.TypedArray;  import android.graphics.Rect;  import android.graphics.drawable.Drawable; -import android.text.TextFlags;  import android.util.AttributeSet;  import android.view.LayoutInflater;  import android.view.View; @@ -61,8 +59,6 @@ public class ListMenuItemView extends LinearLayout      private int mMenuType; -    private boolean mUseNewContextMenu; -      private LayoutInflater mInflater;      private boolean mForceShowIcon; @@ -89,10 +85,6 @@ public class ListMenuItemView extends LinearLayout          a.recycle();          b.recycle(); - -        mUseNewContextMenu = AppGlobals.getIntCoreSetting( -                TextFlags.KEY_ENABLE_NEW_CONTEXT_MENU, -                TextFlags.ENABLE_NEW_CONTEXT_MENU_DEFAULT ? 1 : 0) != 0;      }      public ListMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) { @@ -289,9 +281,7 @@ public class ListMenuItemView extends LinearLayout      private void insertIconView() {          LayoutInflater inflater = getInflater(); -        mIconView = (ImageView) inflater.inflate( -                mUseNewContextMenu ? com.android.internal.R.layout.list_menu_item_fixed_size_icon : -                        com.android.internal.R.layout.list_menu_item_icon, +        mIconView = (ImageView) inflater.inflate(com.android.internal.R.layout.list_menu_item_icon,                  this, false);          addContentView(mIconView, 0);      } diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java index 1979e4fe7a90..36828f2dadca 100644 --- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java +++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java @@ -16,24 +16,26 @@  package com.android.internal.view.menu; +import android.app.AppGlobals;  import android.content.Context;  import android.content.res.Resources;  import android.os.Parcelable; +import android.text.TextFlags;  import android.view.Gravity;  import android.view.KeyEvent;  import android.view.LayoutInflater;  import android.view.View;  import android.view.View.OnAttachStateChangeListener;  import android.view.View.OnKeyListener; -import android.view.ViewTreeObserver.OnGlobalLayoutListener;  import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; +import android.widget.AdapterView.OnItemClickListener;  import android.widget.FrameLayout;  import android.widget.ListView;  import android.widget.MenuPopupWindow;  import android.widget.PopupWindow; -import android.widget.TextView; -import android.widget.AdapterView.OnItemClickListener;  import android.widget.PopupWindow.OnDismissListener; +import android.widget.TextView;  import java.util.Objects; @@ -44,6 +46,8 @@ import java.util.Objects;  final class StandardMenuPopup extends MenuPopup implements OnDismissListener, OnItemClickListener,          MenuPresenter, OnKeyListener {      private static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout; +    private static final int ITEM_LAYOUT_MATERIAL = +            com.android.internal.R.layout.popup_menu_item_layout_material;      private final Context mContext; @@ -53,6 +57,7 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On      private final int mPopupMaxWidth;      private final int mPopupStyleAttr;      private final int mPopupStyleRes; +      // The popup window is final in order to couple its lifecycle to the lifecycle of the      // StandardMenuPopup.      private final MenuPopupWindow mPopup; @@ -114,10 +119,15 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On      public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr,              int popupStyleRes, boolean overflowOnly) {          mContext = Objects.requireNonNull(context); +        boolean useNewContextMenu = AppGlobals.getIntCoreSetting( +                TextFlags.KEY_ENABLE_NEW_CONTEXT_MENU, +                TextFlags.ENABLE_NEW_CONTEXT_MENU_DEFAULT ? 1 : 0) != 0; +          mMenu = menu;          mOverflowOnly = overflowOnly;          final LayoutInflater inflater = LayoutInflater.from(context); -        mAdapter = new MenuAdapter(menu, inflater, mOverflowOnly, ITEM_LAYOUT); +        mAdapter = new MenuAdapter(menu, inflater, mOverflowOnly, +                useNewContextMenu ? ITEM_LAYOUT_MATERIAL : ITEM_LAYOUT);          mPopupStyleAttr = popupStyleAttr;          mPopupStyleRes = popupStyleRes; diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index 9c63d0dd746a..bd654fa0095c 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -1212,6 +1212,10 @@ public class ConversationLayout extends FrameLayout                  }              }          } +        if (android.app.Flags.cleanUpSpansAndNewLines() && conversationText != null) { +            // remove formatting from title. +            conversationText = conversationText.toString(); +        }          if (conversationIcon == null) {              conversationIcon = largeIcon; diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java deleted file mode 100644 index 362fd7b4e937..000000000000 --- a/core/java/com/android/internal/widget/DecorCaptionView.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.widget; - -import android.content.Context; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.view.GestureDetector; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.ViewOutlineProvider; -import android.view.Window; - -import com.android.internal.R; -import com.android.internal.policy.DecorView; -import com.android.internal.policy.PhoneWindow; - -import java.util.ArrayList; - -/** - * This class represents the special screen elements to control a window on freeform - * environment. - * As such this class handles the following things: - * <ul> - * <li>The caption, containing the system buttons like maximize, close and such as well as - * allowing the user to drag the window around.</li> - * </ul> - * After creating the view, the function {@link #setPhoneWindow} needs to be called to make - * the connection to it's owning PhoneWindow. - * Note: At this time the application can change various attributes of the DecorView which - * will break things (in subtle/unexpected ways): - * <ul> - * <li>setOutlineProvider</li> - * <li>setSurfaceFormat</li> - * <li>..</li> - * </ul> - * - * Here describe the behavior of overlaying caption on the content and drawing. - * - * First, no matter where the content View gets added, it will always be the first child and the - * caption will be the second. This way the caption will always be drawn on top of the content when - * overlaying is enabled. - * - * Second, the touch dispatch is customized to handle overlaying. This is what happens when touch - * is dispatched on the caption area while overlaying it on content: - * <ul> - * <li>DecorCaptionView.onInterceptTouchEvent() will try intercepting the touch events if the - * down action is performed on top close or maximize buttons; the reason for that is we want these - * buttons to always work.</li> - * <li>The caption view will try to consume the event to apply the dragging logic.</li> - * <li>If the touch event is not consumed by the caption, the content View will receive the touch - * event</li> - * </ul> - */ -public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, -        GestureDetector.OnGestureListener { -    private PhoneWindow mOwner = null; -    private boolean mShow = false; - -    // True if the window is being dragged. -    private boolean mDragging = false; - -    private boolean mOverlayWithAppContent = false; - -    private View mCaption; -    private View mContent; -    private View mMaximize; -    private View mClose; - -    // Fields for detecting drag events. -    private int mTouchDownX; -    private int mTouchDownY; -    private boolean mCheckForDragging; -    private int mDragSlop; - -    // Fields for detecting and intercepting click events on close/maximize. -    private ArrayList<View> mTouchDispatchList = new ArrayList<>(2); -    // We use the gesture detector to detect clicks on close/maximize buttons and to be consistent -    // with existing click detection. -    private GestureDetector mGestureDetector; -    private final Rect mCloseRect = new Rect(); -    private final Rect mMaximizeRect = new Rect(); -    private View mClickTarget; -    private int mRootScrollY; - -    public DecorCaptionView(Context context) { -        super(context); -        init(context); -    } - -    public DecorCaptionView(Context context, AttributeSet attrs) { -        super(context, attrs); -        init(context); -    } - -    public DecorCaptionView(Context context, AttributeSet attrs, int defStyle) { -        super(context, attrs, defStyle); -        init(context); -    } - -    private void init(Context context) { -        mDragSlop = ViewConfiguration.get(context).getScaledTouchSlop(); -        mGestureDetector = new GestureDetector(context, this); -        setContentDescription(context.getString(R.string.accessibility_freeform_caption, -                context.getPackageManager().getApplicationLabel(context.getApplicationInfo()))); -    } - -    @Override -    protected void onFinishInflate() { -        super.onFinishInflate(); -        mCaption = getChildAt(0); -    } - -    public void setPhoneWindow(PhoneWindow owner, boolean show) { -        mOwner = owner; -        mShow = show; -        mOverlayWithAppContent = owner.isOverlayWithDecorCaptionEnabled(); -        updateCaptionVisibility(); -        // By changing the outline provider to BOUNDS, the window can remove its -        // background without removing the shadow. -        mOwner.getDecorView().setOutlineProvider(ViewOutlineProvider.BOUNDS); -        mMaximize = findViewById(R.id.maximize_window); -        mClose = findViewById(R.id.close_window); -    } - -    @Override -    public boolean onInterceptTouchEvent(MotionEvent ev) { -        // If the user starts touch on the maximize/close buttons, we immediately intercept, so -        // that these buttons are always clickable. -        if (ev.getAction() == MotionEvent.ACTION_DOWN) { -            final int x = (int) ev.getX(); -            final int y = (int) ev.getY(); -            // Only offset y for containment tests because the actual views are already translated. -            if (mMaximizeRect.contains(x, y - mRootScrollY)) { -                mClickTarget = mMaximize; -            } -            if (mCloseRect.contains(x, y - mRootScrollY)) { -                mClickTarget = mClose; -            } -        } -        return mClickTarget != null; -    } - -    @Override -    public boolean onTouchEvent(MotionEvent event) { -        if (mClickTarget != null) { -            mGestureDetector.onTouchEvent(event); -            final int action = event.getAction(); -            if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { -                mClickTarget = null; -            } -            return true; -        } -        return false; -    } - -    @Override -    public boolean onTouch(View v, MotionEvent e) { -        // Note: There are no mixed events. When a new device gets used (e.g. 1. Mouse, 2. touch) -        // the old input device events get cancelled first. So no need to remember the kind of -        // input device we are listening to. -        final int x = (int) e.getX(); -        final int y = (int) e.getY(); -        final boolean fromMouse = e.getToolType(e.getActionIndex()) == MotionEvent.TOOL_TYPE_MOUSE; -        final boolean primaryButton = (e.getButtonState() & MotionEvent.BUTTON_PRIMARY) != 0; -        final int actionMasked = e.getActionMasked(); -        switch (actionMasked) { -            case MotionEvent.ACTION_DOWN: -                if (!mShow) { -                    // When there is no caption we should not react to anything. -                    return false; -                } -                // Checking for a drag action is started if we aren't dragging already and the -                // starting event is either a left mouse button or any other input device. -                if (!fromMouse || primaryButton) { -                    mCheckForDragging = true; -                    mTouchDownX = x; -                    mTouchDownY = y; -                } -                break; - -            case MotionEvent.ACTION_MOVE: -                if (!mDragging && mCheckForDragging && (fromMouse || passedSlop(x, y))) { -                    mCheckForDragging = false; -                    mDragging = true; -                    startMovingTask(e.getRawX(), e.getRawY()); -                    // After the above call the framework will take over the input. -                    // This handler will receive ACTION_CANCEL soon (possible after a few spurious -                    // ACTION_MOVE events which are safe to ignore). -                } -                break; - -            case MotionEvent.ACTION_UP: -            case MotionEvent.ACTION_CANCEL: -                if (!mDragging) { -                    break; -                } -                // Abort the ongoing dragging. -                if (actionMasked == MotionEvent.ACTION_UP) { -                    // If it receives ACTION_UP event, the dragging is already finished and also -                    // the system can not end drag on ACTION_UP event. So request to finish -                    // dragging. -                    finishMovingTask(); -                } -                mDragging = false; -                return !mCheckForDragging; -        } -        return mDragging || mCheckForDragging; -    } - -    @Override -    public boolean shouldDelayChildPressedState() { -        return false; -    } - -    private boolean passedSlop(int x, int y) { -        return Math.abs(x - mTouchDownX) > mDragSlop || Math.abs(y - mTouchDownY) > mDragSlop; -    } - -    /** -     * The phone window configuration has changed and the caption needs to be updated. -     * @param show True if the caption should be shown. -     */ -    public void onConfigurationChanged(boolean show) { -        mShow = show; -        updateCaptionVisibility(); -    } - -    @Override -    public void addView(View child, int index, ViewGroup.LayoutParams params) { -        if (!(params instanceof MarginLayoutParams)) { -            throw new IllegalArgumentException( -                    "params " + params + " must subclass MarginLayoutParams"); -        } -        // Make sure that we never get more then one client area in our view. -        if (index >= 2 || getChildCount() >= 2) { -            throw new IllegalStateException("DecorCaptionView can only handle 1 client view"); -        } -        // To support the overlaying content in the caption, we need to put the content view as the -        // first child to get the right Z-Ordering. -        super.addView(child, 0, params); -        mContent = child; -    } - -    @Override -    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { -        final int captionHeight; -        if (mCaption.getVisibility() != View.GONE) { -            measureChildWithMargins(mCaption, widthMeasureSpec, 0, heightMeasureSpec, 0); -            captionHeight = mCaption.getMeasuredHeight(); -        } else { -            captionHeight = 0; -        } -        if (mContent != null) { -            if (mOverlayWithAppContent) { -                measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0); -            } else { -                measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, -                        captionHeight); -            } -        } - -        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), -                MeasureSpec.getSize(heightMeasureSpec)); -    } - -    @Override -    protected void onLayout(boolean changed, int left, int top, int right, int bottom) { -        final int captionHeight; -        if (mCaption.getVisibility() != View.GONE) { -            mCaption.layout(0, 0, mCaption.getMeasuredWidth(), mCaption.getMeasuredHeight()); -            captionHeight = mCaption.getBottom() - mCaption.getTop(); -            mMaximize.getHitRect(mMaximizeRect); -            mClose.getHitRect(mCloseRect); -        } else { -            captionHeight = 0; -            mMaximizeRect.setEmpty(); -            mCloseRect.setEmpty(); -        } - -        if (mContent != null) { -            if (mOverlayWithAppContent) { -                mContent.layout(0, 0, mContent.getMeasuredWidth(), mContent.getMeasuredHeight()); -            } else { -                mContent.layout(0, captionHeight, mContent.getMeasuredWidth(), -                        captionHeight + mContent.getMeasuredHeight()); -            } -        } - -        ((DecorView) mOwner.getDecorView()).notifyCaptionHeightChanged(); - -        // This assumes that the caption bar is at the top. -        mOwner.notifyRestrictedCaptionAreaCallback(mMaximize.getLeft(), mMaximize.getTop(), -                mClose.getRight(), mClose.getBottom()); -    } - -    /** -     * Updates the visibility of the caption. -     **/ -    private void updateCaptionVisibility() { -        mCaption.setVisibility(mShow ? VISIBLE : GONE); -        mCaption.setOnTouchListener(this); -    } - -    /** -     * Maximize or restore the window by moving it to the maximized or freeform workspace stack. -     **/ -    private void toggleFreeformWindowingMode() { -        Window.WindowControllerCallback callback = mOwner.getWindowControllerCallback(); -        if (callback != null) { -            callback.toggleFreeformWindowingMode(); -        } -    } - -    public boolean isCaptionShowing() { -        return mShow; -    } - -    public int getCaptionHeight() { -        return (mCaption != null) ? mCaption.getHeight() : 0; -    } - -    public void removeContentView() { -        if (mContent != null) { -            removeView(mContent); -            mContent = null; -        } -    } - -    public View getCaption() { -        return mCaption; -    } - -    @Override -    public LayoutParams generateLayoutParams(AttributeSet attrs) { -        return new MarginLayoutParams(getContext(), attrs); -    } - -    @Override -    protected LayoutParams generateDefaultLayoutParams() { -        return new MarginLayoutParams(MarginLayoutParams.MATCH_PARENT, -                MarginLayoutParams.MATCH_PARENT); -    } - -    @Override -    protected LayoutParams generateLayoutParams(LayoutParams p) { -        return new MarginLayoutParams(p); -    } - -    @Override -    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { -        return p instanceof MarginLayoutParams; -    } - -    @Override -    public boolean onDown(MotionEvent e) { -        return false; -    } - -    @Override -    public void onShowPress(MotionEvent e) { - -    } - -    @Override -    public boolean onSingleTapUp(MotionEvent e) { -        if (mClickTarget == mMaximize) { -            toggleFreeformWindowingMode(); -        } else if (mClickTarget == mClose) { -            mOwner.dispatchOnWindowDismissed( -                    true /*finishTask*/, false /*suppressWindowTransition*/); -        } -        return true; -    } - -    @Override -    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { -        return false; -    } - -    @Override -    public void onLongPress(MotionEvent e) { - -    } - -    @Override -    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { -        return false; -    } - -    /** -     * Called when {@link android.view.ViewRootImpl} scrolls for adjustPan. -     */ -    public void onRootViewScrollYChanged(int scrollY) { -        // Offset the caption opposite the root scroll. This keeps the caption at the -        // top of the window during adjustPan. -        if (mCaption != null) { -            mRootScrollY = scrollY; -            mCaption.setTranslationY(scrollY); -        } -    } -} diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java index f8f104943c61..97a2d3beda90 100644 --- a/core/java/com/android/internal/widget/MessagingGroup.java +++ b/core/java/com/android/internal/widget/MessagingGroup.java @@ -21,6 +21,7 @@ import android.annotation.IntDef;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.StyleRes; +import android.app.Flags;  import android.app.Person;  import android.content.Context;  import android.content.res.ColorStateList; @@ -200,6 +201,10 @@ public class MessagingGroup extends NotificationOptimizedLinearLayout implements          if (nameOverride == null) {              nameOverride = sender.getName();          } +        if (Flags.cleanUpSpansAndNewLines() && nameOverride != null) { +            // remove formatting from sender name +            nameOverride = nameOverride.toString(); +        }          mSenderName = nameOverride;          if (mSingleLine && !TextUtils.isEmpty(nameOverride)) {              nameOverride = mContext.getResources().getString( diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 03b57d07c0a7..773823d28d95 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -21,6 +21,7 @@ soong_config_module_type {      config_namespace: "ANDROID",      bool_variables: [          "release_binder_death_recipient_weak_from_jni", +        "release_package_libandroid_runtime_punch_holes",      ],      properties: [          "cflags", @@ -63,6 +64,9 @@ cc_library_shared_for_libandroid_runtime {          release_binder_death_recipient_weak_from_jni: {              cflags: ["-DBINDER_DEATH_RECIPIENT_WEAK_FROM_JNI"],          }, +        release_package_libandroid_runtime_punch_holes: { +            cflags: ["-DENABLE_PUNCH_HOLES"], +        },      },      cpp_std: "gnu++20", @@ -123,6 +127,7 @@ cc_library_shared_for_libandroid_runtime {              srcs: [                  "AndroidRuntime.cpp",                  "com_android_internal_content_F2fsUtils.cpp", +                "com_android_internal_content_FileSystemUtils.cpp",                  "com_android_internal_content_NativeLibraryHelper.cpp",                  "com_google_android_gles_jni_EGLImpl.cpp",                  "com_google_android_gles_jni_GLImpl.cpp", // TODO: .arm diff --git a/core/jni/com_android_internal_content_FileSystemUtils.cpp b/core/jni/com_android_internal_content_FileSystemUtils.cpp new file mode 100644 index 000000000000..4bd2d72a1eb4 --- /dev/null +++ b/core/jni/com_android_internal_content_FileSystemUtils.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "FileSystemUtils" + +#include "com_android_internal_content_FileSystemUtils.h" + +#include <android-base/file.h> +#include <android-base/hex.h> +#include <android-base/unique_fd.h> +#include <elf.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <linux/fs.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <utils/Log.h> + +#include <array> +#include <fstream> +#include <vector> + +using android::base::HexString; +using android::base::ReadFullyAtOffset; + +namespace android { +bool punchHoles(const char *filePath, const uint64_t offset, +                const std::vector<Elf64_Phdr> &programHeaders) { +    struct stat64 beforePunch; +    lstat64(filePath, &beforePunch); +    uint64_t blockSize = beforePunch.st_blksize; +    IF_ALOGD() { +        ALOGD("Total number of LOAD segments %zu", programHeaders.size()); + +        ALOGD("Size before punching holes st_blocks: %" PRIu64 +              ", st_blksize: %ld, st_size: %" PRIu64 "", +              beforePunch.st_blocks, beforePunch.st_blksize, +              static_cast<uint64_t>(beforePunch.st_size)); +    } + +    android::base::unique_fd fd(open(filePath, O_RDWR | O_CLOEXEC)); +    if (!fd.ok()) { +        ALOGE("Can't open file to punch %s", filePath); +        return false; +    } + +    // read in chunks of 64KB +    constexpr uint64_t kChunkSize = 64 * 1024; + +    // malloc is used to gracefully handle oom which might occur during the allocation of buffer. +    // allocating using new or vector here results in oom/exception on failure where as malloc will +    // return nullptr. +    std::unique_ptr<uint8_t, decltype(&free)> buffer(static_cast<uint8_t *>(malloc(kChunkSize)), +                                                     &free); +    if (buffer == nullptr) { +        ALOGE("Failed to allocate read buffer"); +        return false; +    } + +    for (size_t index = 0; programHeaders.size() >= 2 && index < programHeaders.size() - 1; +         index++) { +        // find LOAD segments from program headers, calculate padding and punch holes +        uint64_t punchOffset; +        if (__builtin_add_overflow(programHeaders[index].p_offset, programHeaders[index].p_filesz, +                                   &punchOffset)) { +            ALOGE("Overflow occurred when adding offset and filesize"); +            return false; +        } + +        uint64_t punchLen; +        if (__builtin_sub_overflow(programHeaders[index + 1].p_offset, punchOffset, &punchLen)) { +            ALOGE("Overflow occurred when calculating length"); +            return false; +        } + +        if (punchLen < blockSize) { +            continue; +        } + +        uint64_t punchStartOffset; +        if (__builtin_add_overflow(offset, punchOffset, &punchStartOffset)) { +            ALOGE("Overflow occurred when calculating length"); +            return false; +        } + +        uint64_t position = punchStartOffset; +        uint64_t endPosition; +        if (__builtin_add_overflow(position, punchLen, &endPosition)) { +            ALOGE("Overflow occurred when calculating length"); +            return false; +        } + +        // Read content in kChunkSize and verify it is zero +        while (position <= endPosition) { +            uint64_t uncheckedChunkEnd; +            if (__builtin_add_overflow(position, kChunkSize, &uncheckedChunkEnd)) { +                ALOGE("Overflow occurred when calculating uncheckedChunkEnd"); +                return false; +            } + +            uint64_t readLength; +            if (__builtin_sub_overflow(std::min(uncheckedChunkEnd, endPosition), position, +                                       &readLength)) { +                ALOGE("Overflow occurred when calculating readLength"); +                return false; +            } + +            if (!ReadFullyAtOffset(fd, buffer.get(), readLength, position)) { +                ALOGE("Failed to read content to punch holes"); +                return false; +            } + +            IF_ALOGD() { +                ALOGD("Punching holes for length:%" PRIu64 " content which should be zero: %s", +                      readLength, HexString(buffer.get(), readLength).c_str()); +            } + +            bool isZero = std::all_of(buffer.get(), buffer.get() + readLength, +                                      [](uint8_t i) constexpr { return i == 0; }); +            if (!isZero) { +                ALOGE("Found non zero content while trying to punch hole. Skipping operation"); +                return false; +            } + +            position = uncheckedChunkEnd; +        } + +        // if we have a uncompressed file which is being opened from APK, use the offset to +        // punch native lib inside Apk. +        int result = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, punchStartOffset, +                               punchLen); +        if (result < 0) { +            ALOGE("fallocate failed to punch hole, error:%d", errno); +            return false; +        } +    } + +    IF_ALOGD() { +        struct stat64 afterPunch; +        lstat64(filePath, &afterPunch); +        ALOGD("Size after punching holes st_blocks: %" PRIu64 ", st_blksize: %ld, st_size: %" PRIu64 +              "", +              afterPunch.st_blocks, afterPunch.st_blksize, +              static_cast<uint64_t>(afterPunch.st_size)); +    } + +    return true; +} + +bool punchHolesInElf64(const char *filePath, const uint64_t offset) { +    // Open Elf file +    Elf64_Ehdr ehdr; +    std::ifstream inputStream(filePath, std::ifstream::in); + +    // If this is a zip file, set the offset so that we can read elf file directly +    inputStream.seekg(offset); +    // read executable headers +    inputStream.read((char *)&ehdr, sizeof(ehdr)); +    if (!inputStream.good()) { +        return false; +    } + +    // only consider elf64 for punching holes +    if (ehdr.e_ident[EI_CLASS] != ELFCLASS64) { +        ALOGE("Provided file is not ELF64"); +        return false; +    } + +    // read the program headers from elf file +    uint64_t programHeaderOffset = ehdr.e_phoff; +    uint16_t programHeaderNum = ehdr.e_phnum; + +    IF_ALOGD() { +        ALOGD("Punching holes in file: %s programHeaderOffset: %" PRIu64 " programHeaderNum: %hu", +              filePath, programHeaderOffset, programHeaderNum); +    } + +    // if this is a zip file, also consider elf offset inside a file +    uint64_t phOffset; +    if (__builtin_add_overflow(offset, programHeaderOffset, &phOffset)) { +        ALOGE("Overflow occurred when calculating phOffset"); +        return false; +    } +    inputStream.seekg(phOffset); + +    std::vector<Elf64_Phdr> programHeaders; +    for (int headerIndex = 0; headerIndex < programHeaderNum; headerIndex++) { +        Elf64_Phdr header; +        inputStream.read((char *)&header, sizeof(header)); +        if (!inputStream.good()) { +            return false; +        } + +        if (header.p_type != PT_LOAD) { +            continue; +        } +        programHeaders.push_back(header); +    } + +    return punchHoles(filePath, offset, programHeaders); +} + +}; // namespace android diff --git a/core/jni/com_android_internal_content_FileSystemUtils.h b/core/jni/com_android_internal_content_FileSystemUtils.h new file mode 100644 index 000000000000..a6b145c690d1 --- /dev/null +++ b/core/jni/com_android_internal_content_FileSystemUtils.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <sys/types.h> + +namespace android { + +/* + * This function deallocates space used by zero padding at the end of LOAD segments in given + * uncompressed ELF file. Read ELF headers and find out the offset and sizes of LOAD segments. + * [fallocate(2)](http://man7.org/linux/man-pages/man2/fallocate.2.html) is used to deallocate the + * zero ranges at the end of LOAD segments. If ELF file is present inside of ApK/Zip file, offset to + * the start of the ELF file should be provided. + */ +bool punchHolesInElf64(const char* filePath, uint64_t offset); + +} // namespace android
\ No newline at end of file diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index 149e57a6f5e1..faa83f8017f7 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -36,6 +36,7 @@  #include <memory> +#include "com_android_internal_content_FileSystemUtils.h"  #include "core_jni_helpers.h"  #define RS_BITCODE_SUFFIX ".bc" @@ -169,6 +170,15 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr              return INSTALL_FAILED_INVALID_APK;          } +#ifdef ENABLE_PUNCH_HOLES +        // if library is uncompressed, punch hole in it in place +        if (!punchHolesInElf64(zipFile->getZipFileName(), offset)) { +            ALOGW("Failed to punch uncompressed elf file :%s inside apk : %s at offset: " +                  "%" PRIu64 "", +                  fileName, zipFile->getZipFileName(), offset); +        } +#endif // ENABLE_PUNCH_HOLES +          return INSTALL_SUCCEEDED;      } diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp index 76b05eac82af..b3c41dfe81a1 100644 --- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp +++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp @@ -55,6 +55,14 @@ static void native_setState(jlong nativePtr, jint state, jlong timestamp) {      counter->setState(state, timestamp);  } +static void native_copyStatesFrom(jlong nativePtrTarget, jlong nativePtrSource) { +    battery::LongArrayMultiStateCounter *counterTarget = +            reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtrTarget); +    battery::LongArrayMultiStateCounter *counterSource = +            reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtrSource); +    counterTarget->copyStatesFrom(*counterSource); +} +  static void native_setValues(jlong nativePtr, jint state, jlong longArrayContainerNativePtr) {      battery::LongArrayMultiStateCounter *counter =              reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr); @@ -219,6 +227,8 @@ static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = {          // @CriticalNative          {"native_setState", "(JIJ)V", (void *)native_setState},          // @CriticalNative +        {"native_copyStatesFrom", "(JJ)V", (void *)native_copyStatesFrom}, +        // @CriticalNative          {"native_setValues", "(JIJ)V", (void *)native_setValues},          // @CriticalNative          {"native_updateValues", "(JJJ)V", (void *)native_updateValues}, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f74329903690..c694426a5aa4 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2593,6 +2593,13 @@      <permission android:name="android.permission.VIBRATE_ALWAYS_ON"          android:protectionLevel="signature" /> +    <!-- Allows access to system-only haptic feedback constants. +         <p>Protection level: signature +         @hide +    --> +    <permission android:name="android.permission.VIBRATE_SYSTEM_CONSTANTS" +        android:protectionLevel="signature" /> +      <!-- @SystemApi Allows access to the vibrator state.           <p>Protection level: signature           @hide @@ -3889,6 +3896,13 @@      <permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL"                  android:protectionLevel="internal|role" /> +    <!-- Allows the holder to manage and retrieve max storage limit for admin policies. This +        permission is only grantable on rooted devices. +        @TestAPI +        @hide --> +    <permission android:name="android.permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT" +                android:protectionLevel="internal" /> +      <!-- Allows an application to access EnhancedConfirmationManager.          @SystemApi          @FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled") diff --git a/core/res/res/drawable/pointer_spot_anchor_vector.xml b/core/res/res/drawable/pointer_spot_anchor_vector.xml index 54de2aecb4ce..89990b80bd88 100644 --- a/core/res/res/drawable/pointer_spot_anchor_vector.xml +++ b/core/res/res/drawable/pointer_spot_anchor_vector.xml @@ -22,4 +22,8 @@          <path android:fillColor="#ADC6E7" android:pathData="M12 3c-4.963 0-9 4.038-9 9 0 4.963 4.037 9 9 9s9-4.037 9-9c0-4.962-4.037-9-9-9m0 17c-4.411 0-8-3.589-8-8s3.589-8 8-8 8 3.589 8 8-3.589 8-8 8" />          <path android:fillColor="#ADC6E7" android:pathData="M12 5c-3.859 0-7 3.14-7 7s3.141 7 7 7 7-3.141 7-7-3.141-7-7-7m0 13c-3.309 0-6-2.691-6-6s2.691-6 6-6 6 2.691 6 6-2.691 6-6 6" />      </group> +    <path +        android:pathData="M12 4a8 8 0 1 0 0 16 8 8 0 0 0 0 -16m0 15a7 7 0 1 1 0 -14 7 7 0 0 1 0 14" +        android:fillColor="#99FFFFFF" +        android:fillType="evenOdd"/>  </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_spot_hover_vector.xml b/core/res/res/drawable/pointer_spot_hover_vector.xml index ef596c470480..4bf5fbced36d 100644 --- a/core/res/res/drawable/pointer_spot_hover_vector.xml +++ b/core/res/res/drawable/pointer_spot_hover_vector.xml @@ -22,4 +22,7 @@          <path android:fillColor="#ADC6E7" android:pathData="M12 3c-4.963 0-9 4.038-9 9 0 4.963 4.037 9 9 9s9-4.037 9-9c0-4.962-4.037-9-9-9m0 17c-4.411 0-8-3.589-8-8s3.589-8 8-8 8 3.589 8 8-3.589 8-8 8" />          <path android:fillColor="#ADC6E7" android:pathData="M12 7c-2.757 0-5 2.243-5 5s2.243 5 5 5 5-2.243 5-5-2.243-5-5-5m0 9c-2.206 0-4-1.794-4-4s1.794-4 4-4 4 1.794 4 4-1.794 4-4 4" />      </group> +    <path +        android:pathData="M12 3.998a8.002 8.002 0 1 0 0 16.004 8.002 8.002 0 0 0 0 -16.004m0 13.004a5.002 5.002 0 1 1 0 -10.004 5.002 5.002 0 0 1 0 10.004" +        android:fillColor="#99FFFFFF"/>  </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/pointer_spot_touch_vector.xml b/core/res/res/drawable/pointer_spot_touch_vector.xml index afd2956858fa..a25ffe0da5bd 100644 --- a/core/res/res/drawable/pointer_spot_touch_vector.xml +++ b/core/res/res/drawable/pointer_spot_touch_vector.xml @@ -21,4 +21,7 @@      <path          android:fillColor="#ADC6E7"          android:pathData="M21 12c0-4.963-4.038-9-9-9s-9 4.037-9 9 4.038 9 9 9 9-4.037 9-9m-9 8c-4.411 0-8-3.589-8-8s3.589-8 8-8 8 3.589 8 8-3.589 8-8 8" /> +    <path +        android:pathData="M12 12m-8 0a8 8 0 1 1 16 0a8 8 0 1 1 -16 0" +        android:fillColor="#99FFFFFF"/>  </vector>
\ No newline at end of file diff --git a/core/res/res/layout/list_menu_item_icon.xml b/core/res/res/layout/list_menu_item_icon.xml index a30be6a13db6..d8514608e8dd 100644 --- a/core/res/res/layout/list_menu_item_icon.xml +++ b/core/res/res/layout/list_menu_item_icon.xml @@ -20,7 +20,7 @@      android:layout_height="wrap_content"      android:layout_gravity="center_vertical"      android:layout_marginStart="8dip" -    android:layout_marginEnd="-8dip" +    android:layout_marginEnd="8dip"      android:layout_marginTop="8dip"      android:layout_marginBottom="8dip"      android:scaleType="centerInside" diff --git a/core/res/res/layout/popup_menu_item_layout_material.xml b/core/res/res/layout/popup_menu_item_layout_material.xml new file mode 100644 index 000000000000..e20ead62032c --- /dev/null +++ b/core/res/res/layout/popup_menu_item_layout_material.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + +     Licensed under the Apache License, Version 2.0 (the "License"); +     you may not use this file except in compliance with the License. +     You may obtain a copy of the License at + +          http://www.apache.org/licenses/LICENSE-2.0 + +     Unless required by applicable law or agreed to in writing, software +     distributed under the License is distributed on an "AS IS" BASIS, +     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +     See the License for the specific language governing permissions and +     limitations under the License. + +     Forked from the popup_menu_item_layout.xml for material support. When you edit this file, you +     may also need to update that file. +--> + +<com.android.internal.view.menu.ListMenuItemView xmlns:android="http://schemas.android.com/apk/res/android" +    android:layout_width="match_parent" +    android:layout_height="wrap_content" +    android:minWidth="196dip" +    android:orientation="vertical" > + +    <ImageView +        android:id="@+id/group_divider" +        android:layout_width="match_parent" +        android:layout_height="1dip" +        android:layout_marginTop="4dip" +        android:layout_marginBottom="4dip" +        android:background="@drawable/list_divider_material" /> + +    <LinearLayout +        android:id="@+id/content" +        android:layout_width="match_parent" +        android:layout_height="?attr/dropdownListPreferredItemHeight" +        android:paddingEnd="16dip" +        android:duplicateParentState="true" > + +        <!-- Icon will be inserted here. --> + +        <!-- The title and summary have some gap between them, +        and this 'group' should be centered vertically. --> +        <RelativeLayout +            android:layout_width="0dip" +            android:layout_weight="1" +            android:layout_height="wrap_content" +            android:layout_gravity="center_vertical" +            android:duplicateParentState="true"> + +            <TextView +                android:id="@+id/title" +                android:layout_width="match_parent" +                android:layout_height="wrap_content" +                android:layout_alignParentTop="true" +                android:layout_alignParentStart="true" +                android:textAppearance="?attr/textAppearanceLargePopupMenu" +                android:singleLine="true" +                android:duplicateParentState="true" +                android:ellipsize="marquee" +                android:fadingEdge="horizontal" +                android:textAlignment="viewStart" /> + +            <TextView +                android:id="@+id/shortcut" +                android:layout_width="wrap_content" +                android:layout_height="wrap_content" +                android:layout_below="@id/title" +                android:layout_alignParentStart="true" +                android:textAppearance="?attr/textAppearanceSmallPopupMenu" +                android:singleLine="true" +                android:duplicateParentState="true" +                android:textAlignment="viewStart" /> + +        </RelativeLayout> + +        <ImageView +            android:id="@+id/submenuarrow" +            android:layout_width="wrap_content" +            android:layout_height="wrap_content" +            android:layout_gravity="center" +            android:layout_marginStart="8dp" +            android:scaleType="center" +            android:visibility="gone" /> + +        <!-- Checkbox, and/or radio button will be inserted here. --> + +    </LinearLayout> + +</com.android.internal.view.menu.ListMenuItemView> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 63cd6b941178..08418611d902 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -259,7 +259,7 @@      <string name="global_action_emergency" msgid="1387617624177105088">"Noodgeval"</string>      <string name="global_action_bug_report" msgid="5127867163044170003">"Foutverslag"</string>      <string name="global_action_logout" msgid="6093581310002476511">"Beëindig sessie"</string> -    <string name="global_action_screenshot" msgid="2610053466156478564">"Skermkiekie"</string> +    <string name="global_action_screenshot" msgid="2610053466156478564">"Skermskoot"</string>      <string name="bugreport_title" msgid="8549990811777373050">"Foutverslag"</string>      <string name="bugreport_message" msgid="5212529146119624326">"Dit sal inligting oor die huidige toestand van jou toestel insamel om as \'n e-posboodskap te stuur. Dit sal \'n tydjie neem vandat die foutverslag begin is totdat dit reg is om gestuur te word; wees asseblief geduldig."</string>      <string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Interaktiewe verslag"</string> @@ -1426,7 +1426,7 @@      <string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tik om taal en uitleg te kies"</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">"Wys bo-oor ander programme"</string> +    <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Wys bo-oor ander apps"</string>      <string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> word bo-oor ander programme gewys"</string>      <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> wys bo-oor ander programme"</string>      <string name="alert_windows_notification_message" msgid="6538171456970725333">"As jy nie wil hê dat <xliff:g id="NAME">%s</xliff:g> hierdie kenmerk gebruik nie, tik om instellings oop te maak en skakel dit af."</string> @@ -1929,12 +1929,9 @@      <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Bestuur deur <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Aan"</string>      <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Af"</string> -    <!-- no translation found for zen_mode_trigger_summary_divider_text (7461583466043698862) --> -    <skip /> -    <!-- no translation found for zen_mode_trigger_summary_range_symbol_combination (1804900738798069619) --> -    <skip /> -    <!-- no translation found for zen_mode_trigger_event_calendar_any (2086784607921121803) --> -    <skip /> +    <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string> +    <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>-<xliff:g id="END">%2$s</xliff:g>"</string> +    <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Enige kalender"</string>      <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> demp sekere klanke"</string>      <string name="system_error_wipe_data" msgid="5910572292172208493">"Daar is \'n interne probleem met jou toestel en dit sal dalk onstabiel wees totdat jy \'n fabriekterugstelling doen."</string>      <string name="system_error_manufacturer" msgid="703545241070116315">"Daar is \'n interne probleem met jou toestel. Kontak jou vervaardiger vir besonderhede."</string> @@ -1973,7 +1970,7 @@      <string name="default_notification_channel_label" msgid="3697928973567217330">"Ongekategoriseer"</string>      <string name="importance_from_user" msgid="2782756722448800447">"Jy stel die belangrikheid van hierdie kennisgewings."</string>      <string name="importance_from_person" msgid="4235804979664465383">"Dit is belangrik as gevolg van die mense wat betrokke is."</string> -    <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Gepasmaakte programkennisgewing"</string> +    <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Gepasmaakte appkennisgewing"</string>      <string name="user_creation_account_exists" msgid="2239146360099708035">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep (\'n gebruiker met hierdie rekening bestaan reeds)?"</string>      <string name="user_creation_adding" msgid="7305185499667958364">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep?"</string>      <string name="supervised_user_creation_label" msgid="6884904353827427515">"Voeg gebruiker onder toesig by"</string> @@ -2179,7 +2176,7 @@      <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Kitsinstellings"</string>      <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Kragdialoog"</string>      <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sluitskerm"</string> -    <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skermkiekie"</string> +    <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skermskoot"</string>      <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Kopstuk haak"</string>      <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Toeganklikheidkortpad op skerm"</string>      <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Toeganklikheidkortpadkieser op skerm"</string> @@ -2397,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Toets"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Gemeenskaplik"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Appinhoud is weens sekuriteit van skermdeling verberg"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Outomaties aan satelliet gekoppel"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Jy kan boodskappe stuur en ontvang sonder ’n selfoon- of wi-fi-netwerk"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Maak Boodskappe oop"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 799a7ab95a8d..86df6505ce44 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1894,7 +1894,7 @@      <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g>ን አባዛ"</string>      <string name="private_profile_label_badge" msgid="1712086003787839183">"የግል <xliff:g id="LABEL">%1$s</xliff:g>"</string>      <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"ከመንቀል በፊት ፒን ጠይቅ"</string> -    <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ከመንቀል በፊት የማስከፈቻ ስርዓተ-ጥለት ጠይቅ"</string> +    <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ከመንቀል በፊት የማስከፈቻ ሥርዓተ-ጥለት ጠይቅ"</string>      <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ከመንቀል በፊት የይለፍ ቃል ጠይቅ"</string>      <string name="package_installed_device_owner" msgid="7035926868974878525">"በእርስዎ አስተዳዳሪ ተጭኗል"</string>      <string name="package_updated_device_owner" msgid="7560272363805506941">"በእርስዎ አስተዳዳሪ ተዘምኗል"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"ሙከራ"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"የጋራ"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ለደኅንነት ሲባል የመተግበሪያ ይዘት ከማያ ገጽ ማጋራት ተደብቋል"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"ከሳተላይት ጋር በራስ-ሰር ተገናኝቷል"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"ያለ ሞባይል ወይም የWi-Fi አውታረ መረብ መልዕክቶችን መላክ እና መቀበል ይችላሉ"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"መልዕክቶች ይክፈቱ"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index fad2cd68274d..58ec95ab6c25 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -999,7 +999,7 @@      <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_storage_locked" msgid="634993789186443380">"فتح قفل جميع الميزات والبيانات"</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="1229301273156907613">"لا تتوفر شريحة SIM."</string>      <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"لا تتوفر شريحة SIM في الجهاز اللوحي."</string> @@ -1401,7 +1401,7 @@      <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"تم اكتشاف ملحق صوتي تناظري"</string>      <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"الجهاز الذي تم توصيله بالهاتف غير متوافق معه. انقر للحصول على المزيد من المعلومات."</string>      <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" 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> @@ -1660,7 +1660,7 @@      <string name="media_route_button_content_description" msgid="2299223698196869956">"البث"</string>      <string name="media_route_chooser_title" msgid="6646594924991269208">"الاتصال بجهاز"</string>      <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_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_status_scanning" msgid="8045156315309594482">"البحث عن الشبكات..."</string> @@ -1906,7 +1906,7 @@      <string name="confirm_battery_saver" msgid="5247976246208245754">"حسنًا"</string>      <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد أو إيقاف الأنشطة في الخلفية وبعض التأثيرات المرئية وميزات معيّنة وبعض اتصالات الشبكات."</string>      <string name="battery_saver_description" msgid="8518809702138617167">"يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد أو إيقاف الأنشطة في الخلفية وبعض التأثيرات المرئية وميزات معيّنة وبعض اتصالات الشبكات."</string> -    <string name="data_saver_description" msgid="4995164271550590517">"للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيقات المتاحة لديك الآن استخدام البيانات، ولكن لا يمكنها الإكثار من ذلك. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها."</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>      <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{لمدة دقيقة واحدة (حتى {formattedTime})}zero{لمدة # دقيقة (حتى {formattedTime})}two{لمدة دقيقتين (حتى {formattedTime})}few{لمدة # دقائق (حتى {formattedTime})}many{لمدة # دقيقة (حتى {formattedTime})}other{لمدة # دقيقة (حتى {formattedTime})}}"</string> @@ -2398,8 +2398,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"ملف شخصي تجريبي"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"ملف شخصي مشترك"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"تم إخفاء محتوى التطبيق بعد تفعيل ميزة \"مشاركة الشاشة\" للحفاظ على أمانك"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"تم الاتصال تلقائيًا بالقمر الصناعي"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"يمكنك إرسال الرسائل واستلامها بدون شبكة الجوّال أو شبكة Wi-Fi."</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"فتح تطبيق \"الرسائل\""</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 8b3f8324af20..618c5816fdd5 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -1726,7 +1726,7 @@      <string name="accessibility_service_warning_description" msgid="291674995220940133">"আপোনাক সাধ্য সুবিধাৰ প্ৰয়োজনসমূহৰ জৰিয়তে সহায় কৰা এপ্সমূহৰ বাবে সম্পূর্ণ নিয়ন্ত্ৰণৰ সুবিধাটো সঠিক যদিও অধিকাংশ এপৰ বাবে এয়া সঠিক নহয়।"</string>      <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"চাওক আৰু স্ক্ৰীন নিয়ন্ত্ৰণ কৰক"</string>      <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"ই স্ক্ৰীনত থকা আটাইখিনি সমল পঢ়িব পাৰে আৰু অন্য এপ্সমূহৰ ওপৰত সমল প্ৰদর্শন কৰিব পাৰে।"</string> -    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"কার্যসমূহ চাওক আৰু কৰক"</string> +    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"কার্যসমূহ চোৱা আৰু কৰা"</string>      <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"ই আপুনি কোনো এপ্ বা হার্ডৱেৰ ছেন্সৰৰ সৈতে কৰা ভাব-বিনিময় আৰু আপোনাৰ হৈ অন্য কোনো লোকে এপৰ সৈতে কৰা ভাব-বিনিময় ট্ৰেক কৰিব পাৰে।"</string>      <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"অনুমতি দিয়ক"</string>      <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"অস্বীকাৰ কৰক"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"পৰীক্ষা"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"শ্বেয়াৰ কৰা"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"সুৰক্ষাৰ বাবে এপৰ সমল স্ক্ৰীণ শ্বেয়াৰ কৰাৰ পৰা লুকুৱাই ৰখা হৈছে"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"উপগ্ৰহৰ সৈতে স্বয়ংক্ৰিয়ভাৱে সংযুক্ত হৈছে"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"আপুনি ম’বাইল বা ৱাই-ফাই নেটৱৰ্কৰ জৰিয়তে পাঠ বাৰ্তা পঠিয়াব বা লাভ কৰিব পাৰে"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages খোলক"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index c0b886be2097..643c5cbc6eb9 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Kommunal"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Güvənlik üçün tətbiq kontenti ekran paylaşımından gizlədildi"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Peykə avtomatik qoşulub"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Mobil və ya Wi-Fi şəbəkəsi olmadan mesaj göndərə və qəbul edə bilərsiniz"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Mesajı açın"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index a275cab86042..06b6a13a184d 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1223,7 +1223,7 @@      <string name="whichEditApplicationLabel" msgid="1463288652070140285">"Izmeni"</string>      <string name="whichSendApplication" msgid="4143847974460792029">"Delite"</string>      <string name="whichSendApplicationNamed" msgid="4470386782693183461">"Delite pomoću aplikacije %1$s"</string> -    <string name="whichSendApplicationLabel" msgid="7467813004769188515">"Deli"</string> +    <string name="whichSendApplicationLabel" msgid="7467813004769188515">"Deljenje"</string>      <string name="whichSendToApplication" msgid="77101541959464018">"Pošaljite pomoću:"</string>      <string name="whichSendToApplicationNamed" msgid="3385686512014670003">"Pošaljite pomoću: %1$s"</string>      <string name="whichSendToApplicationLabel" msgid="3543240188816513303">"Pošalji"</string> @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Zajedničko"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je skriven za deljenje sadržaja ekrana zbog bezbednosti"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automatski povezano sa satelitom"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Možete da šaljete i primate poruke bez mobilne ili WiFi mreže"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvori Messages"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index c0d930f2173a..43c73d146756 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -2396,8 +2396,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Тэставы"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Супольны"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Змесціва праграмы выключана з абагульвання экрана ў мэтах бяспекі"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Аўтаматычна падключана да сістэм спадарожнікавай сувязі"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Вы можаце адпраўляць і атрымліваць паведамленні без доступу да мабільнай сеткі або Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Адкрыць Паведамленні"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 5c793e582cb1..181e6129acff 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Тестване"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Общи"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Съдържанието на приложението е скрито от функцията за споделяне на екрана от съображения за сигурност"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Автоматично установена връзка със сателит"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Можете да изпращате и получавате съобщения без мобилна или Wi-Fi мрежа"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Отваряне на Messages"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 894660759c67..958346192a00 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -1743,7 +1743,7 @@      <string name="color_inversion_feature_name" msgid="2672824491933264951">"কালার ইনভার্সন"</string>      <string name="color_correction_feature_name" msgid="7975133554160979214">"রঙ সংশোধন করা"</string>      <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"এক হাতে ব্যবহার করার মোড"</string> -    <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"অতিরিক্ত কম ব্রাইটনেস"</string> +    <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"অতিরিক্ত কম উজ্জ্বলতা"</string>      <string name="hearing_aids_feature_name" msgid="1125892105105852542">"হিয়ারিং ডিভাইস"</string>      <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> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"পরীক্ষা"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"কমিউনাল"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"নিরাপত্তার জন্য স্ক্রিন শেয়ার করা থেকে লুকানো অ্যাপের কন্টেন্ট"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"স্যাটেলাইটের সাথে অটোমেটিক কানেক্ট করা হয়েছে"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"আপনি কোনও মেবাইল বা ওয়াই-ফাই নেটওয়ার্ক ছাড়াই মেসেজ পাঠাতে ও পেতে পারবেন"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages খুলুন"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 2d08a22dbc06..170f84e1b3bd 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Testno"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Opće"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je sakriven od dijeljenja ekrana radi sigurnosti"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automatski je povezano sa satelitom"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Možete slati i primati poruke bez mobilne ili WiFi mreže"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvorite Messages"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 263d12982dd1..ae4fbcf52d51 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -842,10 +842,10 @@      <string name="policylab_forceLock" msgid="7360335502968476434">"Bloquejar la pantalla"</string>      <string name="policydesc_forceLock" msgid="1008844760853899693">"Controla com i quan es bloqueja la pantalla."</string>      <string name="policylab_wipeData" msgid="1359485247727537311">"Esborrar totes les dades"</string> -    <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Esborra les dades de la tauleta sense avisar, i restableix les dades de fàbrica."</string> +    <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Esborra les dades de la tauleta sense avisar mitjançant el restabliment de les dades de fàbrica."</string>      <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Suprimeix les dades del dispositiu Android TV sense previ avís mitjançant el restabliment de les dades de fàbrica."</string>      <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"Esborra les dades del sistema d\'informació i entreteniment sense avisar mitjançant el restabliment de les dades de fàbrica."</string> -    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Esborra les dades del telèfon sense avisar, i restableix les dades de fàbrica."</string> +    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Esborra les dades del telèfon sense avisar mitjançant el restabliment de les dades de fàbrica."</string>      <string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"Esborra les dades del perfil"</string>      <string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"Esborrar les dades de l\'usuari"</string>      <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Esborra les dades de l\'usuari desades a la tauleta sense avisar-ne."</string> @@ -996,7 +996,7 @@      <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcte!"</string>      <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Torna-ho a provar"</string>      <string name="lockscreen_password_wrong" msgid="8605355913868947490">"Torna-ho a provar"</string> -    <string name="lockscreen_storage_locked" msgid="634993789186443380">"Desbl. per accedir a totes les funcions i dades"</string> +    <string name="lockscreen_storage_locked" msgid="634993789186443380">"Desbloqueja per accedir a les funcions i dades"</string>      <string name="faceunlock_multiple_failures" msgid="681991538434031708">"S\'ha superat el nombre màxim d\'intents de Desbloqueig facial"</string>      <string name="lockscreen_missing_sim_message_short" msgid="1229301273156907613">"No hi ha cap SIM"</string>      <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"No hi ha cap SIM a la tauleta."</string> @@ -2032,7 +2032,7 @@      <string name="pin_specific_target" msgid="7824671240625957415">"Fixa <xliff:g id="LABEL">%1$s</xliff:g>"</string>      <string name="unpin_target" msgid="3963318576590204447">"No fixis"</string>      <string name="unpin_specific_target" msgid="3859828252160908146">"No fixis <xliff:g id="LABEL">%1$s</xliff:g>"</string> -    <string name="app_info" msgid="6113278084877079851">"Informació de l\'aplicació"</string> +    <string name="app_info" msgid="6113278084877079851">"Informació de l\'app"</string>      <string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>      <string name="demo_starting_message" msgid="6577581216125805905">"S\'està iniciant la demostració…"</string>      <string name="demo_restarting_message" msgid="1160053183701746766">"S\'està restablint el dispositiu…"</string> @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Prova"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Compartit"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contingut de l\'aplicació amagat de la compartició de pantalla per motius de seguretat"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"S\'ha connectat automàticament a un satèl·lit"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Pots enviar i rebre missatges sense una xarxa mòbil o Wi‑Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Obre Missatges"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index a8ad54362866..4318608f40e7 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -833,16 +833,16 @@      <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Sledovat počet nesprávných hesel zadaných při odemykání obrazovky a uzamknout tablet nebo vymazat z tabletu všechna data, pokud bylo zadáno příliš mnoho nesprávných hesel."</string>      <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Sledovat počet nesprávných hesel zadaných při odemykání obrazovky, a pokud jich bude zadáno příliš mnoho, uzamknout zařízení Android TV nebo z něj vymazat všechna data."</string>      <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Monitorovat počet nesprávných hesel zadaných při odemykání obrazovky a uzamknout informační a zábavní systém nebo vymazat veškerá data v informačním a zábavním systému, pokud je zadáno příliš mnoho nesprávných hesel."</string> -    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Sledovat počet nesprávných hesel zadaných při odemykání obrazovky a uzamknout telefon nebo vymazat z telefonu všechna data, pokud bylo zadáno příliš mnoho nesprávných hesel."</string> +    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Sleduje počet nesprávných hesel zadaných při odemykání obrazovky a uzamkne telefon nebo vymaže z telefonu všechna data, pokud bylo zadáno příliš mnoho nesprávných hesel."</string>      <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Monitorovat počet nesprávných hesel zadaných při odemykání obrazovky, a pokud je zadáno příliš mnoho nesprávných hesel, uzamknout tablet nebo vymazat veškerá data uživatele."</string>      <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Sledovat počet nesprávných hesel zadaných při odemykání obrazovky, a pokud jich bude zadáno příliš mnoho, uzamknout zařízení Android TV nebo z něj vymazat všechna data tohoto uživatele."</string>      <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Monitorovat počet nesprávných hesel zadaných při odemykání obrazovky, a pokud je zadáno příliš mnoho nesprávných hesel, uzamknout informační a zábavní systém nebo vymazat veškerá data profilu."</string> -    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Monitorovat počet nesprávných hesel zadaných při odemykání obrazovky, a pokud je zadáno příliš mnoho nesprávných hesel, uzamknout telefon nebo vymazat veškerá data uživatele."</string> +    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Monitoruje počet nesprávných hesel zadaných při odemykání obrazovky, a pokud je zadáno příliš mnoho nesprávných hesel, uzamkne telefon nebo vymaže veškerá data uživatele."</string>      <string name="policylab_resetPassword" msgid="214556238645096520">"Změnit zámek obrazovky"</string>      <string name="policydesc_resetPassword" msgid="4626419138439341851">"Změní se zámek obrazovky."</string>      <string name="policylab_forceLock" msgid="7360335502968476434">"Uzamknout obrazovku"</string>      <string name="policydesc_forceLock" msgid="1008844760853899693">"Určíte, jak a kdy se obrazovka uzamkne."</string> -    <string name="policylab_wipeData" msgid="1359485247727537311">"Vymazat všechna data"</string> +    <string name="policylab_wipeData" msgid="1359485247727537311">"Mazat všechna data"</string>      <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Bez upozornění smazat všechna data tabletu obnovením továrních dat."</string>      <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Provést obnovení továrních dat a bez upozornění tím vymazat data v zařízení Android TV."</string>      <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"Bez upozornění se smažou všechna data informačního a zábavního systému obnovením továrních dat."</string> @@ -1727,9 +1727,9 @@      <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Chcete službě <xliff:g id="SERVICE">%1$s</xliff:g> povolit plnou kontrolu nad vaším zařízením?"</string>      <string name="accessibility_service_warning_description" msgid="291674995220940133">"Plná kontrola je vhodná u aplikací, které vám pomáhají s usnadněním přístupu. U většiny aplikací však vhodná není."</string>      <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Zobrazení a ovládání obrazovky"</string> -    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Služba může číst veškerý obsah obrazovky a zobrazovat ho přes ostatní aplikace."</string> +    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Služba může číst veškerý obsah obrazovky a zobrazovat ho přes ostatní aplikace."</string>      <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Zobrazení a provádění akcí"</string> -    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Služba může sledovat vaše interakce s aplikací nebo hardwarovým senzorem a komunikovat s aplikacemi namísto vás."</string> +    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Služba může sledovat vaše interakce s aplikací nebo hardwarovým senzorem a komunikovat s aplikacemi za vás."</string>      <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Povolit"</string>      <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Zakázat"</string>      <string name="accessibility_dialog_button_uninstall" msgid="2952465517671708108">"Odinstalovat"</string> @@ -1745,7 +1745,7 @@      <string name="color_inversion_feature_name" msgid="2672824491933264951">"Převrácení barev"</string>      <string name="color_correction_feature_name" msgid="7975133554160979214">"Korekce barev"</string>      <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jedné ruky"</string> -    <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Velmi tmavé"</string> +    <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Velmi tmavé zobrazení"</string>      <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Naslouchátka"</string>      <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> je zapnutá."</string>      <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Byla podržena tlačítka hlasitosti. Služba <xliff:g id="SERVICE_NAME">%1$s</xliff:g> byla vypnuta."</string> @@ -1904,7 +1904,7 @@      <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>      <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Spořič baterie zapíná tmavý motiv a omezuje či vypíná aktivitu na pozadí, některé vizuální efekty, některé funkce a připojení k některým sítím."</string>      <string name="battery_saver_description" msgid="8518809702138617167">"Spořič baterie zapíná tmavý motiv a omezuje či vypíná aktivitu na pozadí, některé vizuální efekty, některé funkce a připojení k některým sítím."</string> -    <string name="data_saver_description" msgid="4995164271550590517">"S cílem snížit spotřebu dat brání spořič dat některým aplikacím odesílat nebo přijímat data 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_description" msgid="4995164271550590517">"S cílem snížit spotřebu dat brání spořič dat některým aplikacím odesílat nebo přijímat data na pozadí. Aplikace, kterou právě používáte, sice data využívat může, ale méně často. Může to například znamenat, že obrázky se zobrazí, až na ně klepnete."</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>      <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Na jednu minutu (do {formattedTime})}few{Na # minuty (do {formattedTime})}many{Na # minuty (do {formattedTime})}other{Na # minut (do {formattedTime})}}"</string> @@ -2396,8 +2396,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Komunální"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikace je z bezpečnostních důvodů při sdílení obrazovky skryt"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automaticky připojeno k satelitu"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Zprávy můžete odesílat a přijímat bez mobilní sítě nebo sítě Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otevřít Zprávy"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 59be3ddc7e8b..3f830c9d7cf1 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Fælles"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Af sikkerhedsmæssige årsager vises appindhold ikke ved skærmdeling"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Der blev automatisk oprettet forbindelse til satellit"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Du kan sende og modtage beskeder uden et mobil- eller Wi-Fi-netværk"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Åbn Beskeder"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index b4882febd4a2..1c01cc76cc77 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -1929,12 +1929,9 @@      <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Verwaltet von <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"An"</string>      <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Aus"</string> -    <!-- no translation found for zen_mode_trigger_summary_divider_text (7461583466043698862) --> -    <skip /> -    <!-- no translation found for zen_mode_trigger_summary_range_symbol_combination (1804900738798069619) --> -    <skip /> -    <!-- no translation found for zen_mode_trigger_event_calendar_any (2086784607921121803) --> -    <skip /> +    <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string> +    <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g>–<xliff:g id="END">%2$s</xliff:g>"</string> +    <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"Alle Kalender"</string>      <string name="muted_by" msgid="91464083490094950">"Einige Töne werden von <xliff:g id="THIRD_PARTY">%1$s</xliff:g> stummgeschaltet"</string>      <string name="system_error_wipe_data" msgid="5910572292172208493">"Es liegt ein internes Problem mit deinem Gerät vor. Möglicherweise verhält es sich instabil, bis du es auf die Werkseinstellungen zurücksetzt."</string>      <string name="system_error_manufacturer" msgid="703545241070116315">"Es liegt ein internes Problem mit deinem Gerät vor. Bitte wende dich diesbezüglich an den Hersteller."</string> @@ -2397,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Gemeinsam genutzt"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App-Inhalte werden aus Sicherheitsgründen bei der Bildschirmfreigabe ausgeblendet"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automatisch mit Satellit verbunden"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Du kannst Nachrichten ohne Mobilfunknetz oder WLAN senden und empfangen"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages öffnen"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 1b88a6ac809d..cafccf5992b0 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Δοκιμή"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Κοινόχρηστο"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Για λόγους ασφάλειας, έγινε απόκρυψη του περιεχομένου της εφαρμογής από την κοινή χρήση οθόνης"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Συνδέθηκε αυτόματα με δορυφόρο"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Μπορείτε να στέλνετε και να λαμβάνετε μηνύματα χωρίς δίκτυο κινητής τηλεφωνίας ή Wi-Fi."</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Άνοιγμα Messages"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 5a6c6200b0e9..11fb50e03869 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Auto-connected to satellite"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"You can send and receive messages without a mobile or Wi-Fi network"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 4972e1bc2f44..60dbcd96914f 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Auto-connected to satellite"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"You can send and receive messages without a mobile or Wi-Fi network"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index c35c2ff84850..859d04af9037 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Auto-connected to satellite"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"You can send and receive messages without a mobile or Wi-Fi network"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 4f7f7a72aac8..39e3d5da2227 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1728,7 +1728,7 @@      <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Ver y controlar la pantalla"</string>      <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Puede leer todo el contenido en la pantalla y mostrar contenido sobre otras apps."</string>      <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Ver y realizar acciones"</string> -    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Puede realizar el seguimiento de tus interacciones con una app o un sensor de hardware, así como interactuar con las apps por ti."</string> +    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Puede seguir tus interacciones con una app o un sensor de hardware, así como interactuar con las apps por ti."</string>      <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Permitir"</string>      <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Rechazar"</string>      <string name="accessibility_dialog_button_uninstall" msgid="2952465517671708108">"Desinstalar"</string> @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Probar"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Compartido"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Se ocultó el contenido de la app durante el uso compartido de la pantalla por motivos de seguridad"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Conexión automática a satélite"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Puedes enviar y recibir mensajes incluso si no tienes conexión a una red móvil o Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir Mensajes"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index bf9d526f403a..796e5eabdf7d 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1903,7 +1903,7 @@      <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>      <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales, ciertas funciones y algunas conexiones de red."</string>      <string name="battery_saver_description" msgid="8518809702138617167">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales, ciertas funciones y algunas conexiones de red."</string> -    <string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, el ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano. Si estás usando una aplicación, podrá acceder a datos, pero 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_description" msgid="4995164271550590517">"Para reducir el uso de datos, Ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano. Si estás usando una aplicación, podrá acceder a datos, pero 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>      <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Durante un minuto (hasta las {formattedTime})}many{Durante # minutos (hasta las {formattedTime})}other{Durante # minutos (hasta las {formattedTime})}}"</string> @@ -2032,7 +2032,7 @@      <string name="pin_specific_target" msgid="7824671240625957415">"Fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string>      <string name="unpin_target" msgid="3963318576590204447">"No fijar"</string>      <string name="unpin_specific_target" msgid="3859828252160908146">"No fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string> -    <string name="app_info" msgid="6113278084877079851">"Información de la aplicación"</string> +    <string name="app_info" msgid="6113278084877079851">"Información de la app"</string>      <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>      <string name="demo_starting_message" msgid="6577581216125805905">"Iniciando demostración…"</string>      <string name="demo_restarting_message" msgid="1160053183701746766">"Restableciendo dispositivo…"</string> @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Prueba"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Común"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenido de la aplicación oculto en pantalla compartida por motivos de seguridad"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Conectado automáticamente al satélite"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Puedes enviar y recibir mensajes sin una red móvil o Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abre Mensajes"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index cc82e47e1b43..99809d3a3311 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Jagatud"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Rakenduse sisu on ekraani jagamises turvalisuse huvides peidetud"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Satelliidiga loodi automaatselt ühendus"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Teil on võimalik sõnumeid saata ja vastu võtta ilma mobiilside- ja WiFi-võrguta"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ava rakendus Messages"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 34c066351d4d..c8c2e4575f7b 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Probakoa"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Partekatua"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Aplikazioko edukia ezkutatu egin da pantaila partekatzeko eginbidetik, segurtasuna bermatzeko"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automatikoki konektatu da satelitera"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Mezuak bidal eta jaso ditzakezu sare mugikorrik edo wifi-sarerik gabe"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ireki Mezuak"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 4f2484e707e8..c59ac025787b 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"آزمایش"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"عمومی"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"بهدلایل امنیتی، محتوای برنامه از دید همرسانی صفحهنمایش پنهان شد"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"بهطور خودکار به ماهواره متصل شد"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"میتوانید بدون شبکه تلفن همراه یا Wi-Fi پیام ارسال و دریافت کنید"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"باز کردن «پیامها»"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 81b984827d9d..7612906d732f 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1384,7 +1384,7 @@      <string name="no_permissions" msgid="5729199278862516390">"Lupia ei tarvita"</string>      <string name="perm_costs_money" msgid="749054595022779685">"tämä voi maksaa"</string>      <string name="dlg_ok" msgid="5103447663504839312">"OK"</string> -    <string name="usb_charging_notification_title" msgid="1674124518282666955">"Laite lataa USB-yhteydellä"</string> +    <string name="usb_charging_notification_title" msgid="1674124518282666955">"Laitetta ladataan USB:llä"</string>      <string name="usb_supplying_notification_title" msgid="5378546632408101811">"Ladataan yhdistettyä laitetta USB:n kautta"</string>      <string name="usb_mtp_notification_title" msgid="1065989144124499810">"USB-tiedostonsiirto on käytössä"</string>      <string name="usb_ptp_notification_title" msgid="5043437571863443281">"PTP USB:n kautta on käytössä"</string> @@ -1655,7 +1655,7 @@      <string name="wireless_display_route_description" msgid="8297563323032966831">"Langaton näyttö"</string>      <string name="media_route_button_content_description" msgid="2299223698196869956">"Suoratoisto"</string>      <string name="media_route_chooser_title" msgid="6646594924991269208">"Yhdistä laitteeseen"</string> -    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Lähetä näyttö laitteeseen"</string> +    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Striimaa näyttö laitteeseen"</string>      <string name="media_route_chooser_searching" msgid="6119673534251329535">"Etsitään laitteita…"</string>      <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Asetukset"</string>      <string name="media_route_controller_disconnect" msgid="7362617572732576959">"Katkaise yhteys"</string> @@ -1903,8 +1903,8 @@      <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Virransäästö laittaa tumman teeman päälle ja rajoittaa tai laittaa pois päältä taustatoimintoja, tiettyjä ominaisuuksia sekä joitakin visuaalisia tehosteita ja verkkoyhteyksiä."</string>      <string name="battery_saver_description" msgid="8518809702138617167">"Virransäästö laittaa tumman teeman päälle ja rajoittaa tai laittaa pois päältä taustatoimintoja, tiettyjä ominaisuuksia sekä joitakin visuaalisia tehosteita ja verkkoyhteyksiä."</string>      <string name="data_saver_description" msgid="4995164271550590517">"Data Saver estää joitakin sovelluksia lähettämästä tai vastaanottamasta tietoja taustalla, jotta datan käyttöä voidaan vähentää. Käytössäsi oleva sovellus voi yhä käyttää dataa, mutta se saattaa tehdä niin tavallista harvemmin. Tämä voi tarkoittaa esimerkiksi sitä, että kuva ladataan vasta, kun kosketat sitä."</string> -    <string name="data_saver_enable_title" msgid="7080620065745260137">"Otetaanko Data Saver käyttöön?"</string> -    <string name="data_saver_enable_button" msgid="4399405762586419726">"Ota käyttöön"</string> +    <string name="data_saver_enable_title" msgid="7080620065745260137">"Laitetaanko Data Saver päälle?"</string> +    <string name="data_saver_enable_button" msgid="4399405762586419726">"Laita päälle"</string>      <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Yhdeksi minuutiksi ({formattedTime} asti)}other{# minuutiksi ({formattedTime} asti)}}"</string>      <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Yhdeksi minuutiksi ({formattedTime} asti)}other{# minuutiksi ({formattedTime} asti)}}"</string>      <string name="zen_mode_duration_hours_summary" msgid="3866333100793277211">"{count,plural, =1{Yhdeksi tunniksi ({formattedTime} asti)}other{# tunniksi ({formattedTime} asti)}}"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Testi"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Jaettu"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sovelluksen sisältö piilotettu näytön jakamiselta turvallisuussyistä"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Yhdistetty automaattisesti satelliittiin"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Voit lähettää ja vastaanottaa viestejä ilman mobiili‑ tai Wi-Fi-verkkoa"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Avaa Messages"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 15d36f57b95b..7d86d83432ff 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1930,12 +1930,9 @@      <string name="zen_mode_implicit_trigger_description" msgid="5714956693073007111">"Géré par <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="zen_mode_implicit_activated" msgid="2634285680776672994">"Activé"</string>      <string name="zen_mode_implicit_deactivated" msgid="8688441768371501750">"Désactivé"</string> -    <!-- no translation found for zen_mode_trigger_summary_divider_text (7461583466043698862) --> -    <skip /> -    <!-- no translation found for zen_mode_trigger_summary_range_symbol_combination (1804900738798069619) --> -    <skip /> -    <!-- no translation found for zen_mode_trigger_event_calendar_any (2086784607921121803) --> -    <skip /> +    <string name="zen_mode_trigger_summary_divider_text" msgid="7461583466043698862">", "</string> +    <string name="zen_mode_trigger_summary_range_symbol_combination" msgid="1804900738798069619">"<xliff:g id="START">%1$s</xliff:g> – <xliff:g id="END">%2$s</xliff:g>"</string> +    <string name="zen_mode_trigger_event_calendar_any" msgid="2086784607921121803">"N\'importe quel agenda"</string>      <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> désactive certains sons"</string>      <string name="system_error_wipe_data" msgid="5910572292172208493">"Un problème interne est survenu avec votre appareil. Il se peut qu\'il soit instable jusqu\'à ce que vous le réinitialisiez à ses paramètres par défaut."</string>      <string name="system_error_manufacturer" msgid="703545241070116315">"Un problème interne est survenu avec votre appareil. Communiquez avec le fabricant pour obtenir plus de détails."</string> @@ -2398,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Commun"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'application est masqué du Partage d\'écran par mesure de sécurité"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Connecté au satellite automatiquement"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Vous pouvez envoyer et recevoir des messages sans avoir recours à un appareil mobile ou à un réseau Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ouvrir Messages"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 0346822b0639..80f1cf8db321 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -330,7 +330,7 @@      <string name="permgroupdesc_microphone" msgid="1047786732792487722">"enregistrer des fichiers audio"</string>      <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Activité physique"</string>      <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"accéder aux données d\'activité physique"</string> -    <string name="permgrouplab_camera" msgid="9090413408963547706">"Caméra"</string> +    <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_nearby_devices" msgid="5529147543651181991">"Appareils à proximité"</string>      <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"détecter des appareils à proximité et s\'y connecter"</string> @@ -726,7 +726,7 @@      <skip />      <string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Impossible de créer votre empreinte faciale. Réessayez."</string>      <string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Lunettes sombres détectées. Votre visage doit être entièrement visible."</string> -    <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Visage partiellement couvert. Votre visage doit être entièrement visible."</string> +    <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Masque détecté. Votre visage doit être entièrement visible."</string>    <string-array name="face_acquired_vendor">    </string-array>      <string name="face_error_hw_not_available" msgid="5085202213036026288">"Imposs. valider visage. Matériel non disponible."</string> @@ -1059,7 +1059,7 @@      <string name="keyguard_accessibility_widget" msgid="6776892679715699875">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>"</string>      <string name="keyguard_accessibility_user_selector" msgid="1466067610235696600">"Sélecteur d\'utilisateur"</string>      <string name="keyguard_accessibility_status" msgid="6792745049712397237">"État"</string> -    <string name="keyguard_accessibility_camera" msgid="7862557559464986528">"Caméra"</string> +    <string name="keyguard_accessibility_camera" msgid="7862557559464986528">"Appareil photo"</string>      <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"Commandes multimédias"</string>      <string name="keyguard_accessibility_widget_reorder_start" msgid="7066213328912939191">"Début de la réorganisation des widgets"</string>      <string name="keyguard_accessibility_widget_reorder_end" msgid="1083806817600593490">"Réorganisation des widgets terminée."</string> @@ -2124,7 +2124,7 @@      <string name="review_notification_settings_dismiss" msgid="4160916504616428294">"Fermer"</string>      <string name="notification_app_name_system" msgid="3045196791746735601">"Système"</string>      <string name="notification_app_name_settings" msgid="9088548800899952531">"Paramètres"</string> -    <string name="notification_appops_camera_active" msgid="8177643089272352083">"Caméra"</string> +    <string name="notification_appops_camera_active" msgid="8177643089272352083">"Appareil photo"</string>      <string name="notification_appops_microphone_active" msgid="581333393214739332">"Micro"</string>      <string name="notification_appops_overlay_active" msgid="5571732753262836481">"se superpose aux autres applications sur l\'écran"</string>      <string name="notification_feedback_indicator" msgid="663476517711323016">"Envoyer des commentaires"</string> @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Commun"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'appli est masqué lors du partage d\'écran pour des raisons de sécurité"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Connecté automatiquement au réseau satellite"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Vous pouvez envoyer et recevoir des messages sans connexion au réseau mobile ou Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ouvrir Messages"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index fa48e96fe3de..0dbf36928683 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -995,7 +995,7 @@      <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto!"</string>      <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Téntao de novo"</string>      <string name="lockscreen_password_wrong" msgid="8605355913868947490">"Téntao de novo"</string> -    <string name="lockscreen_storage_locked" msgid="634993789186443380">"Desbloquea para gozar todas as funcións e datos"</string> +    <string name="lockscreen_storage_locked" msgid="634993789186443380">"Desbloquear para gozar de todas as funcións e datos"</string>      <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Superouse o número máximo de intentos de desbloqueo facial"</string>      <string name="lockscreen_missing_sim_message_short" msgid="1229301273156907613">"Non hai SIM"</string>      <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"Non hai ningunha SIM na tableta."</string> @@ -1970,7 +1970,7 @@      <string name="default_notification_channel_label" msgid="3697928973567217330">"Sen clasificar"</string>      <string name="importance_from_user" msgid="2782756722448800447">"Ti defines a importancia destas notificacións."</string>      <string name="importance_from_person" msgid="4235804979664465383">"É importante polas persoas involucradas."</string> -    <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificación de aplicacións personalizada"</string> +    <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificación de aplicación personalizada"</string>      <string name="user_creation_account_exists" msgid="2239146360099708035">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Xa existe un usuario con esta conta)"</string>      <string name="user_creation_adding" msgid="7305185499667958364">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>      <string name="supervised_user_creation_label" msgid="6884904353827427515">"Engadir usuario supervisado"</string> @@ -2031,7 +2031,7 @@      <string name="pin_specific_target" msgid="7824671240625957415">"Fixar a <xliff:g id="LABEL">%1$s</xliff:g>"</string>      <string name="unpin_target" msgid="3963318576590204447">"Deixar de fixar"</string>      <string name="unpin_specific_target" msgid="3859828252160908146">"Deixar de fixar a <xliff:g id="LABEL">%1$s</xliff:g>"</string> -    <string name="app_info" msgid="6113278084877079851">"Información da aplicación"</string> +    <string name="app_info" msgid="6113278084877079851">"Información da app"</string>      <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>      <string name="demo_starting_message" msgid="6577581216125805905">"Iniciando demostración…"</string>      <string name="demo_restarting_message" msgid="1160053183701746766">"Restablecendo dispositivo…"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Proba"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Compartido"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Por motivos de seguranza, ocultouse o contido da aplicación para que no se mostre na pantalla compartida"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Conexión automática ao satélite"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Podes enviar e recibir mensaxes sen unha rede de telefonía móbil ou wifi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir Mensaxes"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index fb202bac6fb2..b3cf16bb4e5e 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"પરીક્ષણ કરો"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"કૉમ્યુનલ"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"સુરક્ષા માટે સ્ક્રીન શેર કરતી વખતે ઍપનું કન્ટેન્ટ છુપાવેલું છે"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"સેટેલાઇટ સાથે ઑટોમૅટિક રીતે કનેક્ટેડ"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"તમે મોબાઇલ અથવા વાઇ-ફાઇ નેટવર્ક વિના મેસેજ મોકલી અને પ્રાપ્ત કરી શકો છો"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ખોલો"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index fd99d19b59a5..ac070c785905 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -278,7 +278,7 @@      <string name="global_action_settings" msgid="4671878836947494217">"सेटिंग"</string>      <string name="global_action_assist" msgid="2517047220311505805">"सहायता"</string>      <string name="global_action_voice_assist" msgid="6655788068555086695">"आवाज़ से डिवाइस का इस्तेमाल"</string> -    <string name="global_action_lockdown" msgid="2475471405907902963">"फ़ाेन लॉक करें"</string> +    <string name="global_action_lockdown" msgid="2475471405907902963">"लॉकडाउन"</string>      <string name="status_bar_notification_info_overflow" msgid="3330152558746563475">"999+"</string>      <string name="notification_hidden_text" msgid="2835519769868187223">"नई सूचना"</string>      <string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"सामान्य कीबोर्ड"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"टेस्ट"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"कम्यूनिटी"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रीन शेयर करने के दौरान सुरक्षा के लिए, ऐप्लिकेशन का कॉन्टेंट छिपाया गया"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"सैटलाइट से अपने-आप कनेक्ट हो गया"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"मोबाइल या वाई-फ़ाई नेटवर्क के बिना भी मैसेज भेजे और पाए जा सकते हैं"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ऐप्लिकेशन खोलें"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 5ac09ec6fe80..02435994e2b0 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1420,7 +1420,7 @@      <string name="share_remote_bugreport_action" msgid="7630880678785123682">"DIJELI"</string>      <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ODBIJ"</string>      <string name="select_input_method" msgid="3971267998568587025">"Odabir načina unosa"</string> -    <string name="show_ime" msgid="6406112007347443383">"Zadrži na zaslonu dok je fizička tipkovnica aktivna"</string> +    <string name="show_ime" msgid="6406112007347443383">"Zadržava se na zaslonu dok je fizička tipkovnica aktivna"</string>      <string name="hardware" msgid="3611039921284836033">"Upotreba zaslonske tipkovnice"</string>      <string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfigurirajte uređaj <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>      <string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfigurirajte fizičke tipkovnice"</string> @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Zajedničko"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije sakriven je od dijeljenja zaslona radi sigurnosti"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automatski povezano sa satelitom"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Možete slati i primati poruke bez mobilne mreže ili Wi-Fi mreže"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvori Poruke"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 06ca1b6dfbc1..9c8eb5634a33 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1723,7 +1723,7 @@      <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"BE"</string>      <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"KI"</string>      <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Teljes körű vezérlést biztosít eszköze felett a(z) <xliff:g id="SERVICE">%1$s</xliff:g> szolgáltatás számára?"</string> -    <string name="accessibility_service_warning_description" msgid="291674995220940133">"A teljes vezérlés indokolt olyan alkalmazásoknál, amelyek kisegítő lehetőségeket nyújtanak, a legtöbb alkalmazásnál azonban nem."</string> +    <string name="accessibility_service_warning_description" msgid="291674995220940133">"A teljes körű vezérlés indokolt olyan alkalmazásoknál, amelyek kisegítő lehetőségeket nyújtanak, a legtöbb alkalmazásnál azonban nem."</string>      <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Képernyő megtekintése és kezelése"</string>      <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Elolvashatja a képernyő tartalmát, és tartalmakat jeleníthet meg más alkalmazások felett."</string>      <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Műveletek megtekintése és elvégzése"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Teszt"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Közös"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"A biztonság érdekében a képernyőmegosztástól elrejtett alkalmazástartalom"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automatikusan csatlakozva a műholdhoz"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Küldhet és fogadhat üzeneteket mobil- és Wi-Fi-hálózat nélkül is"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"A Messages megnyitása"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 89e087ec7100..63edfcedc523 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1970,7 +1970,7 @@      <string name="default_notification_channel_label" msgid="3697928973567217330">"Չդասակարգված"</string>      <string name="importance_from_user" msgid="2782756722448800447">"Դուք սահմանել եք այս ծանուցումների կարևորությունը:"</string>      <string name="importance_from_person" msgid="4235804979664465383">"Կարևոր է, քանի որ որոշակի մարդիկ են ներգրավված:"</string> -    <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Հավելվածի հատուկ ծանուցում"</string> +    <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Հատուկ հավելվածի ծանուցում"</string>      <string name="user_creation_account_exists" msgid="2239146360099708035">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել (նման հաշվով Օգտատեր արդեն գոյություն ունի):"</string>      <string name="user_creation_adding" msgid="7305185499667958364">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել:"</string>      <string name="supervised_user_creation_label" msgid="6884904353827427515">"Ավելացնել վերահսկվող օգտատեր"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Փորձնական"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Ընդհանուր"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Անվտանգության նկատառումներից ելնելով՝ հավելվածի բովանդակությունը թաքցվել է էկրանի ցուցադրումից"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Ավտոմատ միացել է արբանյակին"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Դուք կարող եք ուղարկել և ստանալ հաղորդագրություններ՝ առանց բջջային կամ Wi-Fi կապի"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Բացել Messages-ը"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 616b30b86ffb..8a29efd9da71 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -995,7 +995,7 @@      <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Perbaiki!"</string>      <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Coba lagi"</string>      <string name="lockscreen_password_wrong" msgid="8605355913868947490">"Coba lagi"</string> -    <string name="lockscreen_storage_locked" msgid="634993789186443380">"Membuka kunci untuk semua fitur dan data"</string> +    <string name="lockscreen_storage_locked" msgid="634993789186443380">"Buka kunci untuk melihat semua fitur dan data"</string>      <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Percobaan Buka dengan Wajah melebihi batas maksimum"</string>      <string name="lockscreen_missing_sim_message_short" msgid="1229301273156907613">"Tidak ada SIM"</string>      <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"Tidak ada SIM di tablet."</string> @@ -1367,7 +1367,7 @@      <string name="sim_removed_message" msgid="8469588437451533845">"Jaringan seluler tidak akan tersedia sampai Anda memulai ulang dengan SIM yang valid."</string>      <string name="sim_done_button" msgid="6464250841528410598">"Selesai"</string>      <string name="sim_added_title" msgid="2976783426741012468">"SIM ditambahkan"</string> -    <string name="sim_added_message" msgid="6602906609509958680">"Mulai ulang perangkat Anda untuk mengakses jaringan selular."</string> +    <string name="sim_added_message" msgid="6602906609509958680">"Mulai ulang perangkat Anda untuk mengakses jaringan seluler."</string>      <string name="sim_restart_button" msgid="8481803851341190038">"Mulai Ulang"</string>      <string name="install_carrier_app_notification_title" msgid="5712723402213090102">"Aktifkan layanan seluler"</string>      <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Download aplikasi operator untuk mengaktifkan SIM baru"</string> @@ -1725,9 +1725,9 @@      <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Izinkan <xliff:g id="SERVICE">%1$s</xliff:g> mengontrol perangkat Anda secara penuh?"</string>      <string name="accessibility_service_warning_description" msgid="291674995220940133">"Kontrol penuh sesuai untuk aplikasi yang mendukung kebutuhan aksesibilitas Anda, tetapi tidak untuk sebagian besar aplikasi."</string>      <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Melihat dan mengontrol layar"</string> -    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Voice Access dapat membaca semua konten di layar dan menampilkan konten di atas aplikasi lain."</string> +    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Membaca semua konten di layar dan menampilkan konten di atas aplikasi lain."</string>      <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Menampilkan dan melakukan tindakan"</string> -    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Voice Access dapat melacak interaksi Anda dengan aplikasi atau sensor hardware, dan berinteraksi dengan aplikasi untuk Anda."</string> +    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Melacak interaksi Anda dengan aplikasi atau sensor hardware, dan berinteraksi dengan aplikasi untuk Anda."</string>      <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Izinkan"</string>      <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Tolak"</string>      <string name="accessibility_dialog_button_uninstall" msgid="2952465517671708108">"Uninstal"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Pengujian"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Umum"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Konten aplikasi disembunyikan dari berbagi layar untuk alasan keamanan"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Menghubungkan otomatis ke satelit"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Anda dapat mengirim dan menerima pesan tanpa jaringan seluler atau Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Buka Message"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 5d55ba8f2a58..996c17779580 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Prófun"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Sameiginlegt"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Efni forrits falið í skjádeilingu af öryggisástæðum"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Tengdist sjálfkrafa við gervihnött"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Þú getur sent og móttekið skilaboð án tengingar við farsímakerfi eða Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Opna Messages"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 9d8d74a3c467..a5373abbc896 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1193,7 +1193,7 @@      <string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"Memoria insufficiente per il sistema. Assicurati di avere 250 MB di spazio libero e riavvia."</string>      <string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> è in esecuzione"</string>      <string name="app_running_notification_text" msgid="5120815883400228566">"Tocca per ulteriori informazioni o per interrompere l\'app."</string> -    <string name="ok" msgid="2646370155170753815">"OK"</string> +    <string name="ok" msgid="2646370155170753815">"Ok"</string>      <string name="cancel" msgid="6908697720451760115">"Annulla"</string>      <string name="yes" msgid="9069828999585032361">"OK"</string>      <string name="no" msgid="5122037903299899715">"Annulla"</string> @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Condiviso"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenuti dell\'app nascosti dalla condivisione schermo per sicurezza"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Connessione automatica al satellite"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Puoi inviare e ricevere messaggi senza una rete mobile o Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Apri Messaggi"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index c256de994bd4..e9e558595a91 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"בדיקה"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"שיתופי"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"תוכן האפליקציה מוסתר משיתוף המסך מטעמי אבטחה"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"חיבור אוטומטי ללוויין"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"אפשר לשלוח ולקבל הודעות ללא רשת סלולרית או רשת Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"לפתיחת Messages"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index eee2e3dc6a17..e8dee3c625dc 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -828,14 +828,14 @@      <string name="policylab_limitPassword" msgid="4851829918814422199">"パスワードルールの設定"</string>      <string name="policydesc_limitPassword" msgid="4105491021115793793">"画面ロックのパスワードとPINの長さと使用できる文字を制御します。"</string>      <string name="policylab_watchLogin" msgid="7599669460083719504">"画面ロック解除試行の監視"</string> -    <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"画面のロック解除に正しくないパスワードを入力した回数を監視し、回数が多すぎる場合はタブレットをロックするかタブレットのデータをすべて消去します。"</string> -    <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"画面のロック解除の際に入力したパスワードが間違っていた回数を監視し、回数が多すぎる場合は Android TV デバイスをロックするか Android TV デバイスのデータをすべて消去します。"</string> -    <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"画面のロック解除に正しくないパスワードを入力した回数を監視し、回数が多すぎる場合はインフォテインメント システムをロックするかインフォテインメント システムのデータをすべて消去します。"</string> -    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"画面のロック解除に正しくないパスワードを入力した回数を監視し、回数が多すぎる場合はモバイルデバイスをロックするかモバイルデバイスのデータをすべて消去します。"</string> -    <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="automotive" msgid="7180857406058327941">"画面のロック解除に正しくないパスワードを入力した回数を監視し、回数が多すぎる場合はインフォテインメント システムをロックするかこのプロファイルのデータをすべて消去します。"</string> -    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"画面のロック解除の際に入力したパスワードが間違っていた回数を監視し、回数が多すぎる場合はスマートフォンをロックするかこのユーザーのデータをすべて消去します。"</string> +    <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"画面のロック解除に失敗した回数を監視し、多すぎる場合はタブレットをロックするかタブレットのデータをすべて消去します。"</string> +    <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"画面のロック解除に失敗した回数を監視し、多すぎる場合は Android TV デバイスをロックするか Android TV デバイスのデータをすべて消去します。"</string> +    <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"画面のロック解除に失敗した回数を監視し、多すぎる場合はインフォテインメント システムをロックするかインフォテインメント システムのデータをすべて消去します。"</string> +    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"画面のロック解除に失敗した回数を監視し、多すぎる場合はモバイルデバイスをロックするかモバイルデバイスのデータをすべて消去します。"</string> +    <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="automotive" msgid="7180857406058327941">"画面のロック解除に失敗した回数を監視し、多すぎる場合はインフォテインメント システムをロックするかこのプロファイルのデータをすべて消去します。"</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> @@ -1420,7 +1420,7 @@      <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"共有しない"</string>      <string name="select_input_method" msgid="3971267998568587025">"入力方法の選択"</string>      <string name="show_ime" msgid="6406112007347443383">"物理キーボードが有効になっていても画面に表示させます"</string> -    <string name="hardware" msgid="3611039921284836033">"画面キーボードの使用"</string> +    <string name="hardware" msgid="3611039921284836033">"画面キーボードを使用"</string>      <string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g>の設定"</string>      <string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"物理キーボードの設定"</string>      <string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"タップして言語とレイアウトを選択してください"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"テスト"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"セキュリティ上、画面共有ではアプリの内容は非表示となります"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"衛星に自動接続しました"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"モバイル ネットワークや Wi-Fi ネットワークを使わずにメッセージを送受信できます"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"メッセージ アプリを開く"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index ececd928bb6e..d4b4d12798b6 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"სატესტო"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"საერთო"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ეკრანის გაზიარებიდან აპის კონტენტი დამალულია უსაფრთხოების მიზნით"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"სატელიტთან ავტომატურად დაკავშირებულია"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"შეგიძლიათ გაგზავნოთ და მიიღოთ შეტყობინებები მობილური ან Wi-Fi ქსელის გარეშე"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages-ის გახსნა"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 38c6f7721cc3..7a2528dc03df 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -831,7 +831,7 @@      <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Экран бекітпесін ашқан кезде терілген қате құпия сөздердің санын бақылау және планшетті бекіту немесе тым көп қате құпия сөздер терілген болса, планшеттің бүкіл деректерін өшіру."</string>      <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Экранның құлпын ашу кезінде қате енгізілген құпия сөздердің санын бақылау, құпия сөз тым көп қате енгізілген жағдайда, Android TV құрылғысын құлыптау және Android TV құрылғыңыздың барлық деректерінен тазарту."</string>      <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Экран құлпын ашқан кезде, терілген қате құпия сөздердің саны бақыланады, сондай-ақ құпия сөздер бірнеше рет қате терілсе, ақпараттық-сауықтық жүйе құлыпталады немесе оның барлық дерегі жойылады."</string> -    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Экран бекітпесін ашқан кезде терілген қате құпия сөздердің санын бақылау және телефонды бекіту немесе тым көп қате құпия сөздер терілген болса, телефонның бүкіл деректерін өшіру."</string> +    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Экран құлпын ашқан кезде терілген қате құпия сөздердің санын бақылау және құпия сөз тым көп рет қате терілгенде, телефонды құлыптау немесе оның бүкіл деректерін өшіру."</string>      <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="automotive" msgid="7180857406058327941">"Экран құлпын ашқан кезде, терілген қате құпия сөздердің саны бақыланады, сондай-ақ құпия сөздер бірнеше рет қате терілсе, ақпараттық-сауықтық жүйе құлыпталады немесе осы профильдің барлық дерегі жойылады."</string> @@ -1970,7 +1970,7 @@      <string name="default_notification_channel_label" msgid="3697928973567217330">"Санатқа жатқызылмаған"</string>      <string name="importance_from_user" msgid="2782756722448800447">"Сіз осы хабарландырулардың маңыздылығын орнатасыз."</string>      <string name="importance_from_person" msgid="4235804979664465383">"Қатысты адамдарға байланысты бұл маңызды."</string> -    <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Арнаулы хабар хабарландыруы"</string> +    <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Арнаулы қолданба хабарландыруы"</string>      <string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунты бар жаңа пайдаланушы (мұндай аккаунтқа ие пайдаланушы бұрыннан бар) жасауға рұқсат етілсін бе?"</string>      <string name="user_creation_adding" msgid="7305185499667958364">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунты бар жаңа пайдаланушы жасауға рұқсат етілсін бе?"</string>      <string name="supervised_user_creation_label" msgid="6884904353827427515">"Бақыланатын пайдаланушыны қосу"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Сынақ"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Жалпы"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Қауіпсіздік мақсатында қолданба контенті экранды көрсету кезінде жасырылды."</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Жерсерік қызметіне автоматты түрде қосылды"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Мобильдік не Wi-Fi желісіне қосылмастан хабар жібере аласыз және ала аласыз."</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages қолданбасын ашу"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 6c0a195be0a4..59a6e30d5abc 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -828,14 +828,14 @@      <string name="policylab_limitPassword" msgid="4851829918814422199">"កំណត់ក្បួនពាក្យសម្ងាត់"</string>      <string name="policydesc_limitPassword" msgid="4105491021115793793">"គ្រប់គ្រងប្រវែង និងតួអក្សរដែលអនុញ្ញាតឲ្យប្រើក្នុងពាក្យសម្ងាត់ និងលេខសម្ងាត់ចាក់សោអេក្រង់។"</string>      <string name="policylab_watchLogin" msgid="7599669460083719504">"តាមដានការព្យាយាមដោះសោអេក្រង់"</string> -    <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"ពិនិត្យចំនួនបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវ។ ពេលដោះសោអេក្រង់ និងចាក់សោទូរស័ព្ទ ឬលុបទិន្នន័យទូរស័ព្ទទាំងអស់ ប្រសិនបើមានពាក្យសម្ងាត់បញ្ចូលមិនត្រឹមត្រូវច្រើនដងពេក។"</string> +    <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"ពិនិត្យមើលចំនួនដងនៃការវាយបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវ នៅពេលដោះសោអេក្រង់ និងចាក់សោថេប្លេត ឬលុបទិន្នន័យថេប្លេតទាំងអស់ ប្រសិនបើវាយបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវច្រើនដងពេក។"</string>      <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"ពិនិត្យចំនួននៃការវាយបញ្ចូលពាក្យសម្ងាត់ដែលមិនត្រឹមត្រូវ នៅពេលដោះសោអេក្រង់ និងចាក់សោឧបករណ៍ Android TV របស់អ្នក ឬលុបទិន្នន័យឧបករណ៍ Android TV របស់អ្នកទាំងអស់ ប្រសិនបើវាយបញ្ចូលពាក្យសម្ងាត់ខុសច្រើនដងពេក។"</string>      <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"ពិនិត្យមើលចំនួនដងនៃការវាយបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវ នៅពេលដោះសោអេក្រង់ និងចាក់សោប្រព័ន្ធព័ត៌មាននិងកម្សាន្ត ឬលុបទិន្នន័យទាំងអស់របស់ប្រព័ន្ធព័ត៌មាននិងកម្សាន្ត ប្រសិនបើវាយបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវច្រើនដងពេក។"</string> -    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"ពិនិត្យចំនួនបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវ។ ពេលដោះសោអេក្រង់ និងចាក់សោទូរស័ព្ទ ឬលុបទិន្នន័យទូរស័ព្ទទាំងអស់ ប្រសិនបើមានពាក្យសម្ងាត់បញ្ចូលមិនត្រឹមត្រូវច្រើនដងពេក។"</string> +    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"ពិនិត្យមើលចំនួនដងនៃការវាយបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវ នៅពេលដោះសោអេក្រង់ និងចាក់សោទូរសព្ទ ឬលុបទិន្នន័យទូរសព្ទទាំងអស់ ប្រសិនបើវាយបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវច្រើនដងពេក។"</string>      <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="automotive" msgid="7180857406058327941">"ពិនិត្យមើលចំនួនដងនៃការវាយបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវ នៅពេលដោះសោអេក្រង់ និងចាក់សោប្រព័ន្ធព័ត៌មាននិងកម្សាន្ត ឬលុបទិន្នន័យទាំងអស់របស់កម្រងព័ត៌មាននេះ ប្រសិនបើវាយបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវច្រើនដងពេក។"</string> -    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"ត្រួតពិនិត្យចំនួននៃការវាយបញ្ចូលពាក្យសម្ងាត់ដែលមិនត្រឹមត្រូវ នៅពេលដោះសោអេក្រង់ និងចាក់សោទូរស័ព្ទ ឬលុបទិន្នន័យអ្នកប្រើនេះទាំងអស់ ប្រសិនបើមានការវាយបញ្ចូលពាក្យសម្ងាត់ខុសច្រើនដងពេក។"</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> @@ -995,7 +995,7 @@      <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_storage_locked" msgid="634993789186443380">"ដោះសោលក្ខណៈពិសេស និងទិន្នន័យទាំងអស់"</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="1229301273156907613">"គ្មានស៊ីមទេ"</string>      <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"គ្មានស៊ីមក្នុងថេប្លេតទេ។"</string> @@ -1761,7 +1761,7 @@      <string name="owner_name" msgid="8713560351570795743">"ម្ចាស់"</string>      <string name="guest_name" msgid="8502103277839834324">"ភ្ញៀវ"</string>      <string name="error_message_title" msgid="4082495589294631966">"កំហុស"</string> -    <string name="error_message_change_not_allowed" msgid="843159705042381454">"ការផ្លាស់ប្ដូរនេះមិនត្រូវបានអនុញ្ញាតដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string> +    <string name="error_message_change_not_allowed" msgid="843159705042381454">"ការផ្លាស់ប្ដូរនេះមិនត្រូវបានអនុញ្ញាតដោយអ្នកគ្រប់គ្រងរបស់អ្នកទេ"</string>      <string name="app_not_found" msgid="3429506115332341800">"រកមិនឃើញកម្មវិធី ដើម្បីគ្រប់គ្រងសកម្មភាពនេះ"</string>      <string name="revoke" msgid="5526857743819590458">"ដកហូត"</string>      <string name="mediasize_iso_a0" msgid="7039061159929977973">"ISO A0"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"ការធ្វើតេស្ត"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"ទូទៅ"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"បានលាក់ខ្លឹមសារកម្មវិធីពីការបង្ហាញអេក្រង់ដើម្បីសុវត្ថិភាព"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"ភ្ជាប់ដោយស្វ័យប្រវត្តិទៅផ្កាយរណប"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"អ្នកអាចផ្ញើ និងទទួលសារដោយមិនប្រើបណ្តាញទូរសព្ទចល័ត ឬ Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"បើកកម្មវិធី Messages"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index faa46baf666f..b1a74720d88f 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -1419,7 +1419,7 @@      <string name="share_remote_bugreport_action" msgid="7630880678785123682">"ಹಂಚಿಕೊಳ್ಳಿ"</string>      <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ನಿರಾಕರಿಸಿ"</string>      <string name="select_input_method" msgid="3971267998568587025">"ಇನ್ಪುಟ್ ವಿಧಾನವನ್ನು ಆರಿಸಿ"</string> -    <string name="show_ime" msgid="6406112007347443383">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಸಕ್ರಿಯವಾಗಿರುವಾಗ ಅದನ್ನು ಪರದೆಯ ಮೇಲಿರಿಸಿ"</string> +    <string name="show_ime" msgid="6406112007347443383">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಸಕ್ರಿಯವಾಗಿರುವಾಗ ಅದನ್ನು ಸ್ಕ್ರೀನ್ ಮೇಲಿರಿಸಿ"</string>      <string name="hardware" msgid="3611039921284836033">"ಆನ್-ಸ್ಕ್ರೀನ್ ಕೀಬೋರ್ಡ್ ಬಳಸಿ"</string>      <string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> ಕಾನ್ಫಿಗರ್ ಮಾಡಿ"</string>      <string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ಗಳನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡಿ"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"ಪರೀಕ್ಷೆ"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"ಸಮುದಾಯ"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ಭದ್ರತೆಗಾಗಿ ಸ್ಕ್ರೀನ್ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯಲ್ಲಿ ಆ್ಯಪ್ ಕಂಟೆಂಟ್ ಅನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"ಸ್ಯಾಟಲೈಟ್ಗೆ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"ನೀವು ಮೊಬೈಲ್ ಅಥವಾ ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ ಇಲ್ಲದೆಯೇ ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಬಹುದು ಮತ್ತು ಸ್ವೀಕರಿಸಬಹುದು"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ಅನ್ನು ತೆರೆಯಿರಿ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 9eaa4147eb30..baa260470dae 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"테스트"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"공동"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"보안을 위해 화면 공유에서 앱 콘텐츠가 숨겨집니다."</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"위성에 자동 연결됨"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"모바일 또는 Wi-Fi 네트워크 없이 메시지를 주고 받을 수 있습니다"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"메시지 열기"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 9efccffc829b..f02b58cd6d41 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -995,7 +995,7 @@      <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_storage_locked" msgid="634993789186443380">"Элементтердин жана дайындардын кулпусун ачуу"</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="1229301273156907613">"SIM карта жок"</string>      <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"Планшетте SIM карта жок."</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Сыноо"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Жалпы"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Коопсуздук үчүн колдонмодогу контент бөлүшүлгөн экрандан жашырылды"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Спутникке автоматтык түрдө туташтырылган"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Сиз мобилдик же Wi-Fi тармагы жок эле билдирүүлөрдү жөнөтүп, ала аласыз"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Жазышуулар колдонмосун ачуу"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 752e68eeeeca..e94f2d386a98 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -1877,7 +1877,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="display_rotation_camera_compat_toast_after_rotation" msgid="7600891546249829854">"ໝຸນເພື່ອມຸມມອງທີ່ດີຂຶ້ນ"</string>      <string name="display_rotation_camera_compat_toast_in_multi_window" msgid="2473122980393502775">"ເປີດ <xliff:g id="NAME">%s</xliff:g> ໃນໂໝດເຕັມຈໍເພື່ອມຸມມອງທີ່ດີຂຶ້ນ"</string>      <string name="done_label" msgid="7283767013231718521">"ແລ້ວໆ"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"ທົດສອບ"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"ສ່ວນກາງ"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ເນື້ອຫາແອັບຖືກເຊື່ອງໄວ້ຈາກການແບ່ງປັນໜ້າຈໍເພື່ອຄວາມປອດໄພ"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"ເຊື່ອມຕໍ່ກັບດາວທຽມໂດຍອັດຕະໂນມັດ"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"ທ່ານສາມາດສົ່ງ ແລະ ຮັບຂໍ້ຄວາມໂດຍບໍ່ຕ້ອງໃຊ້ເຄືອຂ່າຍມືຖື ຫຼື Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"ເປີດ Messages"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 2fd6ded698b6..da46662cf4b2 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -2396,8 +2396,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Bandymas"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Bendruomenės"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Programos turinys paslėptas bendrinant ekraną saugumo sumetimais"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automatiškai prisijungta prie palydovinio ryšio"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Galite siųsti ir gauti pranešimus be mobiliojo ryšio ar „Wi-Fi“ tinklo"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Atidaryti programą „Messages“"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 066cd4bb0fce..9fcf2d1c802d 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Testēšanai"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Kopīgs"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Drošības nolūkos lietotnes saturs kopīgotajā ekrānā ir paslēpts"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automātiski izveidots savienojums ar satelītu"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Varat sūtīt un saņemt ziņojumus bez mobilā vai Wi-Fi tīkla."</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Atvērt lietotni Ziņojumi"</string> diff --git a/core/res/res/values-mcc404/config.xml b/core/res/res/values-mcc404/config.xml index 4cadef7893d3..0cb1029626b1 100644 --- a/core/res/res/values-mcc404/config.xml +++ b/core/res/res/values-mcc404/config.xml @@ -18,8 +18,6 @@  -->  <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> -    <!-- Whether camera shutter sound is forced or not  (country specific). --> -    <bool name="config_camera_sound_forced">true</bool>      <!-- Show area update info settings in CellBroadcastReceiver and information in SIM status in Settings app -->      <bool name="config_showAreaUpdateInfoSettings">true</bool>  </resources> diff --git a/core/res/res/values-mcc405/config.xml b/core/res/res/values-mcc405/config.xml index 4cadef7893d3..0cb1029626b1 100644 --- a/core/res/res/values-mcc405/config.xml +++ b/core/res/res/values-mcc405/config.xml @@ -18,8 +18,6 @@  -->  <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> -    <!-- Whether camera shutter sound is forced or not  (country specific). --> -    <bool name="config_camera_sound_forced">true</bool>      <!-- Show area update info settings in CellBroadcastReceiver and information in SIM status in Settings app -->      <bool name="config_showAreaUpdateInfoSettings">true</bool>  </resources> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index a8d5ea4d341c..a0afccfac08d 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -1105,7 +1105,7 @@      <string name="menu_sym_shortcut_label" msgid="4037566049061218776">"копче Sym+"</string>      <string name="menu_function_shortcut_label" msgid="2367112760987662566">"копче Function+"</string>      <string name="menu_space_shortcut_label" msgid="5949311515646872071">"празен простор"</string> -    <string name="menu_enter_shortcut_label" msgid="6709499510082897320">"внеси"</string> +    <string name="menu_enter_shortcut_label" msgid="6709499510082897320">"enter"</string>      <string name="menu_delete_shortcut_label" msgid="4365787714477739080">"избриши"</string>      <string name="search_go" msgid="2141477624421347086">"Пребарај"</string>      <string name="search_hint" msgid="455364685740251925">"Пребарување…"</string> @@ -1674,7 +1674,7 @@      <string name="kg_wrong_password" msgid="2384677900494439426">"Погрешна лозинка"</string>      <string name="kg_wrong_pin" msgid="3680925703673166482">"Погрешен PIN"</string>      <string name="kg_pattern_instructions" msgid="8366024510502517748">"Употреби ја својата шема"</string> -    <string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Внеси PIN на SIM картичка"</string> +    <string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Внесете PIN за SIM-картичката"</string>      <string name="kg_pin_instructions" msgid="7355933174673539021">"Впишете PIN"</string>      <string name="kg_password_instructions" msgid="7179782578809398050">"Внеси лозинка"</string>      <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM картичката е сега оневозможена. Внесете ПУК код за да продолжите. Контактирајте го операторот за детали."</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Профил за тестирање"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Профил на заедницата"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Од безбедносни причини, содржините на апликацијата се скриени од споделувањето екран"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Поврзано со сателит автоматски"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Може да испраќате и примате пораки без мобилна или Wi-Fi мрежа"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Отворете ја Messages"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 32f2daf9153a..44af8b6f66ed 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -831,7 +831,7 @@      <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"സ്ക്രീൻ അൺലോക്കുചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പുചെയ്ത പാസ്വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുക, വളരെയധികം തെറ്റായ പാസ്വ്ഡുകൾ ടൈപ്പുചെയ്തിട്ടുണ്ടെങ്കിൽ ടാബ്ലെറ്റ് ലോക്കുചെയ്യുകയോ ടാബ്ലെറ്റിലെ എല്ലാ ഡാറ്റയും മായ്ക്കുകയോ ചെയ്യുക."</string>      <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"സ്ക്രീൻ അൺലോക്ക് ചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പ് ചെയ്ത പാസ്വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുകയും നിരവധി തവണ തെറ്റായ പാസ്വേഡുകൾ ടൈപ്പ് ചെയ്തിട്ടുണ്ടെങ്കിൽ നിങ്ങളുടെ Android TV ലോക്ക് ചെയ്യുകയോ Android TV-യിലെ എല്ലാ ഡാറ്റയും മായ്ക്കുകയോ ചെയ്യുക."</string>      <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"സ്ക്രീൻ അൺലോക്ക് ചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പ് ചെയ്ത പാസ്വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുക. നിരവധി തെറ്റായ പാസ്വേഡുകൾ ടൈപ്പ് ചെയ്താൽ, ഇൻഫോറ്റേയിൻമെന്റ് സിസ്റ്റം ലോക്ക് ചെയ്യുകയോ ഇൻഫോറ്റേയിൻമെന്റ് സിസ്റ്റത്തിന്റെ ഡാറ്റ മുഴുവനും മായ്ക്കുകയോ ചെയ്യുക."</string> -    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"സ്ക്രീൻ അൺലോക്കുചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പുചെയ്ത പാസ്വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുക, വളരെയധികം തെറ്റായ പാസ്വ്ഡുകൾ ടൈപ്പുചെയ്തിട്ടുണ്ടെങ്കിൽ ഫോൺ ലോക്കുചെയ്യുകയോ ഫോണിലെ എല്ലാ ഡാറ്റയും മായ്ക്കുകയോചെയ്യുക."</string> +    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"സ്ക്രീൻ അൺലോക്കുചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പുചെയ്ത പാസ്വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുക, വളരെയധികം തെറ്റായ പാസ്വേഡുകൾ ടൈപ്പുചെയ്തിട്ടുണ്ടെങ്കിൽ ഫോൺ ലോക്കുചെയ്യുകയോ ഫോണിലെ എല്ലാ ഡാറ്റയും മായ്ക്കുകയോചെയ്യുക."</string>      <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="automotive" msgid="7180857406058327941">"സ്ക്രീൻ അൺലോക്ക് ചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പ് ചെയ്ത പാസ്വേഡുകളുടെ എണ്ണം നിരീക്ഷിച്ച്, നിരവധി തെറ്റായ പാസ്വേഡുകൾ ടൈപ്പ് ചെയ്താൽ ഇൻഫോറ്റേയിൻമെന്റ് സിസ്റ്റം ലോക്ക് ചെയ്യുകയോ ഈ പ്രൊഫൈലിന്റെ ഡാറ്റ മുഴുവനും മായ്ക്കുകയോ ചെയ്യുക."</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"ടെസ്റ്റ്"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"കമ്മ്യൂണൽ"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ആപ്പ് ഉള്ളടക്കം, അതിന്റെ സുരക്ഷയ്ക്കായി സ്ക്രീൻ പങ്കിടലിൽ നിന്ന് മറച്ചിരിക്കുന്നു"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"സാറ്റലൈറ്റിലേക്ക് സ്വയമേവ കണക്റ്റ് ചെയ്തു"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"മൊബൈലോ വൈഫൈ നെറ്റ്വർക്കോ ഇല്ലാതെ തന്നെ സന്ദേശങ്ങൾ അയയ്ക്കാനും സ്വീകരിക്കാനും നിങ്ങൾക്ക് കഴിയും"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages തുറക്കുക"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index a926e60a02a2..beda8ee3f636 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Туршилт"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Нийтийн"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Аюулгүй байдлын улмаас аппын контентыг дэлгэц хуваалцахаас нуусан"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Хиймэл дагуулд автоматаар холбогдсон"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Та мобайл эсвэл Wi-Fi сүлжээгүйгээр мессеж илгээх болон хүлээн авах боломжтой"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Мессежийг нээх"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index c10b7413fd6a..e8b1b8853d03 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1761,7 +1761,7 @@      <string name="owner_name" msgid="8713560351570795743">"मालक"</string>      <string name="guest_name" msgid="8502103277839834324">"अतिथी"</string>      <string name="error_message_title" msgid="4082495589294631966">"एरर"</string> -    <string name="error_message_change_not_allowed" msgid="843159705042381454">"या बदलास आपल्या प्रशासकाद्वारे अनुमती नाही"</string> +    <string name="error_message_change_not_allowed" msgid="843159705042381454">"या बदलासाठी तुमच्या अॅडमिनची अनुमती नाही"</string>      <string name="app_not_found" msgid="3429506115332341800">"ही क्रिया हाताळण्यासाठी कोणताही ॲप्लिकेशन आढळला नाही"</string>      <string name="revoke" msgid="5526857743819590458">"मागे घ्या"</string>      <string name="mediasize_iso_a0" msgid="7039061159929977973">"ISO A0"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"चाचणी"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"सामुदायिक"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रीन शेअर करताना सुरक्षेसाठी अॅपमधील आशय लपवला आहे"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"उपग्रहाशी आपोआप कनेक्ट केलेले आहे"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"तुम्ही मोबाइल किंवा वाय-फाय नेटवर्कशिवाय मेसेज पाठवू आणि मिळवू शकता"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages उघडा"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 4a4ea8817b94..add32bb4c6e9 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -844,7 +844,7 @@      <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="automotive" msgid="660804547737323300">"Memadam data sistem maklumat hibur 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="policydesc_wipeData" product="default" msgid="8036084184768379022">"Memadam data telefon tanpa amaran dengan melakukan tetapan semula data kilang."</string>      <string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"Padam data profil"</string>      <string name="policylab_wipeData_secondaryUser" product="default" 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> @@ -1517,7 +1517,7 @@      <string name="input_method_binding_label" msgid="1166731601721983656">"Kaedah input"</string>      <string name="sync_binding_label" msgid="469249309424662147">"Penyegerakan"</string>      <string name="accessibility_binding_label" msgid="1974602776545801715">"Kebolehaksesan"</string> -    <string name="wallpaper_binding_label" msgid="1197440498000786738">"Kertas dinding"</string> +    <string name="wallpaper_binding_label" msgid="1197440498000786738">"Hiasan latar"</string>      <string name="chooser_wallpaper" msgid="3082405680079923708">"Tukar hiasan latar"</string>      <string name="notification_listener_binding_label" msgid="2702165274471499713">"Pendengar pemberitahuan"</string>      <string name="vr_listener_binding_label" msgid="8013112996671206429">"Pendengar VR"</string> @@ -1726,7 +1726,7 @@      <string name="accessibility_service_warning_description" msgid="291674995220940133">"Kawalan penuh sesuai untuk apl yang membantu anda berkaitan dengan keperluan kebolehaksesan tetapi bukan untuk kebanyakan apl."</string>      <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Melihat dan mengawal skrin"</string>      <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Ciri ini boleh membaca semua kandungan pada skrin dan memaparkan kandungan di atas apl lain."</string> -    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Lihat dan laksanakan tindakan"</string> +    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Melihat dan melaksanakan tindakan"</string>      <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Ciri ini boleh menjejaki interaksi anda dengan apl atau penderia perkakasan dan berinteraksi dengan apl bagi pihak anda."</string>      <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Benarkan"</string>      <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Tolak"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Ujian"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Umum"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Kandungan apl disembunyikan daripada perkongsian skrin untuk keselamatan"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Disambungkan secara automatik kepada satelit"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Anda boleh menghantar dan menerima mesej tanpa rangkaian mudah alih atau Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Buka Messages"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 834613414a31..3de8fb544ac8 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -995,7 +995,7 @@      <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_storage_locked" msgid="634993789186443380">"ဝန်ဆောင်မှုနှင့် ဒေတာအားလုံးအတွက် လော့ခ်ဖွင့်ပါ"</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="1229301273156907613">"ဆင်းမ်ကတ် မရှိပါ"</string>      <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"တက်ဘလက်တွင် ဆင်းမ်ကတ်မရှိပါ။"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"စမ်းသပ်မှု"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"အများသုံး"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"အက်ပ်အကြောင်းအရာသည် လုံခြုံရေးအတွက် မျက်နှာပြင် မျှဝေခြင်းမှ ဖျောက်ထားသည်"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"ဂြိုဟ်တုနှင့် အလိုအလျောက် ချိတ်ဆက်ထားသည်"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"မိုဘိုင်း (သို့) Wi-Fi ကွန်ရက်မရှိဘဲ မက်ဆေ့ဂျ်များကို ပို့နိုင်၊ လက်ခံနိုင်သည်"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ဖွင့်ရန်"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 252b4138d8f0..b380199b3c36 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Felles"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av sikkerhetsgrunner er appinnholdet skjult for skjermdelingen"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automatisk tilkoblet satellitt"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Du kan sende og motta meldinger uten mobil- eller wifi-nettverk"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Åpne Meldinger"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 6035bb19312d..a4867974c880 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -340,7 +340,7 @@      <string name="permgrouplab_sensors" msgid="9134046949784064495">"बडी सेन्सरहरू"</string>      <string name="permgroupdesc_sensors" msgid="2610631290633747752">"तपाईंको महत्त्वपूर्ण संकेत बारे सेन्सर डेटा पहुँच गर्नुहोस्"</string>      <string name="permgrouplab_notifications" msgid="5472972361980668884">"सूचनाहरू"</string> -    <string name="permgroupdesc_notifications" msgid="4608679556801506580">"सूचनाहरू देखाइयोस्"</string> +    <string name="permgroupdesc_notifications" msgid="4608679556801506580">"सूचनाहरू देखाउनुहोस्"</string>      <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"विन्डो सामग्रीको पुनःबहाली गर्नुहोस्।"</string>      <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"तपाईँको अन्तरक्रिया भइरहेको विन्डोको सामग्रीको निरीक्षण गर्नुहोस्।"</string>      <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"छोएर गरिने खोजलाई सुचारु गर्नुहोस्"</string> @@ -362,7 +362,7 @@      <string name="permdesc_statusBarService" msgid="6652917399085712557">"एपलाई स्थिति पट्टि हुन अनुमति दिन्छ।"</string>      <string name="permlab_expandStatusBar" msgid="1184232794782141698">"स्थिति पट्टिलाई विस्तृत/सङ्कुचित गर्नुहोस्"</string>      <string name="permdesc_expandStatusBar" msgid="7180756900448498536">"एपलाई स्थिति पट्टि विस्तार वा संकुचन गर्न अनुमति दिन्छ।"</string> -    <string name="permlab_fullScreenIntent" msgid="4310888199502509104">"लक गरिएको डिभाइसमा स्क्रिनभरि देखिने सूचनाहरू देखाइयोस्"</string> +    <string name="permlab_fullScreenIntent" msgid="4310888199502509104">"लक गरिएको डिभाइसमा स्क्रिनभरि देखिने सूचनाहरू देखाउनुहोस्"</string>      <string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"यो अनुमति दिइएमा एपले लक गरिएको डिभाइसमा स्क्रिनभरि देखिने सूचनाहरू देखाउन सक्छ"</string>      <string name="permlab_install_shortcut" msgid="7451554307502256221">"सर्टकट इन्स्टल गर्ने"</string>      <string name="permdesc_install_shortcut" msgid="4476328467240212503">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा हाल्ने अनुमति दिन्छ।"</string> @@ -395,7 +395,7 @@      <string name="permlab_receiveWapPush" msgid="4223747702856929056">"टेक्स्ट म्यासेजहरू (WAP) प्राप्त गर्नुहोस्"</string>      <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP म्यासेजहरू प्राप्त गर्न र प्रशोधन गर्न एपलाई अनुमति दिन्छ। यो अनुमतिमा मोनिटर गर्ने वा तपाईँलाई पठाइएका म्यासेजहरू तपाईँलाई नदेखाई मेट्ने क्षमता समावेश हुन्छ।"</string>      <string name="permlab_getTasks" msgid="7460048811831750262">"चलिरहेका एपहरू पुनःबहाली गर्नुहोस्"</string> -    <string name="permdesc_getTasks" msgid="7388138607018233726">"वर्तमानमा र भरखरै चलिरहेका कार्यहरू बारेको सूचना पुनःबहाली गर्न एपलाई अनुमित दिन्छ। यसले उपकरणमा प्रयोग भएका अनुप्रयोगहरूको बारेमा सूचना पत्ता लगाउन एपलाई अनुमति दिन सक्छ।"</string> +    <string name="permdesc_getTasks" msgid="7388138607018233726">"वर्तमानमा र भरखरै चलिरहेका कार्यहरू बारेको सूचना पुनःबहाली गर्न एपलाई अनुमित दिन्छ। यसले उपकरणमा प्रयोग भएका एपहरूको बारेमा सूचना पत्ता लगाउन एपलाई अनुमति दिन सक्छ।"</string>      <string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"प्रोफाइल र यन्त्र मालिकहरूको व्यवस्थापन गराउनुहोस्"</string>      <string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"एपहरूलाई प्रोफाइल र यन्त्र मालिकहरू सेट गर्ने अनुमति दिनुहोस्।"</string>      <string name="permlab_reorderTasks" msgid="7598562301992923804">"चलिरहेका एपहरूलाई पुनःक्रम गराउनुहोस्"</string> @@ -403,7 +403,7 @@      <string name="permlab_enableCarMode" msgid="893019409519325311">"कार मोड सक्षम गर्नुहोस्"</string>      <string name="permdesc_enableCarMode" msgid="56419168820473508">"कार मोडलाई सक्षम पार्न एपलाई अनुमति दिन्छ।"</string>      <string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"एपहरू बन्द गर्नुहोस्"</string> -    <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"एपलाई अन्य अनुप्रयोगहरूको पृष्ठभूमि प्रक्रियाहरू बन्द गर्न अनुमति दिन्छ। यसले अन्य एपहरूलाई चल्नबाट रोक्न सक्दछ।"</string> +    <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"एपलाई अन्य एपहरूको पृष्ठभूमि प्रक्रियाहरू बन्द गर्न अनुमति दिन्छ। यसले अन्य एपहरूलाई चल्नबाट रोक्न सक्दछ।"</string>      <string name="permlab_systemAlertWindow" msgid="5757218350944719065">"यो एप अन्य एपहरूमाथि देखा पर्न सक्छ"</string>      <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"यो एप अन्य एपहरूमाथि वा स्क्रिनका अन्य भागहरूमा देखा पर्न सक्छ। यसले एपको सामान्य प्रयोगमा अवरोध पुर्याउन सक्छ र अन्य एपहरू देखा पर्ने तरिकालाई परिवर्तन गर्न सक्छ।"</string>      <string name="permlab_hideOverlayWindows" msgid="6382697828482271802">"एपका अन्य ओभरलेहरू लुकाउने अनुमति"</string> @@ -452,7 +452,7 @@      <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"यसले एपलाई \"specialUse\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</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> @@ -476,9 +476,9 @@      <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"आगमन तथा बहर्गमन डेटासहित तपाईँको ट्याब्लेटको कल लगको परिमार्जन गर्न एपलाई अनुमति दिन्छ। खराब एपहरूले यसलाई तपाईँको कल लग परिमार्जन गर्न वा मेटाउन प्रयोग गर्न सक्छन्।"</string>      <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"एपलाई तपाईंको Android टिभी डिभाइसको आगमन र बहिर्गमन कलसम्बन्धी डेटासहित कल लग परिमार्जन गर्ने अनुमति दिन्छ। हानिकारक एपहरूले यसलाई तपाईंको कल लग मेटाउन वा परिमार्जन गर्न प्रयोग गर्न सक्छन्।"</string>      <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"एपलाई तपाईंको फोनको आउने र बाहिर जाने कलहरूको बारेको डेटा सहित कल लग परिमार्जन गर्न अनुमति दिन्छ। खराब एपहरूले यसलाई तपाईंको कल लग मेटाउन वा परिमार्जन गर्न प्रयोग गर्न सक्दछ।"</string> -    <string name="permlab_bodySensors" msgid="662918578601619569">"प्रयोग गरिएका बेला हृदयको गति जस्ता बडी सेन्सरसम्बन्धी डेटा हेरियोस् र प्रयोग गरियोस्"</string> +    <string name="permlab_bodySensors" msgid="662918578601619569">"प्रयोग गरिएका बेला हृदयको गति जस्ता बडी सेन्सरसम्बन्धी डेटा हेरियोस् र प्रयोग गर्नुहोस्"</string>      <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"यसले यो एप प्रयोग गरिँदै गरेका बेला यसलाई हृदयको गति, शरीरको तापक्रम तथा रगतमा रहेको अक्सिजनको प्रतिशत जस्ता बडी सेन्सरसम्बन्धी डेटा हेर्ने तथा प्रयोग गर्ने अनुमति दिन्छ।"</string> -    <string name="permlab_bodySensors_background" msgid="4912560779957760446">"ब्याकग्राउन्डमा चलेका बेला हृदयको गति जस्ता बडी सेन्सरसम्बन्धी डेटा हेरियोस् र प्रयोग गरियोस्"</string> +    <string name="permlab_bodySensors_background" msgid="4912560779957760446">"ब्याकग्राउन्डमा चलेका बेला हृदयको गति जस्ता बडी सेन्सरसम्बन्धी डेटा हेरियोस् र प्रयोग गर्नुहोस्"</string>      <string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"यसले यो एप ब्याकग्राउन्डमा चलेका बेला यसलाई हृदयको गति, शरीरको तापक्रम तथा रगतमा रहेको अक्सिजनको प्रतिशत जस्ता बडी सेन्सरसम्बन्धी डेटा हेर्ने तथा प्रयोग गर्ने अनुमति दिन्छ।"</string>      <string name="permlab_readCalendar" msgid="6408654259475396200">"पात्रोका कार्यक्रम र विवरणहरू पढ्ने"</string>      <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"यस एपले तपाईंको ट्याब्लेटमा भण्डारण गरिएका पात्रो सम्बन्धी सबै कार्यक्रमहरू पढ्न र तपाईंको पात्रोको डेटा आदान प्रदान वा सुरक्षित गर्न सक्छ।"</string> @@ -615,7 +615,7 @@      <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"कुनै सम्बन्धित पासवर्ड सुरक्षा र किलकलाई असक्षम पार्न एपलाई अनुमति दिन्छ। उदाहरणको लागि, अन्तर्गमन फोन कल प्राप्त गर्दा फोनले किलकलाई असक्षम पार्छ, त्यसपछि कल सकिएको बेला किलक पुनःसक्षम पार्छ।"</string>      <string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"स्क्रिन लकको जटिलतासम्बन्धी जानकारी प्राप्त गर्ने अनुरोध गर्नुहोस्"</string>      <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"यसले एपलाई स्क्रिन लकको जटिलताको स्तर (उच्च, मध्यम, न्यून वा कुनै पनि होइन) थाहा पाउने अनुमति दिन्छ जसले स्क्रिन लकको लम्बाइको सम्भावित दायरा र त्यसको प्रकारलाई जनाउँछ। यसै गरी, यो एपले प्रयोगकर्ताहरूलाई स्क्रिन लक अद्यावधिक गर्ने सुझाव पनि दिन सक्छ तर प्रयोगकर्ताहरू उक्त सुझावको बेवास्ता गरी बाहिर निस्कन सक्छन्। स्क्रिन लक सादा पाठको ढाँचामा भण्डारण नगरिने हुँदा यो एपलाई वास्तविक पासवर्ड थाहा नहुने कुराको हेक्का राख्नुहोस्।"</string> -    <string name="permlab_postNotification" msgid="4875401198597803658">"सूचनाहरू देखाइयोस्"</string> +    <string name="permlab_postNotification" msgid="4875401198597803658">"सूचनाहरू देखाउनुहोस्"</string>      <string name="permdesc_postNotification" msgid="5974977162462877075">"यो एपलाई सूचना देखाउन दिनुहोस्"</string>      <string name="permlab_turnScreenOn" msgid="219344053664171492">"स्क्रिन अन गर्ने"</string>      <string name="permdesc_turnScreenOn" msgid="4394606875897601559">"यो एपलाई स्क्रिन अन गर्ने अनुमति दिन्छ।"</string> @@ -782,35 +782,35 @@      <string name="permlab_control_incall_experience" msgid="6436863486094352987">"आउने-कल प्रयोगकर्ता अनुभव प्रदान गर्नुहोस्"</string>      <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"एपलाई आउने-कल प्रयोगकर्ता अनुभव प्रदान गर्न अनुमति दिन्छ।"</string>      <string name="permlab_readNetworkUsageHistory" msgid="8470402862501573795">"नेटवर्क उपयोगको इतिहास पढ्नुहोस्"</string> -    <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"निश्चित नेटवर्कहरू र अनुप्रयोगहरूको लागि ऐतिहासिक नेटवर्क उपयोग पढ्नको लागि एपलाई अनुमति दिन्छ।"</string> +    <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"निश्चित नेटवर्कहरू र एपहरूको लागि ऐतिहासिक नेटवर्क उपयोग पढ्नको लागि एपलाई अनुमति दिन्छ।"</string>      <string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"नेटवर्क नीति प्रबन्ध गर्नुहोस्"</string>      <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"नेटवर्क नीतिहरू व्यवस्थापन गर्न र एप-विशेष नियमहरू परिभाषित गर्न एपलाई अनुमति दिन्छ।"</string>      <string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"नेटवर्क उपयोग लेखालाई परिमार्जन गर्नुहोस्"</string> -    <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"एपलाई कसरी अनुप्रयोगहरूको विरूद्धमा कसरी नेटवर्क उपयोगी अकाउन्टेड छ भनेर परिमार्जन गर्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूद्वारा प्रयोगको लागि होइन।"</string> +    <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"एपलाई कसरी एपहरूको विरूद्धमा कसरी नेटवर्क उपयोगी अकाउन्टेड छ भनेर परिमार्जन गर्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूद्वारा प्रयोगको लागि होइन।"</string>      <string name="permlab_accessNotifications" msgid="7130360248191984741">"सूचनाहरू पहुँच गर्नुहोस्"</string>      <string name="permdesc_accessNotifications" msgid="761730149268789668">"अन्य एपहरूबाट पोस्ट गरिएकासहित पुनःप्राप्त गर्न, परीक्षण गर्न र सूचनाहरू हटाउन एपहरूलाई अनुमति दिन्छ।"</string>      <string name="permlab_bindNotificationListenerService" msgid="5848096702733262458">"जानकारी श्रोता सेवामा बाँध्नुहोस्"</string>      <string name="permdesc_bindNotificationListenerService" msgid="4970553694467137126">"होल्डरलाई सूचना श्रोता सेवाको शीर्ष-स्तरको इन्टरफेस बाँध्न अनुमति दिन्छ। सामान्य एपहरूलाई कहिले पनि आवश्यक नपर्न सक्दछ।"</string>      <string name="permlab_bindConditionProviderService" msgid="5245421224814878483">"सर्त प्रदायक सेवामा जोड्न"</string> -    <string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"सर्त प्रदायक सेवाको माथिल्लो स्तरको इन्टरफेसमा जोड्न बाहकलाई अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string> +    <string name="permdesc_bindConditionProviderService" msgid="6106018791256120258">"सर्त प्रदायक सेवाको माथिल्लो स्तरको इन्टरफेसमा जोड्न बाहकलाई अनुमति दिन्छ। साधारण एपहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>      <string name="permlab_bindDreamService" msgid="4776175992848982706">"सपना सेवामा बाँध्नुहोस्"</string> -    <string name="permdesc_bindDreamService" msgid="9129615743300572973">"होल्डरलाई सपना सेवाको माथिल्लो स्तरको इन्टरफेसमा बाँध्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string> +    <string name="permdesc_bindDreamService" msgid="9129615743300572973">"होल्डरलाई सपना सेवाको माथिल्लो स्तरको इन्टरफेसमा बाँध्न अनुमति दिन्छ। साधारण एपहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>      <string name="permlab_invokeCarrierSetup" msgid="5098810760209818140">"वाहक-प्रदान विन्यास एप सुरु गर्नुहोस्"</string>      <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"प्रयोगकर्तालाई वाहक-प्रदान विन्यास एप सुरु गर्न अनुमति दिन्छ। साधारण एपहरूलाई कहिल्यै आवश्यक पर्ने छैन।"</string>      <string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"सञ्जाल अवस्थाका पर्यवेक्षणका लागि सुन्नुहोस्"</string>      <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"सञ्जाल अवस्थाका पर्यवेक्षण सुन्नका लागि एपलाई अनुमति दिन्छ।सामान्य एपलाई चाँहिदै नचाँहिन सक्छ।"</string> -    <string name="permlab_setInputCalibration" msgid="932069700285223434">"इनपुट उपकरण क्यालिब्रेसन परिवर्तन गर्नुहोस्"</string> -    <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"एपलाई टच स्क्रीनको प्यारामिटरहरू क्यालिब्रेसन परिमार्जन गर्न अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै आवश्यक पर्दैन।"</string> +    <string name="permlab_setInputCalibration" msgid="932069700285223434">"इनपुट डिभाइस क्यालिब्रेसन परिवर्तन गर्नुहोस्"</string> +    <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"एपलाई टच स्क्रीनको प्यारामिटरहरू क्यालिब्रेसन परिमार्जन गर्न अनुमति दिन्छ। साधारण एपहरूको लागि कहिल्यै आवश्यक पर्दैन।"</string>      <string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"DRM प्रमाणपत्रको पहुँच"</string> -    <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"DRM प्रमाणपत्रहरू प्रावधान र प्रयोग गर्ने निवेदनको अनुमति दिन्छ। साधारण अनुप्रयोगहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string> +    <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"DRM प्रमाणपत्रहरू प्रावधान र प्रयोग गर्ने निवेदनको अनुमति दिन्छ। साधारण एपहरूको लागि कहिल्यै पनि आवश्यक पर्दैन।"</string>      <string name="permlab_handoverStatus" msgid="7620438488137057281">"Android Beam स्थानान्तरण अवस्था प्राप्त गर्नुहोस्"</string>      <string name="permdesc_handoverStatus" msgid="3842269451732571070">"यस आवेदनले वर्तमान Android Beam स्थानान्तरण बारेमा जानकारी प्राप्त गर्न अनुमति दिन्छ"</string>      <string name="permlab_removeDrmCertificates" msgid="710576248717404416">"DRM सर्टिफिकेट हटाउनुहोस्"</string> -    <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM प्रमाणपत्रहरू हटाउन एपलाई अनुमति दिन्छ। सामान्य अनुप्रयोगहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string> +    <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM प्रमाणपत्रहरू हटाउन एपलाई अनुमति दिन्छ। सामान्य एपहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>      <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"वाहक मेसेजिङ सेवामा आबद्ध हुनुहोस्"</string>      <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"धारकलाई वाहक मेसेजिङ सेवाको उच्च-स्तरको इन्टरफेसमा आबद्ध हुन अनुमति दिनुहोस्। सामान्य एपहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>      <string name="permlab_bindCarrierServices" msgid="2395596978626237474">"वाहक सेवाहरु बाँध्न"</string> -    <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"होल्डरलाई वाहक सेवाहरु बाँध्न अनुमति दिनुहोस्। सामान्य अनुप्रयोगहरूको लागि यो कहिल्यै आवश्यक पर्दैन।"</string> +    <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"होल्डरलाई वाहक सेवाहरु बाँध्न अनुमति दिनुहोस्। सामान्य एपहरूको लागि यो कहिल्यै आवश्यक पर्दैन।"</string>      <string name="permlab_access_notification_policy" msgid="5524112842876975537">"बाधा नपुर्याउँनुहोस् पहुँच गर्नुहोस्"</string>      <string name="permdesc_access_notification_policy" msgid="8538374112403845013">"बाधा नपुर्याउँनुहोस् कन्फिगरेसन पढ्न र लेख्नको लागि एपलाई अनुमति दिनुहोस्।"</string>      <string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"हेर्ने अनुमतिको प्रयोग सुरु गर्नुहोस्"</string> @@ -821,7 +821,7 @@      <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"होल्डरलाई एपका सुविधासम्बन्धी जानकारी हेर्न दिन्छ।"</string>      <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"नमुना लिने उच्च दरमा सेन्सरसम्बन्धी डेटा प्रयोग गर्ने"</string>      <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"यो अनुमति दिइएमा एपले २०० हर्जभन्दा बढी दरमा सेन्सरसम्बन्धी डेटाको नमुना लिन सक्छ"</string> -    <string name="permlab_updatePackagesWithoutUserAction" msgid="3363272609642618551">"एप स्वतः अपडेट गरियोस्"</string> +    <string name="permlab_updatePackagesWithoutUserAction" msgid="3363272609642618551">"एप स्वतः अपडेट गर्नुहोस्"</string>      <string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"तपाईंले यो अनुमति दिनुभयो भने होल्डरले पहिले नै इन्स्टल गरेको एप स्वतः अपडेट गर्न पाउँछ"</string>      <string name="permlab_writeVerificationStateE2eeContactKeys" msgid="3990742344778360457">"अन्य एपको स्वामित्वमा रहेका E2EE कन्ट्याक्ट कीहरूको प्रमाणीकरणको स्थिति अपडेट गर्ने"</string>      <string name="permdesc_writeVerificationStateE2eeContactKeys" msgid="8453156829747427041">"यसले एपलाई अन्य एपको स्वामित्वमा रहेका E2EE कन्ट्याक्ट कीहरूको प्रमाणीकरणको स्थिति अपडेट गर्न दिन्छ"</string> @@ -830,11 +830,11 @@      <string name="policylab_watchLogin" msgid="7599669460083719504">"स्क्रिन अनलक गर्न गरिएको प्रयासको अनुगमन गर्ने"</string>      <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप भएको संख्या निरीक्षण गर्नुहोस् र यदि निकै धेरै गलत पासवर्डहरू टाइप भएका छन भने ट्याब्लेट लक गर्नुहोस् वा ट्याब्लेटका सबै डेटा मेट्नुहोस्।"</string>      <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप गरेको सङ्ख्या निरीक्षण गर्नुहोस्, र धेरै पटक गलत पासवर्डहरू टाइप गरिएको खण्डमा आफ्नो Android टिभी यन्त्र लक गर्नुहोस् वा डिभाइसमा भएको सम्पूर्ण डेटा मेटाउनुहोस्।"</string> -    <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"स्क्रिन अनलक गर्दा कति पटक गलत पासवर्ड टाइप गरिन्छ भन्ने कुरा निगरानी गरियोस् र अत्यन्तै धेरै पटक गलत पासवर्ड टाइप गरिएका खण्डमा यो इन्फोटेनमेन्ट प्रणाली लक गरियोस् वा यस इन्फोटेनमेन्ट प्रणालीका सबै डेटा मेटाइयोस्।"</string> +    <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"स्क्रिन अनलक गर्दा कति पटक गलत पासवर्ड टाइप गरिन्छ भन्ने कुरा निगरानी गर्नुहोस् र अत्यन्तै धेरै पटक गलत पासवर्ड टाइप गरिएका खण्डमा यो इन्फोटेनमेन्ट प्रणाली लक गर्नुहोस् वा यस इन्फोटेनमेन्ट प्रणालीका सबै डेटा मेटाउनुहोस्।"</string>      <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"स्क्रिन अनलक गर्दा कति पटक गलत पासवर्ड टाइप भएको छ हेर्नुहोस् र निकै धेरै पटक गलत पासवर्ड टाइप भएको भने फोन लक गर्नुहोस् वा फोनका सबै डेटा मेट्नुहोस्।"</string>      <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप संख्या अनुगमन गर्नुहोस्, र यदि निकै धेरै गलत पासवर्डहरू टाइप गरिएमा ट्याब्लेट लक गर्नुहोस् वा प्रयोगकर्ताको डेटा मेटाउनुहोस्।"</string>      <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप गरेको सङ्ख्या निरीक्षण गर्नुहोस्, र धेरै पटक गलत पासवर्डहरू टाइप गरिएको खण्डमा आफ्नो Android टिभी यन्त्र लक गर्नुहोस् वा यो प्रयोगकर्ताको सम्पूर्ण डेटा मेटाउनुहोस्।"</string> -    <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"स्क्रिन अनलक गर्दा कति पटक गलत पासवर्ड टाइप गरिन्छ भन्ने कुरा निगरानी गरियोस् र अत्यन्तै धेरै पटक गलत पासवर्ड टाइप गरिएका खण्डमा यो इन्फोटेनमेन्ट प्रणाली लक गरियोस् वा यस प्रोफाइलका सबै डेटा मेटाइयोस्।"</string> +    <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"स्क्रिन अनलक गर्दा कति पटक गलत पासवर्ड टाइप गरिन्छ भन्ने कुरा निगरानी गर्नुहोस् र अत्यन्तै धेरै पटक गलत पासवर्ड टाइप गरिएका खण्डमा यो इन्फोटेनमेन्ट प्रणाली लक गर्नुहोस् वा यस प्रोफाइलका सबै डेटा मेटाउनुहोस्।"</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> @@ -843,13 +843,13 @@      <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 टिभी डिभाइसको डेटा मेटाउनुहोस्।"</string> -    <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"यो इन्फोटेनमेन्ट प्रणालीको डेटा कुनै चेतावनीविनै फ्याक्ट्री डेटा रिसेट गरेर मेटाइयोस्।"</string> -    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"फ्याक्ट्रूी रिसेट गरेर चेतावनी नदिइकन फोनको डेटा मेट्न।"</string> -    <string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"प्रोफाइल डेटा मेटाइयोस्"</string> +    <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"यो इन्फोटेनमेन्ट प्रणालीको डेटा कुनै चेतावनीविनै फ्याक्ट्री डेटा रिसेट गरेर मेटाउनुहोस्।"</string> +    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"फ्याक्ट्रूी रिसेट गरेर चेतावनी नदिइकन फोनको डेटा मेट्नुहोस्।"</string> +    <string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"प्रोफाइल डेटा मेटाउनुहोस्"</string>      <string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"प्रयोगकर्ता डेटा मेट्नुहोस्"</string>      <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"चेतावनी बिना यो ट्याब्लेटमा यस प्रयोगकर्ताको डेटा मेट्नुहोस्।"</string>      <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"यो Android टिभी डिभाइसमा भएको यस प्रयोगकर्ताको डेटा चेतावनी नदिइकन मेटाउनुहोस्।"</string> -    <string name="policydesc_wipeData_secondaryUser" product="automotive" msgid="4658832487305780879">"यो इन्फोटेनमेन्ट प्रणालीमा भएको यस प्रोफाइलको डेटा कुनै चेतावनीविनै मेटाइयोस्।"</string> +    <string name="policydesc_wipeData_secondaryUser" product="automotive" msgid="4658832487305780879">"यो इन्फोटेनमेन्ट प्रणालीमा भएको यस प्रोफाइलको डेटा कुनै चेतावनीविनै मेटाउनुहोस्।"</string>      <string name="policydesc_wipeData_secondaryUser" product="default" msgid="2788325512167208654">"चेतावनी बिना यो फोनमा यस प्रयोगकर्ताको डेटा मेट्नुहोस्।"</string>      <string name="policylab_setGlobalProxy" msgid="215332221188670221">"उपकरण विश्वव्यापी प्रोक्सी मिलाउनुहोस्"</string>      <string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"नीति सक्षम हुँदा प्रयोग गरिनको लागि यन्त्र ग्लोवल प्रोक्सी सेट गर्नुहोस्। केवल यन्त्र मालिकले ग्लोवल प्रोक्सी सेट गर्न सक्नुहुन्छ।"</string> @@ -1405,7 +1405,7 @@      <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> -    <string name="console_running_notification_message" msgid="7892751888125174039">"कार्यसम्पादनमा प्रभाव परेको छ। यसलाई असक्षम पार्न बुटलोडरको जाँच गर्नुहोस्।"</string> +    <string name="console_running_notification_message" msgid="7892751888125174039">"पर्फर्मेन्समा प्रभाव परेको छ। यसलाई असक्षम पार्न बुटलोडरको जाँच गर्नुहोस्।"</string>      <string name="mte_override_notification_title" msgid="4731115381962792944">"परीक्षणका क्रममा रहेको MTE अन गरियो"</string>      <string name="mte_override_notification_message" msgid="2441170442725738942">"पर्फर्मेन्स र स्थिरता प्रभावित हुन सक्छ। अफ गर्न रिबुट गर्नुहोस्। तपाईंले arm64.memtag.bootctl प्रयोग गरी अन गर्नुभएको थियो भने अफ गर्नुअघि यसलाई परिवर्तन गरी \"कुनै पनि होइन\" बनाउनुहोस्।"</string>      <string name="usb_contaminant_detected_title" msgid="4359048603069159678">"USB पोर्टमा तरल पदार्थ वा धुलो भएको कुरा पत्ता लाग्यो"</string> @@ -1419,14 +1419,14 @@      <string name="share_remote_bugreport_action" msgid="7630880678785123682">"सेयर गर्नुहोस्"</string>      <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"अस्वीकार गर्नुहोस्"</string>      <string name="select_input_method" msgid="3971267998568587025">"निवेश विधि छान्नुहोस्"</string> -    <string name="show_ime" msgid="6406112007347443383">"फिजिकल किबोर्ड सक्रिय हुँदा यसलाई स्क्रिनमा राखियोस्"</string> +    <string name="show_ime" msgid="6406112007347443383">"फिजिकल किबोर्ड सक्रिय हुँदा यसलाई स्क्रिनमा राख्नुहोस्"</string>      <string name="hardware" msgid="3611039921284836033">"अनस्क्रिन किबोर्ड प्रयोग गर्नुहोस्"</string>      <string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> कन्फिगर गर्नुहोस्"</string>      <string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"भौतिक किबोर्डहरू कन्फिगर गर्नुहोस्"</string>      <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> @@ -1718,11 +1718,11 @@      <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>      <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<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_shortcut_on" msgid="5463618449556111344">"सक्रिय गर्नुहोस्"</string> +    <string name="accessibility_shortcut_off" msgid="3651336255403648739">"सक्रिय नगर्नुहोस्"</string>      <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"सक्रिय"</string>      <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"निष्क्रिय"</string> -    <string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> लाई तपाईंको यन्त्र पूर्ण रूपमा नियन्त्रण गर्न दिने हो?"</string> +    <string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> लाई तपाईंको डिभाइस पूर्ण रूपमा नियन्त्रण गर्न दिने हो?"</string>      <string name="accessibility_service_warning_description" msgid="291674995220940133">"एक्सेसिबिलिटीसम्बन्धी आवश्यकतामा सहयोग गर्ने एपको पूर्ण नियन्त्रण गर्न दिनु उपयुक्त हुन्छ तर अधिकांश एपका हकमा यस्तो नियन्त्रण उपयुक्त हुँदैन।"</string>      <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"स्क्रिन हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>      <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"यसले स्क्रिनमा देखिने सबै सामग्री पढ्न सक्छ र अन्य एपहरूमा उक्त सामग्री देखाउन सक्छ।"</string> @@ -1741,10 +1741,10 @@      <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"सर्टकटलाई निष्क्रिय पार्नुहोस्"</string>      <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"सर्टकट प्रयोग गर्नुहोस्"</string>      <string name="color_inversion_feature_name" msgid="2672824491933264951">"कलर इन्भर्सन"</string> -    <string name="color_correction_feature_name" msgid="7975133554160979214">"रङ सच्याउने सुविधा"</string> +    <string name="color_correction_feature_name" msgid="7975133554160979214">"कलर करेक्सन"</string>      <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"एक हाते मोड"</string>      <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"अझै मधुरो"</string> -    <string name="hearing_aids_feature_name" msgid="1125892105105852542">"श्रवण यन्त्रहरू"</string> +    <string name="hearing_aids_feature_name" msgid="1125892105105852542">"हियरिङ डिभाइसहरू"</string>      <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="3760999147597564314">"भोल्युम बटनहरू थिच्न छाड्नुहोस्। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> अन गर्न दुवै भोल्युम बटन फेरि ३ सेकेन्डसम्म थिचिराख्नुहोस्।"</string> @@ -2167,7 +2167,7 @@      <string name="car_loading_profile" msgid="8219978381196748070">"लोड गर्दै"</string>      <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # फाइल}other{{file_name} + # वटा फाइल}}"</string>      <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"कुनै पनि व्यक्तिसँग सेयर गर्ने सिफारिस गरिएको छैन"</string> -    <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"अनुप्रयोगहरूको सूची"</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>      <string name="accessibility_system_action_back_label" msgid="4205361367345537608">"पछाडि फर्कनुहोस्"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"परीक्षण"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"सामुदायिक"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रिन सेयर गर्दा सुरक्षाका लागि एपमा भएको सामग्री लुकाइएको छ"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"स्याटलाइटमा स्वतः कनेक्ट गरियो"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"तपाईं मोबाइल वा Wi-Fi नेटवर्कविनै म्यासेज पठाउन र प्राप्त गर्न सक्नुहुन्छ"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages खोल्नुहोस्"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 5870ca36e92c..098162320d17 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -830,12 +830,12 @@      <string name="policylab_watchLogin" msgid="7599669460083719504">"Pogingen voor schermontgrendeling bijhouden"</string>      <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en de tablet vergrendelen of alle gegevens op de tablet wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string>      <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en het Android TV-apparaat vergrendelen of alle gegevens van het Android TV-apparaat wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string> -    <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Bijhouden hoe vaak onjuiste wachtwoorden worden getypt als het scherm wordt ontgrendeld, en het infotainmentsysteem vergrendelen of alle gegevens op het infotainmentsysteem wissen als te veel onjuiste wachtwoorden worden getypt."</string> +    <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld, en het infotainmentsysteem vergrendelen of alle gegevens op het infotainmentsysteem wissen bij te veel onjuiste wachtwoorden."</string>      <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en de telefoon vergrendelen of alle gegevens op de telefoon wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string>      <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en de tablet vergrendelen of alle gegevens van deze gebruiker wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string>      <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en het Android TV-apparaat vergrendelen of alle gegevens van deze gebruiker wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string> -    <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Bijhouden hoe vaak onjuiste wachtwoorden worden getypt als het scherm wordt ontgrendeld, en het infotainmentsysteem vergrendelen of alle gegevens van dit profiel wissen als te veel onjuiste wachtwoorden worden getypt."</string> -    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en de telefoon vergrendelen of alle gegevens van deze gebruiker wissen als te veel onjuiste wachtwoorden worden ingevoerd."</string> +    <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd als het scherm wordt ontgrendeld, en het infotainmentsysteem vergrendelen of alle gegevens van dit profiel wissen bij te veel onjuiste wachtwoorden."</string> +    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Bijhouden hoe vaak onjuiste wachtwoorden worden ingevoerd wanneer het scherm wordt ontgrendeld en de telefoon vergrendelen of alle gegevens van deze gebruiker wissen bij te veel onjuiste wachtwoorden."</string>      <string name="policylab_resetPassword" msgid="214556238645096520">"De schermvergrendeling wijzigen"</string>      <string name="policydesc_resetPassword" msgid="4626419138439341851">"Wijzig de schermvergrendeling."</string>      <string name="policylab_forceLock" msgid="7360335502968476434">"Het scherm vergrendelen"</string> @@ -1902,7 +1902,7 @@      <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>      <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, bepaalde visuele effecten, bepaalde functies en sommige netwerkverbindingen beperkt of uitgezet."</string>      <string name="battery_saver_description" msgid="8518809702138617167">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, bepaalde visuele effecten, bepaalde functies en sommige netwerkverbindingen beperkt of uitgezet."</string> -    <string name="data_saver_description" msgid="4995164271550590517">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens sturen of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden dan bijvoorbeeld niet getoond totdat je erop tikt."</string> +    <string name="data_saver_description" msgid="4995164271550590517">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens sturen of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden bijvoorbeeld pas getoond als je erop tikt."</string>      <string name="data_saver_enable_title" msgid="7080620065745260137">"Databesparing aanzetten?"</string>      <string name="data_saver_enable_button" msgid="4399405762586419726">"Aanzetten"</string>      <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Gedurende 1 minuut (tot {formattedTime})}other{Gedurende # minuten (tot {formattedTime})}}"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Gemeenschappelijk"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App-content verborgen voor scherm delen vanwege beveiligingsrisico\'s"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automatisch verbonden met satelliet"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Je kunt berichten sturen en krijgen zonder een mobiel of wifi-netwerk"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Berichten openen"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 4174d04cf1d1..8b49e6c09a81 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -831,7 +831,7 @@      <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"ସ୍କ୍ରୀନ୍ ଅନଲକ୍ କରିବାବେଳେ ଟାଇପ୍ କରିଥିବା ଭୁଲ ପାସୱର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରେ ଏବଂ ଟାବଲେଟ୍କୁ ଲକ୍ କରିଦିଏ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସୱର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ଟାବଲେଟ୍ର ସମସ୍ତ ଡାଟା ଲିଭାଇଦିଏ।"</string>      <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"ସ୍କ୍ରିନ୍ ଅନ୍ଲକ୍ କରିବା ସମୟରେ ଟାଇପ୍ କରାଯାଇଥିବା ଭୁଲ ପାସ୍ୱାର୍ଡଗୁଡ଼ିକର ସଂଖ୍ୟାକୁ ନିରୀକ୍ଷଣ କରନ୍ତୁ ଏବଂ ଆପଣଙ୍କର Android TV ଡିଭାଇସ୍କୁ ଲକ୍ କରନ୍ତୁ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସ୍ୱାର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ଆପଣଙ୍କ Android TV ଡିଭାଇସ୍ର ସମସ୍ତ ଡାଟା ଲିଭାଇ ଦିଅନ୍ତୁ।"</string>      <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"ସ୍କ୍ରିନ ଅନଲକ କରିବା ସମୟରେ ଟାଇପ କରାଯାଇଥିବା ଭୁଲ ପାସୱାର୍ଡର ସଂଖ୍ୟାକୁ ମନିଟର କରନ୍ତୁ ଏବଂ ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମକୁ ଲକ କରନ୍ତୁ କିମ୍ବା ଯଦି ଅନେକଗୁଡ଼ିଏ ଭୁଲ ପାସୱାର୍ଡ ଟାଇପ କରାଯାଇଥାଏ ତେବେ ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମର ସମସ୍ତ ଡାଟା ଖାଲି କରନ୍ତୁ।"</string> -    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"ଟାଇପ କରାଯାଇଥିବା ଭୁଲ ପାସୱର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରେ। ସ୍କ୍ରିନ ଅନଲକ କରିବାବେଳେ ଏବଂ ଫୋନକୁ ଲକ କରିବା ସମୟରେ ଯଦି ଅନେକ ଭୁଲ ପାସୱର୍ଡ ଟାଇପ କରାଯାଇଥାଏ, ତେବେ ଫୋନର ସମସ୍ତ ଡାଟା ଡିଲିଟ କରେ।"</string> +    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"ଫୋନ ଅନଲକ କରିବା ବେଳେ ଟାଇପ କରାଯାଇଥିବା ଭୁଲ ପାସୱାର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରିବା ଏବଂ ଯଦି ଏକାଧିକ ଥର ଭୁଲ ପାସୱାର୍ଡ ଟାଇପ କରାଯାଇଥାଏ ତେବେ ଫୋନକୁ ଲକ କରିବା ବା ଫୋନର ସମସ୍ତ ଡାଟା ଇରେଜ କରିବା।"</string>      <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="automotive" msgid="7180857406058327941">"ସ୍କ୍ରିନ ଅନଲକ କରିବା ସମୟରେ ଟାଇପ କରାଯାଇଥିବା ଭୁଲ ପାସୱାର୍ଡର ସଂଖ୍ୟାକୁ ମନିଟର କରନ୍ତୁ ଏବଂ ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମକୁ ଲକ କରନ୍ତୁ କିମ୍ବା ଯଦି ଅନେକଗୁଡ଼ିଏ ଭୁଲ ପାସୱାର୍ଡ ଟାଇପ କରାଯାଇଥାଏ ତେବେ ଏହି ପ୍ରୋଫାଇଲର ସମସ୍ତ ଡାଟା ଖାଲି କରନ୍ତୁ।"</string> @@ -844,7 +844,7 @@      <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="automotive" msgid="660804547737323300">"ଏକ ଫ୍ୟାକ୍ଟୋରୀ ଡାଟା ରିସେଟ କରି ବିନା ଚେତାବନୀରେ ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମର ଡାଟା ଖାଲି କରନ୍ତୁ।"</string> -    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"ବିନା ଚେତାବନୀରେ ଫ୍ୟାକ୍ଟୋରୀ ଡାଟା ରିସେଟ କରି ଫୋନର ଡାଟା ଲିଭାଇଥାଏ।"</string> +    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"ବିନା ଚେତାବନୀରେ ଫେକ୍ଟୋରୀ ଡାଟା ରିସେଟ କରି ଫୋନର ଡାଟା ଇରେଜ କରିବା।"</string>      <string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"ପ୍ରୋଫାଇଲ ଡାଟା ଖାଲି କରନ୍ତୁ"</string>      <string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"ୟୁଜର୍ ଡାଟା ଲିଭାନ୍ତୁ"</string>      <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"ବିନା ଚେତାବନୀରେ ଏହି ଟାବଲେଟରେ ଥିବା ଏହି ୟୁଜରଙ୍କ ଡାଟା ଲିଭାଇ ଦିଅନ୍ତୁ।"</string> @@ -1754,7 +1754,7 @@      <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="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>      <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>ଙ୍କୁ ଲଗଆଉଟ୍ କରାଯାଉଛି…"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"ଟେଷ୍ଟ"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"କମ୍ୟୁନାଲ"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ସୁରକ୍ଷା ପାଇଁ ସ୍କ୍ରିନ ସେୟାରରୁ ଆପ ବିଷୟବସ୍ତୁକୁ ଲୁଚାଯାଇଛି"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"ସାଟେଲାଇଟ ସହ ସ୍ୱତଃ କନେକ୍ଟ ହୋଇଛି"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"ଏକ ମୋବାଇଲ କିମ୍ବା ୱାଇ-ଫାଇ ନେଟୱାର୍କ ବିନା ଆପଣ ମେସେଜ ପଠାଇପାରିବେ ଏବଂ ପାଇପାରିବେ"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ଖୋଲନ୍ତୁ"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 3e7b27e9bb8a..282694d32188 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -844,7 +844,7 @@      <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="automotive" msgid="660804547737323300">"ਫੈਕਟਰੀ ਡਾਟਾ ਰੀਸੈੱਟ ਕਰਕੇ ਚਿਤਾਵਨੀ ਤੋਂ ਬਿਨਾਂ ਵਾਹਨ ਆਡੀਓ ਸਿਸਟਮ ਦਾ ਡਾਟਾ ਮਿਟਾਓ।"</string> -    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"ਇੱਕ ਫੈਕਟਰੀ ਡਾਟਾ ਰੀਸੈੱਟ ਕਰਕੇ ਚਿਤਾਵਨੀ ਤੋਂ ਬਿਨਾਂ ਫ਼ੋਨ ਦਾ ਡਾਟਾ ਮਿਟਾਓ।"</string> +    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"ਫੈਕਟਰੀ ਡਾਟਾ ਰੀਸੈੱਟ ਕਰ ਕੇ ਚਿਤਾਵਨੀ ਤੋਂ ਬਿਨਾਂ ਫ਼ੋਨ ਦਾ ਡਾਟਾ ਮਿਟਾਓ।"</string>      <string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟਾਓ"</string>      <string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"ਉਪਭੋਗਤਾ  ਡਾਟਾ  ਮਿਟਾਓ"</string>      <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"ਬਿਨਾਂ ਚਿਤਾਵਨੀ ਦੇ ਇਸ ਟੈਬਲੈੱਟ ਤੇ ਮੌਜੂਦ ਇਸ ਵਰਤੋਂਕਾਰ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ।"</string> @@ -1724,10 +1724,10 @@      <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"ਬੰਦ"</string>      <string name="accessibility_enable_service_title" msgid="3931558336268541484">"ਕੀ <xliff:g id="SERVICE">%1$s</xliff:g> ਨੂੰ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦਾ ਪੂਰਾ ਕੰਟਰੋਲ ਦੇਣਾ ਹੈ?"</string>      <string name="accessibility_service_warning_description" msgid="291674995220940133">"ਪੂਰਾ ਕੰਟਰੋਲ ਉਨ੍ਹਾਂ ਐਪਾਂ ਲਈ ਢੁਕਵਾਂ ਹੈ ਜੋ ਪਹੁੰਚਯੋਗਤਾ ਸੰਬੰਧੀ ਲੋੜਾਂ ਵਿੱਚ ਤੁਹਾਡੀ ਮਦਦ ਕਰਦੀਆਂ ਹਨ, ਪਰ ਜ਼ਿਆਦਾਤਰ ਐਪਾਂ ਲਈ ਢੁਕਵਾਂ ਨਹੀਂ ਹੁੰਦਾ।"</string> -    <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"ਸਕ੍ਰੀਨ ਨੂੰ ਦੇਖੋ ਅਤੇ ਕੰਟਰੋਲ ਕਰੋ"</string> +    <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"ਸਕ੍ਰੀਨ ਨੂੰ ਦੇਖਣਾ ਅਤੇ ਕੰਟਰੋਲ ਕਰਨਾ"</string>      <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"ਇਹ ਸਕ੍ਰੀਨ \'ਤੇ ਸਾਰੀ ਸਮੱਗਰੀ ਪੜ੍ਹ ਸਕਦੀ ਹੈ ਅਤੇ ਸਮੱਗਰੀ ਨੂੰ ਦੂਜੀਆਂ ਐਪਾਂ ਦੇ ਉੱਪਰ ਦਿਖਾ ਸਕਦੀ ਹੈ।"</string> -    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"ਕਾਰਵਾਈਆਂ ਦੇਖੋ ਅਤੇ ਕਰੋ"</string> -    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"ਇਹ ਕਿਸੇ ਐਪ ਜਾਂ ਹਾਰਡਵੇਅਰ ਸੈਂਸਰ ਦੇ ਨਾਲ ਤੁਹਾਡੀਆਂ ਅੰਤਰਕਿਰਿਆਵਾਂ ਨੂੰ ਟਰੈਕ ਕਰ ਸਕਦੀ ਹੈ, ਅਤੇ ਤੁਹਾਡੀ ਤਰਫ਼ੋਂ ਐਪਾਂ ਦੇ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰ ਸਕਦੀ ਹੈ।"</string> +    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"ਕਾਰਵਾਈਆਂ ਦੇਖਣਾ ਅਤੇ ਕਰਨਾ"</string> +    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"ਇਹ ਕਿਸੇ ਐਪ ਜਾਂ ਹਾਰਡਵੇਅਰ ਸੈਂਸਰ ਦੇ ਨਾਲ ਤੁਹਾਡੀਆਂ ਅੰਤਰਕਿਰਿਆਵਾਂ ਨੂੰ ਟਰੈਕ ਕਰ ਸਕਦੀ ਹੈ ਅਤੇ ਤੁਹਾਡੀ ਤਰਫ਼ੋਂ ਐਪਾਂ ਦੇ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰ ਸਕਦੀ ਹੈ।"</string>      <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"ਕਰਨ ਦਿਓ"</string>      <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"ਨਾ ਕਰਨ ਦਿਓ"</string>      <string name="accessibility_dialog_button_uninstall" msgid="2952465517671708108">"ਅਣਸਥਾਪਤ ਕਰੋ"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"ਜਾਂਚ"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"ਭਾਈਚਾਰਕ"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ਐਪ ਸਮੱਗਰੀ ਨੂੰ ਸੁਰੱਖਿਆ ਲਈ ਸਕ੍ਰੀਨ ਸਾਂਝਾਕਰਨ ਤੋਂ ਲੁਕਾਇਆ ਗਿਆ ਹੈ"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"ਸੈਟੇਲਾਈਟ ਨਾਲ ਸਵੈ-ਕਨੈਕਟ ਹੋਇਆ"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"ਤੁਸੀਂ ਮੋਬਾਈਲ ਜਾਂ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਤੋਂ ਬਿਨਾਂ ਸੁਨੇਹੇ ਭੇਜ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੇ ਹੋ"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ਐਪ ਖੋਲ੍ਹੋ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index ca126f794c06..470191581044 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -997,7 +997,7 @@      <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Poprawnie!"</string>      <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Spróbuj ponownie."</string>      <string name="lockscreen_password_wrong" msgid="8605355913868947490">"Spróbuj ponownie."</string> -    <string name="lockscreen_storage_locked" msgid="634993789186443380">"Odblokowanie wszystkich funkcji i danych"</string> +    <string name="lockscreen_storage_locked" msgid="634993789186443380">"Odblokuj, by używać wszystkich funkcji i danych"</string>      <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Przekroczono maksymalną liczbę prób rozpoznania twarzy."</string>      <string name="lockscreen_missing_sim_message_short" msgid="1229301273156907613">"Brak karty SIM"</string>      <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"Brak karty SIM w tablecie."</string> @@ -1763,7 +1763,7 @@      <string name="owner_name" msgid="8713560351570795743">"Właściciel"</string>      <string name="guest_name" msgid="8502103277839834324">"Gość"</string>      <string name="error_message_title" msgid="4082495589294631966">"Błąd"</string> -    <string name="error_message_change_not_allowed" msgid="843159705042381454">"Ta zmiana nie jest dozwolona przez administratora"</string> +    <string name="error_message_change_not_allowed" msgid="843159705042381454">"Ta zmiana nie jest dozwolona przez administratora."</string>      <string name="app_not_found" msgid="3429506115332341800">"Nie znaleziono aplikacji do obsługi tej akcji"</string>      <string name="revoke" msgid="5526857743819590458">"Cofnij"</string>      <string name="mediasize_iso_a0" msgid="7039061159929977973">"ISO A0"</string> @@ -1905,7 +1905,7 @@      <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne, pewne funkcje oraz wybrane połączenia sieciowe."</string>      <string name="battery_saver_description" msgid="8518809702138617167">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne, pewne funkcje oraz wybrane połączenia sieciowe."</string>      <string name="data_saver_description" msgid="4995164271550590517">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string> -    <string name="data_saver_enable_title" msgid="7080620065745260137">"Włączyć Oszczędzanie danych?"</string> +    <string name="data_saver_enable_title" msgid="7080620065745260137">"Włączyć oszczędzanie danych?"</string>      <string name="data_saver_enable_button" msgid="4399405762586419726">"Włącz"</string>      <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{Przez 1 minutę (do {formattedTime})}few{Przez # minuty (do {formattedTime})}many{Przez # minut (do {formattedTime})}other{Przez # minuty (do {formattedTime})}}"</string>      <string name="zen_mode_duration_minutes_summary_short" msgid="1187553788355486950">"{count,plural, =1{Przez 1 min (do {formattedTime})}few{Przez # min (do {formattedTime})}many{Przez # min (do {formattedTime})}other{Przez # min (do {formattedTime})}}"</string> @@ -2396,8 +2396,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Testowy"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Wspólny"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ze względów bezpieczeństwa zawartość aplikacji jest niewidoczna podczas udostępniania ekranu"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automatycznie połączono z satelitą"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Możesz wymieniać wiadomości bez dostępu do sieci komórkowej lub Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otwórz Wiadomości"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index c53b1d50aa35..73121ce35ce3 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1371,8 +1371,8 @@      <string name="sim_added_message" msgid="6602906609509958680">"Reinicie o dispositivo para acessar a rede móvel."</string>      <string name="sim_restart_button" msgid="8481803851341190038">"Reiniciar"</string>      <string name="install_carrier_app_notification_title" msgid="5712723402213090102">"Ativar serviço móvel"</string> -    <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Faça o download do app da operadora para ativar seu novo chip"</string> -    <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Faça o download do app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar seu novo chip"</string> +    <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Baixe o app da operadora para ativar seu novo chip"</string> +    <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Baixe o app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar seu novo chip"</string>      <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Fazer download do app"</string>      <string name="carrier_app_notification_title" msgid="5815477368072060250">"Novo chip inserido"</string>      <string name="carrier_app_notification_text" msgid="6567057546341958637">"Toque para configurar"</string> @@ -1744,7 +1744,7 @@      <string name="color_inversion_feature_name" msgid="2672824491933264951">"Inversão de cores"</string>      <string name="color_correction_feature_name" msgid="7975133554160979214">"Correção de cor"</string>      <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo uma mão"</string> -    <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Escurecer a tela"</string> +    <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Escurecer ainda mais a tela"</string>      <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparelhos auditivos"</string>      <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>      <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string> @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Teste"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Público"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo do app oculto no compartilhamento de tela por motivos de segurança"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Conectado automaticamente ao satélite"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Você pode enviar e receber mensagens sem um dispositivo móvel ou uma rede Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir o app Mensagens"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 6b6f5c5af0f6..10e19cdf6c72 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -845,7 +845,7 @@      <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Apagar os dados do tablet sem avisar através de uma reposição de dados de fábrica."</string>      <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Apagar os dados do seu dispositivo Android TV sem avisar ao efetuar uma reposição de dados de fábrica."</string>      <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"Apague os dados do sistema de infoentretenimento sem aviso ao executar uma reposição de dados de fábrica."</string> -    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Apaga os dados do telemóvel sem avisar ao efetuar uma reposição de dados de fábrica."</string> +    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Apaga os dados do telemóvel sem avisar repondo os dados de fábrica."</string>      <string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"Apague os dados do perfil"</string>      <string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"Apagar os dados do utilizador"</string>      <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Apagar os dados deste utilizador neste tablet sem aviso."</string> @@ -1393,7 +1393,7 @@      <string name="usb_midi_notification_title" msgid="7404506788950595557">"O MIDI através de USB está ativado"</string>      <string name="usb_uvc_notification_title" msgid="2030032862673400008">"Dispositivo ligado como câmara Web"</string>      <string name="usb_accessory_notification_title" msgid="1385394660861956980">"Acessório USB ligado"</string> -    <string name="usb_notification_message" msgid="4715163067192110676">"Toque para obter mais opções."</string> +    <string name="usb_notification_message" msgid="4715163067192110676">"Toque para ver mais opções."</string>      <string name="usb_power_notification_message" msgid="7284765627437897702">"A carregar o dispositivo ligado. Toque para obter mais opções."</string>      <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Acessório de áudio analógico detetado"</string>      <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"O dispositivo ligado não é compatível com este telemóvel. Toque para saber mais."</string> @@ -1724,10 +1724,10 @@      <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"ATIVADO"</string>      <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"DESATIVADO"</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_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 apps."</string> +    <string name="accessibility_service_warning_description" msgid="291674995220940133">"O controlo total é adequado para apps que ajudam nas necessidades de acessibilidade, mas não para a maioria das apps."</string>      <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Ver e controlar o ecrã"</string> -    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Pode ler todo o conteúdo do ecrã e sobrepor conteúdo a outras aplicações."</string> -    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Veja e execute ações"</string> +    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Pode ler todo o conteúdo do ecrã e sobrepor conteúdo a outras apps."</string> +    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Ver e executar ações"</string>      <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Pode monitorizar as suas interações com uma app ou um sensor de hardware e interagir com apps em seu nome."</string>      <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Permitir"</string>      <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Recusar"</string> @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Teste"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Comum"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo da app ocultado da partilha de ecrã por motivos de segurança"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Ligação de satélite estabelecida automaticamente"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Pode enviar e receber mensagens sem uma rede móvel ou Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abre a app Mensagens"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index c53b1d50aa35..73121ce35ce3 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1371,8 +1371,8 @@      <string name="sim_added_message" msgid="6602906609509958680">"Reinicie o dispositivo para acessar a rede móvel."</string>      <string name="sim_restart_button" msgid="8481803851341190038">"Reiniciar"</string>      <string name="install_carrier_app_notification_title" msgid="5712723402213090102">"Ativar serviço móvel"</string> -    <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Faça o download do app da operadora para ativar seu novo chip"</string> -    <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Faça o download do app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar seu novo chip"</string> +    <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Baixe o app da operadora para ativar seu novo chip"</string> +    <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Baixe o app <xliff:g id="APP_NAME">%1$s</xliff:g> para ativar seu novo chip"</string>      <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Fazer download do app"</string>      <string name="carrier_app_notification_title" msgid="5815477368072060250">"Novo chip inserido"</string>      <string name="carrier_app_notification_text" msgid="6567057546341958637">"Toque para configurar"</string> @@ -1744,7 +1744,7 @@      <string name="color_inversion_feature_name" msgid="2672824491933264951">"Inversão de cores"</string>      <string name="color_correction_feature_name" msgid="7975133554160979214">"Correção de cor"</string>      <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo uma mão"</string> -    <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Escurecer a tela"</string> +    <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Escurecer ainda mais a tela"</string>      <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparelhos auditivos"</string>      <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Teclas de volume pressionadas. Serviço <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ativado."</string>      <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Teclas de volume pressionadas. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desativado."</string> @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Teste"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Público"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo do app oculto no compartilhamento de tela por motivos de segurança"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Conectado automaticamente ao satélite"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Você pode enviar e receber mensagens sem um dispositivo móvel ou uma rede Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir o app Mensagens"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 5a449e3b14f0..e27603af34c9 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Comun"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conținutul aplicației este ascuns de permiterea accesului la ecran din motive de securitate"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"S-a conectat automat la satelit"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Poți să trimiți și să primești mesaje fără o rețea mobilă sau Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Deschide Mesaje"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 59982ef42804..a92a580e927b 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -833,7 +833,7 @@      <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Отслеживает попытки ввода пароля при разблокировке экрана и блокирует планшетный ПК или удаляет с него все данные, если было сделано слишком много таких попыток."</string>      <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Блокировать устройство Android TV или удалять с него все ваши данные при слишком большом количестве неудачных попыток ввести пароль для разблокировки экрана."</string>      <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Блокировать информационно-развлекательную систему или удалять из нее все данные, если совершено слишком много неудачных попыток ввести пароль для разблокировки экрана."</string> -    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Отслеживает попытки ввода пароля при разблокировке экрана и блокирует телефон или удаляет с него все данные, если было сделано слишком много таких попыток."</string> +    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Отслеживать попытки ввода пароля при разблокировке экрана и блокировать телефон или удалять с него все данные, если было сделано слишком много таких попыток."</string>      <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="automotive" msgid="7180857406058327941">"Блокировать информационно-развлекательную систему или удалять все данные профиля, если совершено слишком много неудачных попыток ввести пароль для разблокировки экрана."</string> @@ -2396,8 +2396,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Тестовый"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Совместный"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Содержимое приложения исключено из демонстрации экрана в целях безопасности."</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Автоматически подключено к системам спутниковой связи"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Вы можете отправлять и получать сообщения без доступа к мобильной сети или Wi-Fi."</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Открыть Сообщения"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 04b2c52b425c..5c9f4d9004f5 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"පරීක්ෂණය"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"වාර්ගික"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ආරක්ෂාව සඳහා යෙදුම් අන්තර්ගතය තිරය බෙදා ගැනීමෙන් සඟවා ඇත"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"චන්ද්රිකාවට ස්වයංක්රීයව සම්බන්ධ වේ"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"ඔබට ජංගම හෝ Wi-Fi ජාලයක් නොමැතිව පණිවිඩ යැවීමට සහ ලැබීමට හැක"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages විවෘත කරන්න"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 76cad30f16ce..8dc68ca0a9bd 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -833,7 +833,7 @@      <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Sledovať počet nesprávnych hesiel zadaných pri odomykaní obrazovky a zamknúť tablet alebo vymazať všetky údaje tabletu v prípade príliš veľkého počtu neplatných pokusov o zadanie hesla."</string>      <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Sledovanie počtu nesprávnych hesiel zadaných pri odomykaní obrazovky a v prípade, že ich je zadaných príliš mnoho, uzamknutie zariadenia Android TV alebo vymazanie všetkých jeho údajov."</string>      <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Sledujte počet nesprávnych hesiel zadaných pri odomykaní obrazovky a uzamknite palubný systém alebo vymažte všetky údaje v palubnom systéme v prípade príliš veľkého počtu neplatných pokusov o zadanie hesla."</string> -    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Sledovať počet nesprávnych hesiel zadaných pri odomykaní obrazovky a zamknúť telefón alebo vymazať všetky údaje v telefóne v prípade príliš veľkého počtu neplatných pokusov o zadanie hesla."</string> +    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Sleduje počet nesprávnych hesiel zadaných pri odomykaní obrazovky a uzamkne telefón alebo vymaže z telefónu všetky dáta, ak bolo zadaných príliš veľa nesprávnych hesiel."</string>      <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Sledujte počet nesprávnych hesiel zadaných pri odomykaní obrazovky a v prípade, že ich je zadaných príliš mnoho, uzamknite tablet alebo vymažte všetky údaje tohto používateľa."</string>      <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Sledovanie počtu nesprávnych hesiel zadaných pri odomykaní obrazovky a ak je ich zadaných príliš mnoho, uzamknutie zariadenia Android TV alebo vymazanie všetkých údajov tohto používateľa."</string>      <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Sledujte počet nesprávnych hesiel zadaných pri odomykaní obrazovky a v prípade, že ich je zadaných príliš mnoho, uzamknite palubný systém alebo vymažte všetky údaje tohto profilu."</string> @@ -846,7 +846,7 @@      <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Bez predchádzajúceho upozornenia vymazať všetky dáta obnovením výrobných nastavení tabletu."</string>      <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Vymazanie údajov v zariadení Android TV bez upozornenia obnovením výrobných nastavení."</string>      <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"Vymažte údaje palubného systému bez upozornenia obnovením výrobných nastavení."</string> -    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Bez predchádzajúceho upozornenia vymazať všetky dáta obnovením výrobných nastavení telefónu."</string> +    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Bez predchádzajúceho upozornenia vymaže všetky dáta obnovením výrobných nastavení telefónu."</string>      <string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"Vymazanie údajov profilu"</string>      <string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"Vymazať údaje používateľa"</string>      <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Vymažte bez upozornenia údaje tohto používateľa na tomto tablete."</string> @@ -2396,8 +2396,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Testovací"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Spoločný"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikácie bol na účely zabezpečenia skrytý v zdieľaní obrazovky"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automaticky pripojené k satelitu"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Správy môžete odosielať a prijímať bez mobilnej siete či siete Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvoriť Správy"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 5983929eaed3..9118c9532c53 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -2396,8 +2396,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Preizkus"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Skupno"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Pri deljenju zaslona je vsebina aplikacije skrita zaradi varnosti"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Samodejno vzpostavljena povezava s satelitom"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Sporočila SMS lahko pošiljate in prejemate brez mobilnega omrežja ali omrežja Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Odpri Sporočila"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 5a02d565eb44..6036a1773274 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"I përbashkët"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Përmbajtja e aplikacionit është fshehur nga ndarja e ekranit për arsye sigurie"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"U lidh automatikisht me satelitin"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Mund të dërgosh dhe të marrësh mesazhe pa një rrjet celular apo rrjet Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Hap \"Mesazhet\""</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 637371ced5ce..2020f916376a 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1223,7 +1223,7 @@      <string name="whichEditApplicationLabel" msgid="1463288652070140285">"Измени"</string>      <string name="whichSendApplication" msgid="4143847974460792029">"Делите"</string>      <string name="whichSendApplicationNamed" msgid="4470386782693183461">"Делите помоћу апликације %1$s"</string> -    <string name="whichSendApplicationLabel" msgid="7467813004769188515">"Дели"</string> +    <string name="whichSendApplicationLabel" msgid="7467813004769188515">"Дељење"</string>      <string name="whichSendToApplication" msgid="77101541959464018">"Пошаљите помоћу:"</string>      <string name="whichSendToApplicationNamed" msgid="3385686512014670003">"Пошаљите помоћу: %1$s"</string>      <string name="whichSendToApplicationLabel" msgid="3543240188816513303">"Пошаљи"</string> @@ -2395,8 +2395,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Тест"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Заједничко"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Садржај апликације је скривен за дељење садржаја екрана због безбедности"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Аутоматски повезано са сателитом"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Можете да шаљете и примате поруке без мобилне или WiFi мреже"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Отвори Messages"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 2dde3a8bcde5..cd334a359f19 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -50,7 +50,7 @@        <item quantity="other">Du har <xliff:g id="NUMBER_1">%d</xliff:g> försök kvar innan SIM-kortet låses.</item>        <item quantity="one">Du har <xliff:g id="NUMBER_0">%d</xliff:g> försök kvar innan SIM-kortet låses.</item>      </plurals> -    <string name="imei" msgid="2157082351232630390">"IMEI-kod"</string> +    <string name="imei" msgid="2157082351232630390">"IMEI"</string>      <string name="meid" msgid="3291227361605924674">"MEID"</string>      <string name="ClipMmi" msgid="4110549342447630629">"Nummerpresentatör för inkommande samtal"</string>      <string name="ClirMmi" msgid="6752346475055446417">"Dölj nummerpresentatör för utgående samtal"</string> @@ -831,7 +831,7 @@      <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Övervaka antalet felaktiga lösenord som angetts för skärmlåset och lås surfplattan eller ta bort alla data från surfplattan om för många felaktiga försök görs."</string>      <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Övervaka antalet felaktiga lösenord som skrivits in vid upplåsning av skärmen och lås Android TV-enheten eller rensa all data på Android TV-enheten om för många felaktiga lösenord har skrivits in."</string>      <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Övervaka antalet felaktiga lösenord som angetts för skärmlåset och lås infotainmentsystemet eller rensa all data från infotainmentsystemet om för många felaktiga försök görs."</string> -    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Övervaka antalet felaktiga lösenord som angivits för skärmlåset och lås mobilen eller ta bort alla data från mobilen om för många felaktiga försök görs."</string> +    <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Övervaka antalet felaktiga lösenord som angivits för skärmlåset och lås telefonen eller ta bort alla data från telefonen om för många felaktiga försök görs."</string>      <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Övervaka antalet felaktiga lösenord som skrivits in vid upplåsning av skärmen och lås surfplattan eller rensa alla uppgifter för den här användaren om för många felaktiga lösenord har skrivits in."</string>      <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Övervaka antalet felaktiga lösenord som skrivits in vid upplåsning av skärmen och lås Android TV-enheten eller rensa alla uppgifter för den här användaren om för många felaktiga lösenord har skrivits in."</string>      <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Övervaka antalet felaktiga lösenord som angetts för skärmlåset och lås infotainmentsystemet eller rensa all data från profilen om för många felaktiga lösenord har skrivits in."</string> @@ -844,7 +844,7 @@      <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Ta bort data från surfplattan utan förvarning genom att återställa standardinställningarna."</string>      <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Radera data på Android TV-enheten utan förvarning genom att återställa standardinställningarna."</string>      <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"Rensa data från infotainmentsystemet utan förvarning genom att återställa standardinställningarna."</string> -    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Ta bort data från mobilen utan förvarning genom att återställa standardinställningarna."</string> +    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Ta bort data från telefonen utan förvarning genom att återställa standardinställningarna."</string>      <string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"Rensa profildata"</string>      <string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"Radera användaruppgifter"</string>      <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Rensa användarens uppgifter på den här surfplattan utan förvarning."</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Allmän"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av säkerhetsskäl döljs appinnehållet vid skärmdelning"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Automatiskt ansluten till satellit"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Du kan skicka och ta emot meddelanden utan mobil- eller wifi-nätverk"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Öppna Messages"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 2936716a67b5..b16bbcd74364 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Jaribio"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Unaoshirikiwa"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Maudhui ya programu yamefichwa ili yasionekane kwenye skrini ya pamoja kwa sababu za kiusalama"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Imeunganishwa kiotomatiki na satelaiti"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Unaweza kutuma na kupokea ujumbe bila mtandao wa simu au Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Fungua Programu ya Messages"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 28ee91ddb448..870f52e7fce5 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"பரிசோதனை"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"பொது"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"பாதுகாப்பிற்காக, திரைப் பகிர்வில் இருந்து ஆப்ஸ் உள்ளடக்கம் மறைக்கப்பட்டுள்ளது"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"சாட்டிலைட்டுடன் தானாக இணைக்கப்பட்டது"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"மொபைல்/வைஃபை நெட்வொர்க் இல்லாமல் நீங்கள் மெசேஜ்களை அனுப்பலாம் பெறலாம்"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ஆப்ஸைத் திறக்கவும்"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index c64c9b6d61ee..ecd7e94592a9 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -688,7 +688,7 @@    </string-array>      <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"ఏదో తప్పు జరిగింది. మళ్లీ ట్రై చేయండి."</string>      <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"వేలిముద్ర చిహ్నం"</string> -    <string name="device_unlock_notification_name" msgid="2632928999862915709">"పరికర అన్లాక్"</string> +    <string name="device_unlock_notification_name" msgid="2632928999862915709">"డివైజ్ అన్లాక్"</string>      <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"అన్లాక్ చేయడానికి మరొక మార్గాన్ని ట్రై చేయండి"</string>      <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"మీ వేళ్లు తడిగా ఉండటం లేక ఇతరత్రా కారణాల వల్ల మీ వేలిముద్రను గుర్తించకపోతే, ఫేస్ అన్లాక్ను ఉపయోగించండి"</string>      <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"తగినంత వెలుతురు లేకపోవడం లేక ఇతరత్రా కారణాల వల్ల మీ ఫేస్ గుర్తించబడనప్పుడు, వేలిముద్ర అన్లాక్ను ఉపయోగించండి"</string> @@ -995,7 +995,7 @@      <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_storage_locked" msgid="634993789186443380">"అన్ని లక్షణాలు మరియు డేటా కోసం అన్లాక్ చేయండి"</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="1229301273156907613">"SIM లేదు"</string>      <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"టాబ్లెట్లో SIM లేదు."</string> @@ -1222,7 +1222,7 @@      <string name="whichEditApplicationLabel" msgid="1463288652070140285">"ఎడిట్"</string>      <string name="whichSendApplication" msgid="4143847974460792029">"షేర్ చేయండి"</string>      <string name="whichSendApplicationNamed" msgid="4470386782693183461">"%1$sతో షేర్ చేయండి"</string> -    <string name="whichSendApplicationLabel" msgid="7467813004769188515">"షేర్ చేయి"</string> +    <string name="whichSendApplicationLabel" msgid="7467813004769188515">"షేర్ చేయండి"</string>      <string name="whichSendToApplication" msgid="77101541959464018">"దీన్ని ఉపయోగించి పంపండి"</string>      <string name="whichSendToApplicationNamed" msgid="3385686512014670003">"%1$sని ఉపయోగించి పంపండి"</string>      <string name="whichSendToApplicationLabel" msgid="3543240188816513303">"పంపండి"</string> @@ -1416,7 +1416,7 @@      <string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"బగ్ రిపోర్ట్ను షేర్ చేయాలా?"</string>      <string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"బగ్ రిపోర్ట్ను షేర్ చేస్తోంది..."</string>      <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"మీ అడ్మిన్ ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ రిపోర్ట్ను రిక్వెస్ట్ చేశారు. యాప్లు మరియు డేటా షేర్ చేయబడవచ్చు."</string> -    <string name="share_remote_bugreport_action" msgid="7630880678785123682">"షేర్ చేయి"</string> +    <string name="share_remote_bugreport_action" msgid="7630880678785123682">"షేర్ చేయండి"</string>      <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"తిరస్కరిస్తున్నాను"</string>      <string name="select_input_method" msgid="3971267998568587025">"ఇన్పుట్ పద్ధతిని ఎంచుకోండి"</string>      <string name="show_ime" msgid="6406112007347443383">"దీన్ని భౌతిక కీబోర్డ్ యాక్టివ్గా ఉన్నప్పుడు స్క్రీన్పై ఉంచుతుంది"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"పరీక్ష"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"కమ్యూనల్"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"సెక్యూరిటీ కోసం స్క్రీన్ షేర్ నుండి యాప్ కంటెంట్ దాచబడింది"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"శాటిలైట్కు ఆటోమేటిక్గా కనెక్ట్ చేయబడింది"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"మీరు మొబైల్ లేదా Wi-Fi నెట్వర్క్ లేకుండా మెసేజ్లను పంపవచ్చు, స్వీకరించవచ్చు"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messagesను తెరవండి"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 7555f26fd2fa..b1debfd4cf74 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"ทดสอบ"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"ส่วนกลาง"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ซ่อนเนื้อหาแอปจากการแชร์หน้าจอเพื่อความปลอดภัย"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"เชื่อมต่อกับดาวเทียมโดยอัตโนมัติ"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"คุณรับส่งข้อความผ่านดาวเทียมได้โดยไม่ต้องใช้เครือข่ายมือถือหรือ Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"เปิด Messages"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 112da5cc6b3e..3547870302b0 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1222,7 +1222,7 @@      <string name="whichEditApplicationLabel" msgid="1463288652070140285">"I-edit"</string>      <string name="whichSendApplication" msgid="4143847974460792029">"Ibahagi"</string>      <string name="whichSendApplicationNamed" msgid="4470386782693183461">"Ibahagi gamit ang %1$s"</string> -    <string name="whichSendApplicationLabel" msgid="7467813004769188515">"Ibahagi"</string> +    <string name="whichSendApplicationLabel" msgid="7467813004769188515">"I-share"</string>      <string name="whichSendToApplication" msgid="77101541959464018">"Ipadala gamit ang"</string>      <string name="whichSendToApplicationNamed" msgid="3385686512014670003">"Ipadala gamit ang %1$s"</string>      <string name="whichSendToApplicationLabel" msgid="3543240188816513303">"Ipadala"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Communal"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nakatago ang content ng app mula sa pagbabahagi ng screen para sa seguridad"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Awtomatikong nakakonekta sa satellite"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Puwede kang magpadala at tumanggap ng mga mensahe nang walang mobile o Wi-Fi network"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Buksan ang Messages"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 2ca545b89612..7e34e4bf97f3 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1396,8 +1396,8 @@      <string name="usb_power_notification_message" msgid="7284765627437897702">"Bağlı cihaz şarj ediliyor. Diğer seçenekler için dokunun."</string>      <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Analog ses aksesuarı algılandı"</string>      <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Takılan cihaz bu telefonla uyumlu değil. Daha fazla bilgi edinmek için dokunun."</string> -    <string name="adb_active_notification_title" msgid="408390247354560331">"USB hata ayıklaması bağlandı"</string> -    <string name="adb_active_notification_message" msgid="5617264033476778211">"USB hata ayıklamayı kapatmak için dokunun"</string> +    <string name="adb_active_notification_title" msgid="408390247354560331">"USB üzerinden hata ayıklama bağlandı"</string> +    <string name="adb_active_notification_message" msgid="5617264033476778211">"USB üzerinden hata ayıklamayı kapatmak için dokunun"</string>      <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB hata ayıklamasını devre dışı bırakmak için seçin."</string>      <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Kablosuz hata ayıklama bağlı"</string>      <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Kablosuz hata ayıklamayı kapatmak için dokunun"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Paylaşılan"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Uygulama içerikleri, güvenlik nedeniyle ekran paylaşımında gizlendi"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Uyduya otomatik olarak bağlandı"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Mobil veya kablosuz ağa bağlı olmadan mesaj alıp gönderebilirsiniz"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Mesajlar\'ı aç"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index df2c7157b88f..34618cd243c4 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1185,7 +1185,7 @@      <string name="deleteText" msgid="4200807474529938112">"Видалити"</string>      <string name="inputMethod" msgid="1784759500516314751">"Метод введення"</string>      <string name="editTextMenuTitle" msgid="857666911134482176">"Дії з текстом"</string> -    <string name="error_handwriting_unsupported" msgid="7809438534946014050">"Рукописне введення не підтримується в цьому полі"</string> +    <string name="error_handwriting_unsupported" msgid="7809438534946014050">"У цьому полі не підтримується рукописне введення"</string>      <string name="error_handwriting_unsupported_password" msgid="5095401146106891087">"Рукописне введення не підтримується в полях паролів"</string>      <string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Назад"</string>      <string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Змінити метод введення"</string> @@ -2396,8 +2396,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Тестовий профіль"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Спільний профіль"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"З міркувань безпеки вміст додатка приховано під час показу екрана"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Автоматично підключено до супутника"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Ви можете надсилати й отримувати повідомлення, не використовуючи Wi-Fi або мобільну мережу"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Відкрийте Повідомлення"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 29bd5bec0415..caf0ca4e435a 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"ٹیسٹ"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"کمیونل"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"سیکیورٹی کے مد نظر ایپ کا مواد اسکرین کے اشتراک سے چھپا ہوا ہے"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"سٹلائٹ سے خودکار طور پر منسلک ہے"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"آپ موبائل یا Wi-Fi نیٹ ورک کے بغیر پیغامات بھیج اور موصول کر سکتے ہیں"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"پیغامات ایپ کو کھولیں"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index dddc3d6e9d81..e22c1dce2a03 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Test"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Umumiy"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ekran namoyishida xavfsizlik maqsadida ilova kontenti berkitildi"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Sputnikka avtomatik ulandi"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Mobil yoki Wi-Fi tarmoqsiz xabarlarni yuborishingiz va qabul qilishingiz mumkin"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Xabarlar ilovasini ochish"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 073a1a8ee7ae..d6bd1904ec21 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -2178,9 +2178,9 @@      <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khóa màn hình"</string>      <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Chụp ảnh màn hình"</string>      <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Giá treo tai nghe"</string> -    <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Phím tắt hỗ trợ tiếp cận trên màn hình"</string> -    <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Bộ chọn phím tắt hỗ trợ tiếp cận trên màn hình"</string> -    <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Phím tắt hỗ trợ tiếp cận"</string> +    <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Lối tắt hỗ trợ tiếp cận trên màn hình"</string> +    <string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Bộ chọn lối tắt hỗ trợ tiếp cận trên màn hình"</string> +    <string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Lối tắt hỗ trợ tiếp cận"</string>      <string name="accessibility_system_action_dismiss_notification_shade" msgid="8931637495533770352">"Đóng Ngăn thông báo"</string>      <string name="accessibility_system_action_dpad_up_label" msgid="1029042950229333782">"Chuyển lên trên bằng bàn phím di chuyển"</string>      <string name="accessibility_system_action_dpad_down_label" msgid="3441918448624921461">"Chuyển xuống dưới bằng bàn phím di chuyển"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Kiểm thử"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Dùng chung"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nội dung ứng dụng bị ẩn khỏi tính năng chia sẻ màn hình vì lý do bảo mật"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Đã tự động kết nối với vệ tinh"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Bạn có thể gửi và nhận tin nhắn mà không cần có mạng di động hoặc mạng Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Mở ứng dụng Tin nhắn"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index ff2d4fc3f886..2019249be083 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -256,7 +256,7 @@      <string name="global_action_power_off" msgid="4404936470711393203">"关机"</string>      <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_emergency" msgid="1387617624177105088">"紧急呼叫"</string>      <string name="global_action_bug_report" msgid="5127867163044170003">"错误报告"</string>      <string name="global_action_logout" msgid="6093581310002476511">"结束会话"</string>      <string name="global_action_screenshot" msgid="2610053466156478564">"屏幕截图"</string> @@ -844,7 +844,7 @@      <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="automotive" msgid="660804547737323300">"在不发出警告的情况下,通过恢复出厂设置来清除信息娱乐系统上的数据。"</string> -    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"恢复出厂设置时,系统会在不发出警告的情况下清除手机上的数据。"</string> +    <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"恢复出厂设置,不发出警告就直接清除手机上的数据。"</string>      <string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"清除个人资料数据"</string>      <string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"清空用户数据"</string>      <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"清空此用户在这台平板电脑上的数据,而不事先发出警告。"</string> @@ -990,7 +990,7 @@      <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"按 Menu 解锁或进行紧急呼救。"</string>      <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"按 MENU 解锁。"</string>      <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"绘制解锁图案"</string> -    <string name="lockscreen_emergency_call" msgid="7500692654885445299">"紧急呼救"</string> +    <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> @@ -1012,7 +1012,7 @@      <string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"停止"</string>      <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"快退"</string>      <string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"快进"</string> -    <string name="emergency_calls_only" msgid="3057351206678279851">"只能拨打紧急呼救电话"</string> +    <string name="emergency_calls_only" msgid="3057351206678279851">"只能拨打紧急呼叫电话"</string>      <string name="lockscreen_network_locked_message" msgid="2814046965899249635">"网络已锁定"</string>      <string name="lockscreen_sim_puk_locked_message" msgid="2867953953604224166">"SIM 卡已用 PUK 码锁定。"</string>      <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"请参阅《用户指南》或与客服人员联系。"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"测试"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"为安全起见而在屏幕共享画面中处于隐藏状态的应用内容"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"自动连接到卫星"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"您无需使用移动网络或 WLAN 网络便能收发消息"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"打开“信息”应用"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 6f560bb65078..e92b7f08b6a5 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"測試"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"共用"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"為安全起見,應用程式內容已從分享螢幕畫面隱藏"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"已自動連線至衛星"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"你可在沒有流動/Wi-Fi 網絡的情況下收發訊息"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"開啟「訊息」"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 8b2d5343ea38..124d17a805b3 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1725,7 +1725,7 @@      <string name="accessibility_enable_service_title" msgid="3931558336268541484">"要將裝置的完整控制權授予「<xliff:g id="SERVICE">%1$s</xliff:g>」嗎?"</string>      <string name="accessibility_service_warning_description" msgid="291674995220940133">"如果你有無障礙服務需求,建議可將完整控制權授予具有相關功能的應用程式,但請勿將完整控制權授予大多數的應用程式。"</string>      <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"查看及控制螢幕"</string> -    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"可讀取螢幕上的所有內容及在其他應用程式上顯示內容。"</string> +    <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"可讀取螢幕上的所有內容,並在其他應用程式上顯示內容。"</string>      <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"查看及執行動作"</string>      <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"可追蹤你與應用程式或硬體感應器的互動,並代表你與應用程式進行互動。"</string>      <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"允許"</string> @@ -1902,7 +1902,7 @@      <string name="confirm_battery_saver" msgid="5247976246208245754">"確定"</string>      <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"省電模式會開啟深色主題,並限制或關閉背景活動、某些視覺效果、特定功能和部分網路連線。"</string>      <string name="battery_saver_description" msgid="8518809702138617167">"省電模式會開啟深色主題,並限制或關閉背景活動、某些視覺效果、特定功能和部分網路連線。"</string> -    <string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你有一個使用中的應用程式仍可存取資料,但存取頻率可能會變低。舉例來說,圖片可能要等到你輕觸後才會顯示。"</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>      <string name="zen_mode_duration_minutes_summary" msgid="4555514757230849789">"{count,plural, =1{1 分鐘 (直到 {formattedTime})}other{# 分鐘 (直到 {formattedTime})}}"</string> @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"測試"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"通用"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"為安全起見,分享螢幕畫面未顯示應用程式內容"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"已自動連上衛星"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"你可以收發訊息,沒有行動/Wi-Fi 網路也無妨"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"開啟「訊息」應用程式"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 922172ce7f41..8ffb7a43b36c 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -2394,8 +2394,7 @@      <string name="profile_label_test" msgid="9168641926186071947">"Hlola"</string>      <string name="profile_label_communal" msgid="8743921499944800427">"Okomphakathi"</string>      <string name="redacted_notification_action_title" msgid="6942924973335920935"></string> -    <!-- no translation found for screen_not_shared_sensitive_content (7058419185079565001) --> -    <skip /> +    <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Okuqukethwe kwe-app kufihliwe kusuka ekwabelaneni kwesikrini ngokuvikelwa"</string>      <string name="satellite_notification_title" msgid="4026338973463121526">"Ixhumeke ngokuzenzakalelayo kusathelayithi"</string>      <string name="satellite_notification_summary" msgid="5207364139430767162">"Ungathumela futhi wamukele imilayezo ngaphandle kwenethiwekhi yeselula noma ye-Wi-Fi"</string>      <string name="satellite_notification_open_message" msgid="4149234979688273729">"Vula Imilayezo"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d4db244a852b..a622d36edc6a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4334,9 +4334,6 @@      -->      <bool name="config_wallpaperTopApp">false</bool> -    <!-- True if the device supports dVRR  --> -    <bool name="config_supportsDvrr">false</bool> -      <!-- True if the device supports at least one form of multi-window.           E.g. freeform, split-screen, picture-in-picture. -->      <bool name="config_supportsMultiWindow">true</bool> @@ -7018,4 +7015,9 @@      <!-- Frame rate compatibility value for Wallpaper           FRAME_RATE_COMPATIBILITY_MIN (102) is used by default for lower power consumption -->      <integer name="config_wallpaperFrameRateCompatibility">102</integer> + +    <!-- Min time in milliseconds to complete an emergency gesture for it count. +         If the gesture is completed faster than this, we assume it's not performed by human and the +         event gets ignored. --> +    <integer name="config_defaultMinEmergencyGestureTapDurationMillis">200</integer>  </resources> diff --git a/core/res/res/values/config_battery_stats.xml b/core/res/res/values/config_battery_stats.xml index e42962ce9195..ae4789937832 100644 --- a/core/res/res/values/config_battery_stats.xml +++ b/core/res/res/values/config_battery_stats.xml @@ -32,6 +32,9 @@      devices-->      <integer name="config_defaultPowerStatsThrottlePeriodCpu">60000</integer> +    <!-- Mobile Radio power stats collection throttle period in milliseconds. --> +    <integer name="config_defaultPowerStatsThrottlePeriodMobileRadio">3600000</integer> +      <!-- PowerStats aggregation period in milliseconds. This is the interval at which the power      stats aggregation procedure is performed and the results stored in PowerStatsStore. -->      <integer name="config_powerStatsAggregationPeriod">14400000</integer> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f33e2771879d..c4033f2d680a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -404,7 +404,6 @@    <java-symbol type="bool" name="config_supportAudioSourceUnprocessed" />    <java-symbol type="bool" name="config_freeformWindowManagement" />    <java-symbol type="bool" name="config_supportsBubble" /> -  <java-symbol type="bool" name="config_supportsDvrr" />    <java-symbol type="bool" name="config_supportsMultiWindow" />    <java-symbol type="bool" name="config_supportsSplitScreenMultiWindow" />    <java-symbol type="bool" name="config_supportsMultiDisplay" /> @@ -1528,6 +1527,7 @@    <java-symbol type="layout" name="number_picker" />    <java-symbol type="layout" name="permissions_package_list_item" />    <java-symbol type="layout" name="popup_menu_item_layout" /> +  <java-symbol type="layout" name="popup_menu_item_layout_material" />    <java-symbol type="layout" name="popup_menu_header_item_layout" />    <java-symbol type="layout" name="remote_views_adapter_default_loading_view" />    <java-symbol type="layout" name="search_bar" /> @@ -5217,6 +5217,7 @@    <java-symbol type="bool" name="config_batteryStatsResetOnUnplugHighBatteryLevel" />    <java-symbol type="bool" name="config_batteryStatsResetOnUnplugAfterSignificantCharge" />    <java-symbol type="integer" name="config_defaultPowerStatsThrottlePeriodCpu" /> +  <java-symbol type="integer" name="config_defaultPowerStatsThrottlePeriodMobileRadio" />    <java-symbol type="integer" name="config_powerStatsAggregationPeriod" />    <java-symbol type="integer" name="config_aggregatedPowerStatsSpanDuration" /> @@ -5401,4 +5402,6 @@    <!-- Frame rate compatibility value for Wallpaper -->    <java-symbol type="integer" name="config_wallpaperFrameRateCompatibility" /> + +  <java-symbol type="integer" name="config_defaultMinEmergencyGestureTapDurationMillis" />  </resources> diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index c8625b9114da..9bb72d9db6c7 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -28,7 +28,7 @@           standard SMS rate. The user is warned when the destination phone number matches the           "pattern" or "premium" regexes, and does not match the "free" or "standard" regexes. --> -    <!-- Harmonised European Short Codes are 6 digit numbers starting with 116 (free helplines). +    <!-- Harmonised European Short Codes are 7 digit numbers starting with 116 (free helplines).           Premium patterns include short codes from: http://aonebill.com/coverage&tariffs           and http://mobilcent.com/info-worldwide.asp and extracted from:           http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ --> @@ -39,8 +39,8 @@      <!-- Albania: 5 digits, known short codes listed -->      <shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" /> -    <!-- Argentina: 5 digits, known short codes listed --> -    <shortcode country="ar" pattern="\\d{5}" free="11711|28291|44077|78887" /> +    <!-- Argentina: 6 digits, known short codes listed --> +    <shortcode country="ar" pattern="\\d{1,6}" free="11711|28291|44077|78887|191289|39010" />      <!-- Armenia: 3-5 digits, emergency numbers 10[123] -->      <shortcode country="am" pattern="\\d{3,5}" premium="11[2456]1|3024" free="10[123]|71522|71512|71502" /> @@ -67,7 +67,7 @@      <shortcode country="bh" pattern="\\d{1,5}" free="81181|85999" />      <!-- Brazil: 1-5 digits (standard system default, not country specific) --> -    <shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d|876|5500|9963|4141|8000" /> +    <shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d|876|5500|9963|4141|8000|2652" />      <!-- Belarus: 4 digits -->      <shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" /> @@ -163,7 +163,7 @@      <shortcode country="in" pattern="\\d{1,5}" free="59336|53969" />      <!-- Indonesia: 1-5 digits (standard system default, not country specific) --> -    <shortcode country="id" pattern="\\d{1,5}" free="99477|6006|46645|363|93457" /> +    <shortcode country="id" pattern="\\d{1,5}" free="99477|6006|46645|363|93457|99265" />      <!-- Ireland: 5 digits, 5xxxx (50xxx=free, 5[12]xxx=standard), plus EU:           http://www.comreg.ie/_fileupload/publications/ComReg1117.pdf --> @@ -172,6 +172,9 @@      <!-- Israel: 1-5 digits, known premium codes listed -->      <shortcode country="il" pattern="\\d{1,5}" premium="4422|4545" free="37477|6681" /> +    <!-- Iran: 4-6 digits, known premium codes listed --> +    <shortcode country="ir" pattern="\\d{4,6}" free="700791|700792" /> +      <!-- Italy: 5 digits (premium=41xxx,42xxx), plus EU:           https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf -->      <shortcode country="it" pattern="\\d{5}" premium="44[0-4]\\d{2}|47[0-4]\\d{2}|48[0-4]\\d{2}|44[5-9]\\d{4}|47[5-9]\\d{4}|48[5-9]\\d{4}|455\\d{2}|499\\d{2}" free="116\\d{3}|4112503|40\\d{0,12}" standard="430\\d{2}|431\\d{2}|434\\d{4}|435\\d{4}|439\\d{7}" /> @@ -219,11 +222,11 @@      <!-- Mozambique: 1-5 digits (standard system default, not country specific) -->      <shortcode country="mz" pattern="\\d{1,5}" free="1714" /> -    <!-- Mexico: 4-5 digits (not confirmed), known premium codes listed --> -    <shortcode country="mx" pattern="\\d{4,6}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101|45453|550346" /> +    <!-- Mexico: 4-7 digits (not confirmed), known premium codes listed --> +    <shortcode country="mx" pattern="\\d{4,7}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101|45453|550346|3030303" />      <!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf --> -    <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" /> +    <shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668|66966" />      <!-- Namibia: 1-5 digits (standard system default, not country specific) -->      <shortcode country="na" pattern="\\d{1,5}" free="40005" /> @@ -255,6 +258,9 @@      <!-- Palestine: 5 digits, known premium codes listed -->      <shortcode country="ps" pattern="\\d{1,5}" free="37477|6681" /> +    <!-- Paraguay: 6 digits, known premium codes listed --> +    <shortcode country="py" pattern="\\d{6}" free="191289" /> +      <!-- Poland: 4-5 digits (not confirmed), known premium codes listed, plus EU -->      <shortcode country="pl" pattern="\\d{4,5}" premium="74240|79(?:10|866)|92525" free="116\\d{3}|8012|80921" /> @@ -275,7 +281,7 @@      <shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)|8424" free="6954|8501" standard="2037|2044"/>      <!-- Rwanda: 4 digits --> -    <shortcode country="rw" pattern="\\d{4}" free="5060" /> +    <shortcode country="rw" pattern="\\d{4}" free="5060|5061" />      <!-- Saudi Arabia -->      <shortcode country="sa" pattern="\\d{1,5}" free="8145" /> @@ -309,7 +315,10 @@      <shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" />      <!-- Tanzania: 1-5 digits (standard system default, not country specific) --> -    <shortcode country="tz" pattern="\\d{1,5}" free="15046|15234" /> +    <shortcode country="tz" pattern="\\d{1,5}" free="15046|15234|15324" /> + +    <!-- Tunisia: 5 digits, known premium codes listed --> +    <shortcode country="tn" pattern="\\d{5}" free="85799" />      <!-- Turkey -->      <shortcode country="tr" pattern="\\d{1,5}" free="7529|5528|6493|3193" /> @@ -324,8 +333,11 @@           visual voicemail code for T-Mobile: 122 -->      <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567|244444" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245|611611|96831" /> -    <!--Uruguay : 1-5 digits (standard system default, not country specific) --> -    <shortcode country="uy" pattern="\\d{1,5}" free="55002" /> +    <!--Uruguay : 1-6 digits (standard system default, not country specific) --> +    <shortcode country="uy" pattern="\\d{1,6}" free="55002|191289" /> + +    <!-- Venezuela: 1-6 digits (standard system default, not country specific) --> +    <shortcode country="ve" pattern="\\d{1,6}" free="538352" />      <!-- Vietnam: 1-5 digits (standard system default, not country specific) -->      <shortcode country="vn" pattern="\\d{1,5}" free="5001|9055|8079" /> @@ -336,6 +348,9 @@      <!-- South Africa -->      <shortcode country="za" pattern="\\d{1,5}" free="44136|30791|36056|33009" /> +    <!-- Yemen --> +    <shortcode country="ye" pattern="\\d{1,4}" free="5081" /> +      <!-- Zimbabwe -->      <shortcode country="zw" pattern="\\d{1,5}" free="33679" /> diff --git a/core/tests/FileSystemUtilsTest/Android.bp b/core/tests/FileSystemUtilsTest/Android.bp new file mode 100644 index 000000000000..53c22df67b85 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/Android.bp @@ -0,0 +1,78 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +//      http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { +    default_applicable_licenses: ["frameworks_base_license"], +    default_team: "trendy_team_android_kernel", +} + +cc_library { +    name: "libpunchtest", +    stl: "none", +    host_supported: true, +    srcs: ["jni/android_test_jni_source.cpp"], +    header_libs: ["jni_headers"], +} + +android_test_helper_app { +    name: "embedded_native_libs_test_app", +    srcs: ["apk_embedded_native_libs/src/**/*.java"], +    manifest: "apk_embedded_native_libs/embedded_native_libs_test_app.xml", +    compile_multilib: "64", +    jni_libs: [ +        "libpunchtest", +    ], +    static_libs: [ +        "androidx.test.rules", +        "platform-test-annotations", +    ], +    use_embedded_native_libs: true, +} + +android_test_helper_app { +    name: "extract_native_libs_test_app", +    srcs: ["apk_extract_native_libs/src/**/*.java"], +    manifest: "apk_extract_native_libs/extract_native_libs_test_app.xml", +    compile_multilib: "64", +    jni_libs: [ +        "libpunchtest", +    ], +    static_libs: [ +        "androidx.test.rules", +        "platform-test-annotations", +    ], +    use_embedded_native_libs: false, +} + +java_test_host { +    name: "FileSystemUtilsTests", +    // Include all test java files +    srcs: ["src/**/*.java"], +    static_libs: [ +        "junit", +        "platform-test-annotations", +        "truth", +    ], +    libs: [ +        "tradefed", +        "compatibility-host-util", +        "compatibility-tradefed", +    ], +    data: [ +        ":embedded_native_libs_test_app", +        ":extract_native_libs_test_app", +    ], +    test_suites: ["general-tests"], +    test_config: "AndroidTest.xml", +} diff --git a/core/tests/FileSystemUtilsTest/AndroidManifest.xml b/core/tests/FileSystemUtilsTest/AndroidManifest.xml new file mode 100644 index 000000000000..acd5ef3c90c2 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/AndroidManifest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2024 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT 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" +          android:installLocation="internalOnly" +          package="com.android.internal.content.fstests"> + +    <instrumentation +            android:name="androidx.test.runner.AndroidJUnitRunner" +            android:targetPackage="com.android.internal.content.fstests" +            android:label="Frameworks FileSystemUtils Tests" /> + +</manifest> diff --git a/core/tests/FileSystemUtilsTest/AndroidTest.xml b/core/tests/FileSystemUtilsTest/AndroidTest.xml new file mode 100644 index 000000000000..27f49b2289ba --- /dev/null +++ b/core/tests/FileSystemUtilsTest/AndroidTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2024 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  ~ See the License for the specific language governing permissions and +  ~ limitations under the License. +  --> + +<configuration description="Runs FileSystemUtilsTest."> +    <option name="test-suite-tag" value="apct"/> + +    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> +        <option name="cleanup-apks" value="true" /> +        <option name="test-file-name" value="embedded_native_libs_test_app.apk" /> +        <option name="test-file-name" value="extract_native_libs_test_app.apk" /> +    </target_preparer> + +    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" > +        <option name="jar" value="FileSystemUtilsTests.jar" /> +    </test> +</configuration> diff --git a/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/embedded_native_libs_test_app.xml b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/embedded_native_libs_test_app.xml new file mode 100644 index 000000000000..868f7f3b7799 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/embedded_native_libs_test_app.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2024 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT 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="android.test.embedded"> +    <application android:extractNativeLibs="false"> +        <uses-library android:name="android.test.runner"/> +        <activity android:name=".MainActivity" +                  android:exported="true" +                  android:process=":NewProcess"> +            <intent-filter> +                <action android:name="android.intent.action.MAIN"/> +                <category android:name="android.intent.category.LAUNCHER"/> +                <category android:name="android.intent.category.DEFAULT"/> +            </intent-filter> +        </activity> +    </application> +    <instrumentation +        android:name="androidx.test.runner.AndroidJUnitRunner" +        android:targetPackage="android.test.embedded"/> +</manifest>
\ No newline at end of file diff --git a/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/MainActivity.java b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/MainActivity.java new file mode 100644 index 000000000000..efa2a39881dc --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/MainActivity.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.test.embedded; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +import androidx.annotation.VisibleForTesting; + +public class MainActivity extends Activity { + +    static { +        System.loadLibrary("punchtest"); +    } + +    @VisibleForTesting +    static final String INTENT_TYPE = "android.test.embedded.EMBEDDED_LIB_LOADED"; + +    @VisibleForTesting +    static final String KEY_OPERAND_1 = "OP1"; + +    @VisibleForTesting +    static final String KEY_OPERAND_2 = "OP2"; + +    @VisibleForTesting +    static final String KEY_RESULT = "RESULT"; + +    @Override +    public void onCreate(Bundle savedOnstanceState) { +        super.onCreate(savedOnstanceState); + +        Intent received =  getIntent(); +        int op1 = received.getIntExtra(KEY_OPERAND_1, -1); +        int op2 = received.getIntExtra(KEY_OPERAND_2, -1); +        int result = add(op1, op2); + +        // Send broadcast so that test can know app has launched and lib is loaded +        // attach result which has been fetched from JNI lib +        Intent intent = new Intent(INTENT_TYPE); +        intent.putExtra(KEY_RESULT, result); +        sendBroadcast(intent); +    } + +    private native int add(int op1, int op2); +} diff --git a/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/PunchEmbeddedLibTest.java b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/PunchEmbeddedLibTest.java new file mode 100644 index 000000000000..d7d67b888490 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_embedded_native_libs/src/android/test/embedded/PunchEmbeddedLibTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.test.embedded; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class PunchEmbeddedLibTest { + +    @Test +    public void testPunchedNativeLibs_embeddedLib() throws Exception { +        Context context = InstrumentationRegistry.getContext(); +        CountDownLatch receivedSignal = new CountDownLatch(1); + +        // Test app is expected to receive this and perform addition of operands using punched lib +        int op1 = 48; +        int op2 = 75; +        IntentFilter intentFilter = new IntentFilter(MainActivity.INTENT_TYPE); +        BroadcastReceiver broadcastReceiver = +                new BroadcastReceiver() { +                    @Override +                    public void onReceive(Context context, Intent intent) { +                        receivedSignal.countDown(); +                        int result = intent.getIntExtra(MainActivity.KEY_RESULT, 1000); +                        Assert.assertEquals(result, op1 + op2); + +                    } +                }; +        context.registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_EXPORTED); + +        Intent launchIntent = +                context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); +        launchIntent.putExtra(MainActivity.KEY_OPERAND_1, op1); +        launchIntent.putExtra(MainActivity.KEY_OPERAND_2, op2); +        context.startActivity(launchIntent); + +        Assert.assertTrue("Failed to launch app", receivedSignal.await(10, TimeUnit.SECONDS)); +    } +} diff --git a/core/tests/FileSystemUtilsTest/apk_extract_native_libs/extract_native_libs_test_app.xml b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/extract_native_libs_test_app.xml new file mode 100644 index 000000000000..6db96f79b3f1 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/extract_native_libs_test_app.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2024 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT 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="android.test.extract"> +    <application android:extractNativeLibs="true"> +        <uses-library android:name="android.test.runner"/> +        <activity android:name=".MainActivity" +                  android:exported="true" +                  android:process=":NewProcess"> +            <intent-filter> +                <action android:name="android.intent.action.MAIN"/> +                <category android:name="android.intent.category.LAUNCHER"/> +                <category android:name="android.intent.category.DEFAULT"/> +            </intent-filter> +        </activity> +    </application> +    <instrumentation +        android:name="androidx.test.runner.AndroidJUnitRunner" +        android:targetPackage="android.test.extract"/> +</manifest>
\ No newline at end of file diff --git a/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/MainActivity.java b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/MainActivity.java new file mode 100644 index 000000000000..b1c157e17985 --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/MainActivity.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.test.extract; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +import androidx.annotation.VisibleForTesting; + +public class MainActivity extends Activity { + +    static { +        System.loadLibrary("punchtest"); +    } + +    @VisibleForTesting +    static final String INTENT_TYPE = "android.test.extract.EXTRACTED_LIB_LOADED"; + +    @VisibleForTesting +    static final String KEY_OPERAND_1 = "OP1"; + +    @VisibleForTesting +    static final String KEY_OPERAND_2 = "OP2"; + +    @VisibleForTesting +    static final String KEY_RESULT = "RESULT"; + +    @Override +    public void onCreate(Bundle savedOnstanceState) { +        super.onCreate(savedOnstanceState); + +        Intent received =  getIntent(); +        int op1 = received.getIntExtra(KEY_OPERAND_1, -1); +        int op2 = received.getIntExtra(KEY_OPERAND_2, -1); +        int result = subtract(op1, op2); + +        // Send broadcast so that test can know app has launched and lib is loaded +        // attach result which has been fetched from JNI lib +        Intent intent = new Intent(INTENT_TYPE); +        intent.putExtra(KEY_RESULT, result); +        sendBroadcast(intent); +    } + +    private native int subtract(int op1, int op2); +} diff --git a/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/PunchExtractedLibTest.java b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/PunchExtractedLibTest.java new file mode 100644 index 000000000000..7cc101751b3d --- /dev/null +++ b/core/tests/FileSystemUtilsTest/apk_extract_native_libs/src/android/test/extract/PunchExtractedLibTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.test.extract; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class PunchExtractedLibTest { + +    @Test +    public void testPunchedNativeLibs_extractedLib() throws Exception { +        Context context = InstrumentationRegistry.getContext(); +        CountDownLatch receivedSignal = new CountDownLatch(1); + +        // Test app is expected to receive this and perform subtraction using extracted lib +        int op1 = 100; +        int op2 = 71; +        IntentFilter intentFilter = new IntentFilter(MainActivity.INTENT_TYPE); +        BroadcastReceiver broadcastReceiver = +                new BroadcastReceiver() { +                    @Override +                    public void onReceive(Context context, Intent intent) { +                        receivedSignal.countDown(); +                        int result = intent.getIntExtra(MainActivity.KEY_RESULT, 1000); +                        Assert.assertEquals(result, op1 - op2); +                    } +                }; +        context.registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_EXPORTED); + +        Intent launchIntent = +                context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); +        launchIntent.putExtra(MainActivity.KEY_OPERAND_1, op1); +        launchIntent.putExtra(MainActivity.KEY_OPERAND_2, op2); +        context.startActivity(launchIntent); + +        Assert.assertTrue("Failed to launch app", receivedSignal.await(10, TimeUnit.SECONDS)); +    } +} diff --git a/core/tests/FileSystemUtilsTest/jni/android_test_jni_source.cpp b/core/tests/FileSystemUtilsTest/jni/android_test_jni_source.cpp new file mode 100644 index 000000000000..2a5ba817d9db --- /dev/null +++ b/core/tests/FileSystemUtilsTest/jni/android_test_jni_source.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <jni.h> + +// This will be called from embedded_native_libs_test_app +extern "C" JNIEXPORT +jint JNICALL Java_android_test_embedded_MainActivity_add(JNIEnv*, jclass, jint op1, jint op2) { +    return op1 + op2; +} + +// This will be called from extract_native_libs_test_app +extern "C" JNIEXPORT +jint JNICALL Java_android_test_extract_MainActivity_subtract(JNIEnv*, jclass, jint op1, jint op2) { +    return op1 - op2; +} + +// Initialize JNI +jint JNI_OnLoad(JavaVM *jvm, void */* reserved */) { +    JNIEnv *e; + +    // Check JNI version +    if (jvm->GetEnv((void **) &e, JNI_VERSION_1_6)) { +        return JNI_ERR; +    } + +    return JNI_VERSION_1_6; +} diff --git a/core/tests/FileSystemUtilsTest/src/com/android/internal/content/FileSystemUtilsTest.java b/core/tests/FileSystemUtilsTest/src/com/android/internal/content/FileSystemUtilsTest.java new file mode 100644 index 000000000000..77802e5e811a --- /dev/null +++ b/core/tests/FileSystemUtilsTest/src/com/android/internal/content/FileSystemUtilsTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.content; + +import static org.junit.Assert.assertTrue; + +import android.platform.test.annotations.AppModeFull; + +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class FileSystemUtilsTest extends BaseHostJUnit4Test { + +    @Test +    @AppModeFull +    public void runPunchedApp_embeddedNativeLibs() throws DeviceNotAvailableException { +        String appPackage = "android.test.embedded"; +        String testName = "PunchEmbeddedLibTest"; +        assertTrue(isPackageInstalled(appPackage)); +        runDeviceTests(appPackage, appPackage + "." + testName); +    } + +    @Test +    @AppModeFull +    public void runPunchedApp_extractedNativeLibs() throws DeviceNotAvailableException { +        String appPackage = "android.test.extract"; +        String testName = "PunchExtractedLibTest"; +        assertTrue(isPackageInstalled(appPackage)); +        runDeviceTests(appPackage, appPackage + "." + testName); +    } +} diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 48082048691c..04e90baaff3a 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -154,6 +154,12 @@ android_app {          "android.test.runner",          "org.apache.http.legacy",      ], +    uses_libs: [ +        "android.test.runner", +    ], +    optional_uses_libs: [ +        "org.apache.http.legacy", +    ],      sdk_version: "core_platform",  } @@ -267,5 +273,10 @@ android_ravenwood_test {          generate_get_transaction_name: true,          local_include_dirs: ["aidl"],      }, +    java_resources: [ +        "res/xml/power_profile_test.xml", +        "res/xml/power_profile_test_cpu_legacy.xml", +        "res/xml/power_profile_test_modem.xml", +    ],      auto_gen_config: true,  } diff --git a/core/tests/coretests/res/xml/power_profile_test.xml b/core/tests/coretests/res/xml/power_profile_test.xml index 322ae05bc63e..7356c9e38012 100644 --- a/core/tests/coretests/res/xml/power_profile_test.xml +++ b/core/tests/coretests/res/xml/power_profile_test.xml @@ -98,4 +98,16 @@          <value>40</value>          <value>50</value>      </array> -</device>
\ No newline at end of file + +    <!-- Idle current for bluetooth in mA.--> +    <item name="bluetooth.controller.idle">0.02</item> + +    <!-- Rx current for bluetooth in mA.--> +    <item name="bluetooth.controller.rx">3</item> + +    <!-- Tx current for bluetooth in mA--> +    <item name="bluetooth.controller.tx">5</item> + +    <!-- Operating voltage for bluetooth in mV.--> +    <item name="bluetooth.controller.voltage">3300</item> +</device> diff --git a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java index a5c854561293..5765562e2383 100644 --- a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java +++ b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java @@ -189,12 +189,16 @@ public class AutomaticZenRuleTest {      @Test      @EnableFlags(Flags.FLAG_MODES_API) -    public void builder_defaultTypeUnknown() { +    public void builder_defaultsAreSensible() {          AutomaticZenRule rule = new AutomaticZenRule.Builder("name",                  Uri.parse("conditionId")).build();          assertThat(rule.getType()).isEqualTo(AutomaticZenRule.TYPE_UNKNOWN); +        assertThat(rule.getInterruptionFilter()).isEqualTo( +                NotificationManager.INTERRUPTION_FILTER_PRIORITY); +        assertThat(rule.isEnabled()).isTrue();      } +      @Test      @EnableFlags(Flags.FLAG_MODES_API)      public void validate_builderWithValidType_succeeds() throws Exception { diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java index 2ce7a7d3d70d..a0aff6e7b9a0 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java +++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java @@ -16,7 +16,6 @@  package android.app.servertransaction; -import static android.content.Context.DEVICE_ID_DEFAULT;  import static android.view.Display.DEFAULT_DISPLAY;  import static org.junit.Assert.assertEquals; @@ -29,9 +28,6 @@ import static org.mockito.Mockito.verify;  import android.app.Activity;  import android.app.ActivityThread;  import android.app.ClientTransactionHandler; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo;  import android.content.res.Configuration;  import android.os.IBinder;  import android.os.RemoteException; @@ -107,35 +103,6 @@ public class ClientTransactionItemTest {      }      @Test -    public void testActivityConfigurationChangeItem_getContextToUpdate() { -        final ActivityConfigurationChangeItem item = ActivityConfigurationChangeItem -                .obtain(mActivityToken, mConfiguration, mActivityWindowInfo); -        final Context context = item.getContextToUpdate(mHandler); - -        assertEquals(mActivity, context); -    } - -    @Test -    public void testActivityRelaunchItem_getContextToUpdate() { -        final ActivityRelaunchItem item = ActivityRelaunchItem -                .obtain(mActivityToken, null /* pendingResults */, null  /* pendingNewIntents */, -                        0 /* configChange */, mMergedConfiguration, false /* preserveWindow */, -                        mActivityWindowInfo); -        final Context context = item.getContextToUpdate(mHandler); - -        assertEquals(mActivity, context); -    } - -    @Test -    public void testConfigurationChangeItem_getContextToUpdate() { -        final ConfigurationChangeItem item = ConfigurationChangeItem -                .obtain(mConfiguration, DEVICE_ID_DEFAULT); -        final Context context = item.getContextToUpdate(mHandler); - -        assertEquals(ActivityThread.currentApplication(), context); -    } - -    @Test      public void testDestroyActivityItem_preExecute() {          final DestroyActivityItem item = DestroyActivityItem                  .obtain(mActivityToken, false /* finished */); @@ -166,26 +133,6 @@ public class ClientTransactionItemTest {      }      @Test -    public void testLaunchActivityItem_getContextToUpdate() { -        final LaunchActivityItem item = new TestUtils.LaunchActivityItemBuilder( -                mActivityToken, new Intent(), new ActivityInfo()) -                .build(); - -        final Context context = item.getContextToUpdate(mHandler); - -        assertEquals(ActivityThread.currentApplication(), context); -    } - -    @Test -    public void testMoveToDisplayItem_getContextToUpdate() { -        final MoveToDisplayItem item = MoveToDisplayItem -                .obtain(mActivityToken, DEFAULT_DISPLAY, mConfiguration, mActivityWindowInfo); -        final Context context = item.getContextToUpdate(mHandler); - -        assertEquals(mActivity, context); -    } - -    @Test      public void testWindowContextInfoChangeItem_execute() {          final WindowContextInfoChangeItem item = WindowContextInfoChangeItem                  .obtain(mWindowClientToken, mConfiguration, DEFAULT_DISPLAY); @@ -196,17 +143,6 @@ public class ClientTransactionItemTest {      }      @Test -    public void testWindowContextInfoChangeItem_getContextToUpdate() { -        doReturn(mWindowContext).when(mHandler).getWindowContext(mWindowClientToken); - -        final WindowContextInfoChangeItem item = WindowContextInfoChangeItem -                .obtain(mWindowClientToken, mConfiguration, DEFAULT_DISPLAY); -        final Context context = item.getContextToUpdate(mHandler); - -        assertEquals(mWindowContext, context); -    } - -    @Test      public void testWindowContextWindowRemovalItem_execute() {          final WindowContextWindowRemovalItem item = WindowContextWindowRemovalItem.obtain(                  mWindowClientToken); @@ -220,7 +156,7 @@ public class ClientTransactionItemTest {          final WindowStateResizeItem item = WindowStateResizeItem.obtain(mWindow, mFrames,                  true /* reportDraw */, mMergedConfiguration, mInsetsState, true /* forceLayout */,                  true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */, -                true /* dragResizing */, mActivityToken, mActivityWindowInfo); +                true /* dragResizing */, mActivityWindowInfo);          item.execute(mHandler, mPendingActions);          verify(mWindow).resized(mFrames, @@ -228,16 +164,4 @@ public class ClientTransactionItemTest {                  true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */,                  true /* dragResizing */, mActivityWindowInfo);      } - -    @Test -    public void testWindowStateResizeItem_getContextToUpdate() { -        final WindowStateResizeItem item = WindowStateResizeItem.obtain(mWindow, mFrames, -                true /* reportDraw */, mMergedConfiguration, mInsetsState, true /* forceLayout */, -                true /* alwaysConsumeSystemBars */, 123 /* displayId */, 321 /* syncSeqId */, -                true /* dragResizing */, mActivityToken, mActivityWindowInfo); -        final Context context = item.getContextToUpdate(mHandler); - -        assertEquals(ActivityThread.currentApplication(), context); -    } -  } diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java index 77d31a5f27e7..8506905e6ca0 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java +++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java @@ -23,11 +23,17 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat  import static com.android.window.flags.Flags.FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG;  import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt;  import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doNothing;  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 android.app.Activity; +import android.content.res.Configuration; +import android.content.res.Resources;  import android.graphics.Rect;  import android.hardware.display.DisplayManager;  import android.hardware.display.DisplayManagerGlobal; @@ -76,6 +82,13 @@ public class ClientTransactionListenerControllerTest {      private BiConsumer<IBinder, ActivityWindowInfo> mActivityWindowInfoListener;      @Mock      private IBinder mActivityToken; +    @Mock +    private Activity mActivity; +    @Mock +    private Resources mResources; + +    private Configuration mConfiguration; +      private DisplayManagerGlobal mDisplayManager;      private Handler mHandler; @@ -88,7 +101,12 @@ public class ClientTransactionListenerControllerTest {          MockitoAnnotations.initMocks(this);          mDisplayManager = new DisplayManagerGlobal(mIDisplayManager);          mHandler = getInstrumentation().getContext().getMainThreadHandler(); -        mController = ClientTransactionListenerController.createInstanceForTesting(mDisplayManager); +        mController = spy(ClientTransactionListenerController +                .createInstanceForTesting(mDisplayManager)); + +        mConfiguration = new Configuration(); +        doReturn(mConfiguration).when(mResources).getConfiguration(); +        doReturn(mResources).when(mActivity).getResources();      }      @Test @@ -107,6 +125,43 @@ public class ClientTransactionListenerControllerTest {      }      @Test +    public void testOnContextConfigurationChanged() { +        doNothing().when(mController).onDisplayChanged(anyInt()); +        doReturn(123).when(mActivity).getDisplayId(); + +        // Not trigger onDisplayChanged when there is no change. +        mController.onContextConfigurationPreChanged(mActivity); +        mController.onContextConfigurationPostChanged(mActivity); + +        verify(mController, never()).onDisplayChanged(anyInt()); + +        mController.onContextConfigurationPreChanged(mActivity); +        mConfiguration.windowConfiguration.setMaxBounds(new Rect(0, 0, 100, 200)); +        mController.onContextConfigurationPostChanged(mActivity); + +        verify(mController).onDisplayChanged(123); +    } + +    @Test +    public void testOnContextConfigurationChanged_duringClientTransaction() { +        doNothing().when(mController).onDisplayChanged(anyInt()); +        doReturn(123).when(mActivity).getDisplayId(); + +        // Not trigger onDisplayChanged until ClientTransaction finished execution. +        mController.onClientTransactionStarted(); + +        mController.onContextConfigurationPreChanged(mActivity); +        mConfiguration.windowConfiguration.setMaxBounds(new Rect(0, 0, 100, 200)); +        mController.onContextConfigurationPostChanged(mActivity); + +        verify(mController, never()).onDisplayChanged(anyInt()); + +        mController.onClientTransactionFinished(); + +        verify(mController).onDisplayChanged(123); +    } + +    @Test      public void testActivityWindowInfoChangedListener() {          mSetFlagsRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG); diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java index 442394e3428a..0697c96052f6 100644 --- a/core/tests/coretests/src/android/os/ParcelTest.java +++ b/core/tests/coretests/src/android/os/ParcelTest.java @@ -16,6 +16,8 @@  package android.os; +import static com.google.common.truth.Truth.assertThat; +  import static org.junit.Assert.assertEquals;  import static org.junit.Assert.assertFalse;  import static org.junit.Assert.assertThrows; @@ -24,6 +26,7 @@ import static org.junit.Assert.assertTrue;  import android.platform.test.annotations.IgnoreUnderRavenwood;  import android.platform.test.annotations.Presubmit;  import android.platform.test.ravenwood.RavenwoodRule; +import android.util.Log;  import androidx.test.runner.AndroidJUnit4; @@ -31,6 +34,8 @@ import org.junit.Rule;  import org.junit.Test;  import org.junit.runner.RunWith; +import java.util.ArrayList; +  @Presubmit  @RunWith(AndroidJUnit4.class)  public class ParcelTest { @@ -349,6 +354,50 @@ public class ParcelTest {      }      @Test +    public void testClassCookies() { +        Parcel p = Parcel.obtain(); +        assertThat(p.hasClassCookie(ParcelTest.class)).isFalse(); + +        p.setClassCookie(ParcelTest.class, "string_cookie"); +        assertThat(p.hasClassCookie(ParcelTest.class)).isTrue(); +        assertThat(p.getClassCookie(ParcelTest.class)).isEqualTo("string_cookie"); + +        p.removeClassCookie(ParcelTest.class, "string_cookie"); +        assertThat(p.hasClassCookie(ParcelTest.class)).isFalse(); +        assertThat(p.getClassCookie(ParcelTest.class)).isEqualTo(null); + +        p.setClassCookie(ParcelTest.class, "to_be_discarded_cookie"); +        p.recycle(); +        assertThat(p.getClassCookie(ParcelTest.class)).isNull(); +    } + +    @Test +    public void testClassCookies_removeUnexpected() { +        Parcel p = Parcel.obtain(); + +        assertLogsWtf(() -> p.removeClassCookie(ParcelTest.class, "not_present")); + +        p.setClassCookie(ParcelTest.class, "value"); + +        assertLogsWtf(() -> p.removeClassCookie(ParcelTest.class, "different")); +        assertThat(p.getClassCookie(ParcelTest.class)).isNull(); // still removed + +        p.recycle(); +    } + +    private static void assertLogsWtf(Runnable test) { +        ArrayList<Log.TerribleFailure> wtfs = new ArrayList<>(); +        Log.TerribleFailureHandler oldHandler = Log.setWtfHandler( +                (tag, what, system) -> wtfs.add(what)); +        try { +            test.run(); +        } finally { +            Log.setWtfHandler(oldHandler); +        } +        assertThat(wtfs).hasSize(1); +    } + +    @Test      @IgnoreUnderRavenwood(blockedBy = Parcel.class)      public void testHasBinders_AfterWritingBinderToParcel() {          Binder binder = new Binder(); @@ -360,7 +409,6 @@ public class ParcelTest {          assertTrue(pA.hasBinders());      } -      @Test      @IgnoreUnderRavenwood(blockedBy = Parcel.class)      public void testHasBindersInRange_AfterWritingBinderToParcel() { diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index 97f894f8dcac..4fb85c1fa7ff 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -25,9 +25,7 @@ import static android.view.InsetsSource.FLAG_ANIMATE_RESIZING;  import static android.view.InsetsSource.ID_IME;  import static android.view.InsetsSourceConsumer.ShowResult.IME_SHOW_DELAYED;  import static android.view.InsetsSourceConsumer.ShowResult.SHOW_IMMEDIATELY; -import static android.view.ViewRootImpl.CAPTION_ON_SHELL;  import static android.view.WindowInsets.Type.all; -import static android.view.WindowInsets.Type.captionBar;  import static android.view.WindowInsets.Type.defaultVisible;  import static android.view.WindowInsets.Type.ime;  import static android.view.WindowInsets.Type.navigationBars; @@ -49,7 +47,6 @@ import static org.mockito.ArgumentMatchers.notNull;  import static org.mockito.Mockito.clearInvocations;  import static org.mockito.Mockito.mock;  import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset;  import static org.mockito.Mockito.spy;  import static org.mockito.Mockito.times;  import static org.mockito.Mockito.verify; @@ -805,48 +802,6 @@ public class InsetsControllerTest {      }      @Test -    public void testCaptionInsetsStateAssemble() { -        if (CAPTION_ON_SHELL) { -            // For this case, the test is covered by WindowContainerInsetsSourceProviderTest, This -            // test can be removed after the caption is moved to shell completely. -            return; -        } -        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { -            final Rect frame = new Rect(0, 0, 100, 300); -            final int captionBarHeight = 100; -            final InsetsState state = mController.getState(); -            mController.onFrameChanged(frame); -            mController.setCaptionInsetsHeight(captionBarHeight); -            // The caption bar insets height should be the same as the caption bar height. -            assertEquals(captionBarHeight, state.calculateInsets(frame, captionBar(), false).top); -            // Test update to remove the caption bar -            mController.setCaptionInsetsHeight(0); -            // The caption bar source should not be there at all, because we don't add empty -            // caption to the state from the server. -            for (int i = state.sourceSize() - 1; i >= 0; i--) { -                assertNotEquals(captionBar(), state.sourceAt(i).getType()); -            } -        }); -    } - -    @Test -    public void testNotifyCaptionInsetsOnlyChange() { -        if (CAPTION_ON_SHELL) { -            // For this case, the test is covered by WindowContainerInsetsSourceProviderTest, This -            // test can be removed after the caption is moved to shell completely. -            return; -        } -        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { -            reset(mTestHost); -            mController.setCaptionInsetsHeight(100); -            verify(mTestHost).notifyInsetsChanged(); -            reset(mTestHost); -            mController.setCaptionInsetsHeight(0); -            verify(mTestHost).notifyInsetsChanged(); -        }); -    } - -    @Test      public void testRequestedState() {          InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {              mController.hide(statusBars() | navigationBars()); diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java index dcfbf6437930..28343f1faeda 100644 --- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java +++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java @@ -19,7 +19,6 @@ package android.view;  import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;  import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;  import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL; -import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE;  import static android.view.flags.Flags.FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY;  import static android.view.flags.Flags.FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY;  import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY; @@ -27,18 +26,23 @@ import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;  import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly;  import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly;  import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly; +import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly;  import static junit.framework.Assert.assertEquals;  import static org.junit.Assert.assertFalse;  import static org.junit.Assert.assertTrue; +import android.annotation.NonNull;  import android.app.Activity; +import android.os.Handler; +import android.os.Looper;  import android.os.SystemClock;  import android.platform.test.annotations.RequiresFlagsEnabled;  import android.platform.test.flag.junit.CheckFlagsRule;  import android.platform.test.flag.junit.DeviceFlagsValueProvider;  import android.util.DisplayMetrics; +import android.widget.FrameLayout;  import androidx.test.annotation.UiThreadTest;  import androidx.test.filters.SmallTest; @@ -69,6 +73,8 @@ public class ViewFrameRateTest {      private Activity mActivity;      private View mMovingView;      private ViewRootImpl mViewRoot; +    private CountDownLatch mAfterDrawLatch; +    private Throwable mAfterDrawThrowable;      @Before      public void setUp() throws Throwable { @@ -82,23 +88,34 @@ public class ViewFrameRateTest {              parent = parent.getParent();          }          mViewRoot = (ViewRootImpl) parent; +        mAfterDrawThrowable = null;      } -    @UiThreadTest      @Test      @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API,              FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) -    public void frameRateChangesWhenContentMoves() { -        mMovingView.offsetLeftAndRight(100); -        float frameRate = mViewRoot.getPreferredFrameRate(); -        assertTrue(frameRate > 0); +    public void frameRateChangesWhenContentMoves() throws Throwable { +        waitForFrameRateCategoryToSettle(); +        mActivityRule.runOnUiThread(() -> { +            mMovingView.offsetLeftAndRight(100); +            runAfterDraw(() -> { +                if (toolkitFrameRateVelocityMappingReadOnly()) { +                    float frameRate = mViewRoot.getLastPreferredFrameRate(); +                    assertTrue(frameRate > 0); +                } else { +                    assertEquals(FRAME_RATE_CATEGORY_HIGH, +                            mViewRoot.getLastPreferredFrameRateCategory()); +                } +            }); +        }); +        waitForAfterDraw();      }      @UiThreadTest      @Test      @RequiresFlagsEnabled(FLAG_VIEW_VELOCITY_API)      public void firstFrameNoMovement() { -        assertEquals(0f, mViewRoot.getPreferredFrameRate(), 0f); +        assertEquals(0f, mViewRoot.getLastPreferredFrameRate(), 0f);      }      @Test @@ -141,9 +158,34 @@ public class ViewFrameRateTest {          mActivityRule.runOnUiThread(() -> {              mMovingView.setFrameContentVelocity(1f);              mMovingView.invalidate(); -            assertEquals(60f, mViewRoot.getPreferredFrameRate(), 0f); -            assertEquals(FRAME_RATE_COMPATIBILITY_GTE, mViewRoot.getFrameRateCompatibility()); +            runAfterDraw(() -> assertEquals(60f, mViewRoot.getLastPreferredFrameRate(), 0f)); +        }); +        waitForAfterDraw(); +    } + +    @Test +    @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API, +            FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY, +            FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) +    public void velocityWithChildMovement() throws Throwable { +        FrameLayout frameLayout = new FrameLayout(mActivity); +        mActivityRule.runOnUiThread(() -> { +            ViewGroup.LayoutParams fullSize = new ViewGroup.LayoutParams( +                    ViewGroup.LayoutParams.MATCH_PARENT, +                    ViewGroup.LayoutParams.MATCH_PARENT); +            mActivity.setContentView(frameLayout, fullSize); +            if (mMovingView.getParent() instanceof ViewGroup) { +                ((ViewGroup) mMovingView.getParent()).removeView(mMovingView); +            } +            frameLayout.addView(mMovingView, fullSize); +        }); +        waitForFrameRateCategoryToSettle(); +        mActivityRule.runOnUiThread(() -> { +            frameLayout.setFrameContentVelocity(1f); +            mMovingView.offsetTopAndBottom(100); +            runAfterDraw(() -> assertEquals(60f, mViewRoot.getLastPreferredFrameRate(), 0f));          }); +        waitForAfterDraw();      }      @Test @@ -161,23 +203,9 @@ public class ViewFrameRateTest {          mActivityRule.runOnUiThread(() -> {              mMovingView.setFrameContentVelocity(1_000_000_000f);              mMovingView.invalidate(); -            assertEquals(140f, mViewRoot.getPreferredFrameRate(), 0f); -            assertEquals(FRAME_RATE_COMPATIBILITY_GTE, mViewRoot.getFrameRateCompatibility()); +            runAfterDraw(() -> assertEquals(140f, mViewRoot.getLastPreferredFrameRate(), 0f));          }); -    } - -    private void waitForFrameRateCategoryToSettle() throws Throwable { -        for (int i = 0; i < 5; i++) { -            final CountDownLatch drawLatch = new CountDownLatch(1); - -            // Now that it is small, any invalidation should have a normal category -            mActivityRule.runOnUiThread(() -> { -                mMovingView.invalidate(); -                mMovingView.getViewTreeObserver().addOnDrawListener(drawLatch::countDown); -            }); - -            assertTrue(drawLatch.await(1, TimeUnit.SECONDS)); -        } +        waitForAfterDraw();      }      @Test @@ -211,8 +239,10 @@ public class ViewFrameRateTest {              mMovingView.invalidate();              int expected = toolkitFrameRateBySizeReadOnly()                      ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL; -            assertEquals(expected, mViewRoot.getPreferredFrameRateCategory()); +            runAfterDraw( +                    () -> assertEquals(expected, mViewRoot.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw();      }      @Test @@ -245,8 +275,10 @@ public class ViewFrameRateTest {              mMovingView.invalidate();              int expected = toolkitFrameRateBySizeReadOnly()                      ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL; -            assertEquals(expected, mViewRoot.getPreferredFrameRateCategory()); +            runAfterDraw( +                    () -> assertEquals(expected, mViewRoot.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw();      }      @Test @@ -279,8 +311,10 @@ public class ViewFrameRateTest {              mMovingView.invalidate();              int expected = toolkitFrameRateBySizeReadOnly()                      ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL; -            assertEquals(expected, mViewRoot.getPreferredFrameRateCategory()); +            runAfterDraw( +                    () -> assertEquals(expected, mViewRoot.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw();      }      @Test @@ -313,8 +347,10 @@ public class ViewFrameRateTest {              mMovingView.invalidate();              int expected = toolkitFrameRateDefaultNormalReadOnly()                      ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; -            assertEquals(expected, mViewRoot.getPreferredFrameRateCategory()); +            runAfterDraw( +                    () -> assertEquals(expected, mViewRoot.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw();      }      @Test @@ -347,8 +383,10 @@ public class ViewFrameRateTest {              mMovingView.invalidate();              int expected = toolkitFrameRateDefaultNormalReadOnly()                      ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; -            assertEquals(expected, mViewRoot.getPreferredFrameRateCategory()); +            runAfterDraw( +                    () -> assertEquals(expected, mViewRoot.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw();      }      @Test @@ -367,8 +405,54 @@ public class ViewFrameRateTest {              mMovingView.invalidate();              int expected = toolkitFrameRateDefaultNormalReadOnly()                      ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; -            assertEquals(expected, -                    mViewRoot.getPreferredFrameRateCategory()); +            runAfterDraw(() -> assertEquals(expected, +                    mViewRoot.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw(); +    } + +    private void runAfterDraw(@NonNull Runnable runnable) { +        Handler handler = new Handler(Looper.getMainLooper()); +        mAfterDrawLatch = new CountDownLatch(1); +        ViewTreeObserver.OnDrawListener listener = new ViewTreeObserver.OnDrawListener() { +            @Override +            public void onDraw() { +                handler.postAtFrontOfQueue(() -> { +                    mMovingView.getViewTreeObserver().removeOnDrawListener(this); +                    try { +                        runnable.run(); +                    } catch (Throwable t) { +                        mAfterDrawThrowable = t; +                    } +                    mAfterDrawLatch.countDown(); +                }); +            } +        }; +        mMovingView.getViewTreeObserver().addOnDrawListener(listener); +    } + +    private void waitForAfterDraw() throws Throwable { +        assertTrue(mAfterDrawLatch.await(1, TimeUnit.SECONDS)); +        if (mAfterDrawThrowable != null) { +            throw mAfterDrawThrowable; +        } +    } + +    private void waitForFrameRateCategoryToSettle() throws Throwable { +        for (int i = 0; i < 5 || mViewRoot.getIsFrameRateBoosting(); i++) { +            final CountDownLatch drawLatch = new CountDownLatch(1); + +            // Now that it is small, any invalidation should have a normal category +            ViewTreeObserver.OnDrawListener listener = drawLatch::countDown; + +            mActivityRule.runOnUiThread(() -> { +                mMovingView.invalidate(); +                mMovingView.getViewTreeObserver().addOnDrawListener(listener); +            }); + +            assertTrue(drawLatch.await(1, TimeUnit.SECONDS)); +            mActivityRule.runOnUiThread( +                    () -> mMovingView.getViewTreeObserver().removeOnDrawListener(listener)); +        }      }  } diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index 90ee36e07268..e6e7e8c157fc 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -43,7 +43,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;  import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;  import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;  import static android.view.WindowManager.LayoutParams.TYPE_TOAST; +import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly;  import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly; +import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly;  import static com.google.common.truth.Truth.assertThat;  import static com.google.common.truth.Truth.assertWithMessage; @@ -54,6 +56,7 @@ import static org.junit.Assert.assertTrue;  import static org.junit.Assert.fail;  import static org.junit.Assume.assumeTrue; +import android.annotation.NonNull;  import android.app.Instrumentation;  import android.app.UiModeManager;  import android.content.Context; @@ -107,6 +110,7 @@ public class ViewRootImplTest {      public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();      private ViewRootImpl mViewRootImpl; +    private View mView;      private volatile boolean mKeyReceived = false;      private static Context sContext; @@ -116,6 +120,9 @@ public class ViewRootImplTest {      // state after the test completes.      private static boolean sOriginalTouchMode; +    private CountDownLatch mAfterDrawLatch; +    private Throwable mAfterDrawThrowable; +      @Rule      public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @@ -148,6 +155,16 @@ public class ViewRootImplTest {              setForceDarkSysProp(false);          }); +        if (mView != null) { +            sInstrumentation.runOnMainSync(() -> { +                WindowManager wm = sContext.getSystemService(WindowManager.class); +                wm.removeView(mView); +            }); +            mView = null; +        } +        mViewRootImpl = null; +        mAfterDrawLatch = null; +        mAfterDrawThrowable = null;      }      @Test @@ -309,7 +326,7 @@ public class ViewRootImplTest {       */      @Test      public void requestScrollCapture_timeout() { -        final View view = new View(sContext); +        View view = new View(sContext);          view.setScrollCaptureCallback(new TestScrollCaptureCallback()); // Does nothing          sInstrumentation.runOnMainSync(() -> {              WindowManager.LayoutParams wmlp = @@ -337,9 +354,9 @@ public class ViewRootImplTest {      @Test      public void whenTouchModeChanges_viewRootIsNotified() throws Exception { -        View view = new View(sContext); -        attachViewToWindow(view); -        ViewTreeObserver viewTreeObserver = view.getRootView().getViewTreeObserver(); +        mView = new View(sContext); +        attachViewToWindow(mView); +        ViewTreeObserver viewTreeObserver = mView.getRootView().getViewTreeObserver();          CountDownLatch latch = new CountDownLatch(1);          ViewTreeObserver.OnTouchModeChangeListener touchModeListener = (boolean inTouchMode) -> {              assertWithMessage("addOnTouchModeChangeListener parameter").that( @@ -349,10 +366,10 @@ public class ViewRootImplTest {          viewTreeObserver.addOnTouchModeChangeListener(touchModeListener);          try { -            view.requestFocusFromTouch(); +            mView.requestFocusFromTouch();              assertThat(latch.await(1, TimeUnit.SECONDS)).isTrue(); -            assertThat(view.isInTouchMode()).isFalse(); +            assertThat(mView.isInTouchMode()).isFalse();          } finally {              viewTreeObserver.removeOnTouchModeChangeListener(touchModeListener);          } @@ -360,25 +377,25 @@ public class ViewRootImplTest {      @Test      public void whenDispatchFakeFocus_focusDoesNotPersist() throws Exception { -        View view = new View(sContext); -        attachViewToWindow(view); -        view.clearFocus(); +        mView = new View(sContext); +        attachViewToWindow(mView); +        mView.clearFocus(); -        assertThat(view.hasWindowFocus()).isFalse(); +        assertThat(mView.hasWindowFocus()).isFalse(); -        mViewRootImpl = view.getViewRootImpl(); +        mViewRootImpl = mView.getViewRootImpl();          mViewRootImpl.dispatchCompatFakeFocus(); -        assertThat(view.hasWindowFocus()).isFalse(); +        assertThat(mView.hasWindowFocus()).isFalse();      }      @Test      @RequiresFlagsEnabled(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)      public void whenViewIsAttachedToWindow_getHostToken() { -        View view = new View(sContext); -        attachViewToWindow(view); +        mView = new View(sContext); +        attachViewToWindow(mView); -        mViewRootImpl = view.getViewRootImpl(); +        mViewRootImpl = mView.getViewRootImpl();          assertThat(mViewRootImpl.getInputTransferToken()).isNotEqualTo(null);      } @@ -482,9 +499,9 @@ public class ViewRootImplTest {      public void votePreferredFrameRate_getDefaultValues() {          ViewRootImpl viewRootImpl = new ViewRootImpl(sContext,                  sContext.getDisplayNoVerify()); -        assertEquals(viewRootImpl.getPreferredFrameRateCategory(), +        assertEquals(viewRootImpl.getLastPreferredFrameRateCategory(),                  FRAME_RATE_CATEGORY_NO_PREFERENCE); -        assertEquals(viewRootImpl.getPreferredFrameRate(), 0, 0.1); +        assertEquals(viewRootImpl.getLastPreferredFrameRate(), 0, 0.1);      }      /** @@ -497,28 +514,31 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_BY_SIZE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY}) -    public void votePreferredFrameRate_voteFrameRateCategory_visibility_bySize() { -        View view = new View(sContext); -        attachViewToWindow(view); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +    public void votePreferredFrameRate_voteFrameRateCategory_visibility_bySize() throws Throwable { +        mView = new View(sContext); +        attachViewToWindow(mView); +        mViewRootImpl = mView.getViewRootImpl(); +        waitForFrameRateCategoryToSettle(mView); +        ViewTreeObserver.OnDrawListener failIfDrawn = () -> fail("Should not draw invisible views");          sInstrumentation.runOnMainSync(() -> { -            view.setVisibility(View.INVISIBLE); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), -                    FRAME_RATE_CATEGORY_NO_PREFERENCE); +            mView.setVisibility(View.INVISIBLE); +            mView.invalidate(); +            mView.getViewTreeObserver().addOnDrawListener(failIfDrawn);          });          sInstrumentation.waitForIdleSync(); +        mView.getViewTreeObserver().removeOnDrawListener(failIfDrawn);          sInstrumentation.runOnMainSync(() -> { -            view.setVisibility(View.VISIBLE); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), -                    FRAME_RATE_CATEGORY_NORMAL); +            mView.setVisibility(View.VISIBLE); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(FRAME_RATE_CATEGORY_HIGH, +                    mViewRootImpl.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw();          sInstrumentation.waitForIdleSync();          sInstrumentation.runOnMainSync(() -> { -            assertEquals(viewRootImpl.getIsFrameRateBoosting(), true); +            assertEquals(mViewRootImpl.getIsFrameRateBoosting(), true);          });      } @@ -531,8 +551,8 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_BY_SIZE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY}) -    public void votePreferredFrameRate_voteFrameRateCategory_smallSize_bySize() { -        View view = new View(sContext); +    public void votePreferredFrameRate_voteFrameRateCategory_smallSize_bySize() throws Throwable { +        mView = new View(sContext);          WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);          wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check          wmlp.width = 1; @@ -540,15 +560,18 @@ public class ViewRootImplTest {          sInstrumentation.runOnMainSync(() -> {              WindowManager wm = sContext.getSystemService(WindowManager.class); -            wm.addView(view, wmlp); +            wm.addView(mView, wmlp);          });          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        mViewRootImpl = mView.getViewRootImpl(); +        waitForFrameRateCategoryToSettle(mView);          sInstrumentation.runOnMainSync(() -> { -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                    FRAME_RATE_CATEGORY_LOW));          }); +        waitForAfterDraw();      }      /** @@ -560,8 +583,8 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_BY_SIZE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY}) -    public void votePreferredFrameRate_voteFrameRateCategory_normalSize_bySize() { -        View view = new View(sContext); +    public void votePreferredFrameRate_voteFrameRateCategory_normalSize_bySize() throws Throwable { +        mView = new View(sContext);          WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);          wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check @@ -572,15 +595,18 @@ public class ViewRootImplTest {              display.getMetrics(metrics);              wmlp.width = (int) (metrics.widthPixels * 0.9);              wmlp.height = (int) (metrics.heightPixels * 0.9); -            wm.addView(view, wmlp); +            wm.addView(mView, wmlp);          });          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        mViewRootImpl = mView.getViewRootImpl(); +        waitForFrameRateCategoryToSettle(mView);          sInstrumentation.runOnMainSync(() -> { -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_NORMAL); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(FRAME_RATE_CATEGORY_NORMAL, +                    mViewRootImpl.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw();      }      /** @@ -593,30 +619,56 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) -    public void votePreferredFrameRate_voteFrameRateCategory_visibility_defaultHigh() { -        View view = new View(sContext); -        attachViewToWindow(view); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +    public void votePreferredFrameRate_voteFrameRateCategory_visibility_defaultHigh() +            throws Throwable { +        mView = new View(sContext); +        WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY); +        wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check +          sInstrumentation.runOnMainSync(() -> { -            view.setVisibility(View.INVISIBLE); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), -                    FRAME_RATE_CATEGORY_NO_PREFERENCE); +            DisplayMetrics metrics = sContext.getResources().getDisplayMetrics(); +            wmlp.width = metrics.widthPixels / 2; +            wmlp.height = metrics.heightPixels / 2; +            WindowManager wm = sContext.getSystemService(WindowManager.class); +            wm.addView(mView, wmlp);          });          sInstrumentation.waitForIdleSync(); +        mViewRootImpl = mView.getViewRootImpl(); +        waitForFrameRateCategoryToSettle(mView); +        ViewTreeObserver.OnDrawListener failIfDrawn = () -> fail("Draw was not expected!"); +        sInstrumentation.runOnMainSync(() -> { +            mView.setVisibility(View.INVISIBLE); +            mView.invalidate(); +            mView.getViewTreeObserver().addOnDrawListener(failIfDrawn); +        }); +        sInstrumentation.waitForIdleSync(); +        sInstrumentation.runOnMainSync( +                () -> mView.getViewTreeObserver().removeOnDrawListener(failIfDrawn));          sInstrumentation.runOnMainSync(() -> { -            view.setVisibility(View.VISIBLE); -            view.invalidate(); -            int expected = toolkitFrameRateDefaultNormalReadOnly() -                    ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; -            assertEquals(expected, viewRootImpl.getPreferredFrameRateCategory()); +            mView.setVisibility(View.VISIBLE); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(FRAME_RATE_CATEGORY_HIGH, +                    mViewRootImpl.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw();          sInstrumentation.waitForIdleSync();          sInstrumentation.runOnMainSync(() -> { -            assertEquals(viewRootImpl.getIsFrameRateBoosting(), true); +            assertEquals(mViewRootImpl.getIsFrameRateBoosting(), true);          }); + +        waitForFrameRateCategoryToSettle(mView); + +        sInstrumentation.runOnMainSync(() -> { +            mView.setVisibility(View.VISIBLE); +            mView.invalidate(); +            int expected = toolkitFrameRateDefaultNormalReadOnly() +                    ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; +            runAfterDraw(() -> assertEquals(expected, +                    mViewRootImpl.getLastPreferredFrameRateCategory())); +        }); +        waitForAfterDraw();      }      /** @@ -628,8 +680,9 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) -    public void votePreferredFrameRate_voteFrameRateCategory_smallSize_defaultHigh() { -        View view = new View(sContext); +    public void votePreferredFrameRate_voteFrameRateCategory_smallSize_defaultHigh() +            throws Throwable { +        mView = new View(sContext);          WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);          wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check          wmlp.width = 1; @@ -637,15 +690,20 @@ public class ViewRootImplTest {          sInstrumentation.runOnMainSync(() -> {              WindowManager wm = sContext.getSystemService(WindowManager.class); -            wm.addView(view, wmlp); +            wm.addView(mView, wmlp);          });          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        mViewRootImpl = mView.getViewRootImpl(); +        waitForFrameRateCategoryToSettle(mView);          sInstrumentation.runOnMainSync(() -> { -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_NORMAL); +            mView.invalidate(); +            int expected = toolkitFrameRateBySizeReadOnly() ? FRAME_RATE_CATEGORY_LOW +                    : FRAME_RATE_CATEGORY_NORMAL; +            runAfterDraw(() -> assertEquals(expected, +                    mViewRootImpl.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw();      }      /** @@ -657,8 +715,9 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) -    public void votePreferredFrameRate_voteFrameRateCategory_normalSize_defaultHigh() { -        View view = new View(sContext); +    public void votePreferredFrameRate_voteFrameRateCategory_normalSize_defaultHigh() +            throws Throwable { +        mView = new View(sContext);          WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);          wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check @@ -669,17 +728,20 @@ public class ViewRootImplTest {              display.getMetrics(metrics);              wmlp.width = (int) (metrics.widthPixels * 0.9);              wmlp.height = (int) (metrics.heightPixels * 0.9); -            wm.addView(view, wmlp); +            wm.addView(mView, wmlp);          });          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        mViewRootImpl = mView.getViewRootImpl(); +        waitForFrameRateCategoryToSettle(mView);          sInstrumentation.runOnMainSync(() -> { -            view.invalidate(); +            mView.invalidate();              int expected = toolkitFrameRateDefaultNormalReadOnly()                      ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; -            assertEquals(expected, viewRootImpl.getPreferredFrameRateCategory()); +            runAfterDraw(() -> assertEquals(expected, +                    mViewRootImpl.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw();      }      /** @@ -690,9 +752,9 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY})      public void votePreferredFrameRate_voteFrameRateCategory_aggregate() { -        View view = new View(sContext); -        attachViewToWindow(view); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        View mView1 = new View(sContext); +        attachViewToWindow(mView1); +        ViewRootImpl viewRootImpl = mView1.getViewRootImpl();          sInstrumentation.runOnMainSync(() -> {              assertEquals(viewRootImpl.getPreferredFrameRateCategory(),                      FRAME_RATE_CATEGORY_NO_PREFERENCE); @@ -701,8 +763,8 @@ public class ViewRootImplTest {          // reset the frame rate category counts          for (int i = 0; i < 5; i++) {              sInstrumentation.runOnMainSync(() -> { -                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); -                view.invalidate(); +                mView1.setRequestedFrameRate(mView1.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); +                mView1.invalidate();              });              sInstrumentation.waitForIdleSync();          } @@ -736,52 +798,52 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY})      public void votePreferredFrameRate_voteFrameRate_aggregate() { -        View view = new View(sContext); -        attachViewToWindow(view); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        mView = new View(sContext); +        attachViewToWindow(mView); +        mViewRootImpl = mView.getViewRootImpl();          sInstrumentation.runOnMainSync(() -> { -            assertEquals(viewRootImpl.getPreferredFrameRate(), 0, 0.1); -            assertEquals(viewRootImpl.getFrameRateCompatibility(), +            assertEquals(mViewRootImpl.getPreferredFrameRate(), 0, 0.1); +            assertEquals(mViewRootImpl.getFrameRateCompatibility(),                      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); -            assertEquals(viewRootImpl.isFrameRateConflicted(), false); -            viewRootImpl.votePreferredFrameRate(24, FRAME_RATE_COMPATIBILITY_GTE); -            assertEquals(viewRootImpl.getPreferredFrameRate(), 24, 0.1); -            assertEquals(viewRootImpl.getFrameRateCompatibility(), +            assertEquals(mViewRootImpl.isFrameRateConflicted(), false); +            mViewRootImpl.votePreferredFrameRate(24, FRAME_RATE_COMPATIBILITY_GTE); +            assertEquals(mViewRootImpl.getPreferredFrameRate(), 24, 0.1); +            assertEquals(mViewRootImpl.getFrameRateCompatibility(),                      FRAME_RATE_COMPATIBILITY_GTE); -            assertEquals(viewRootImpl.isFrameRateConflicted(), false); -            viewRootImpl.votePreferredFrameRate(30, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); -            assertEquals(viewRootImpl.getPreferredFrameRate(), 30, 0.1); +            assertEquals(mViewRootImpl.isFrameRateConflicted(), false); +            mViewRootImpl.votePreferredFrameRate(30, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); +            assertEquals(mViewRootImpl.getPreferredFrameRate(), 30, 0.1);              // If there is a conflict, then set compatibility to              // FRAME_RATE_COMPATIBILITY_FIXED_SOURCE -            assertEquals(viewRootImpl.getFrameRateCompatibility(), +            assertEquals(mViewRootImpl.getFrameRateCompatibility(),                      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE);              // Should be true since there is a conflict between 24 and 30. -            assertEquals(viewRootImpl.isFrameRateConflicted(), true); -            view.invalidate(); +            assertEquals(mViewRootImpl.isFrameRateConflicted(), true); +            mView.invalidate();          });          sInstrumentation.waitForIdleSync();          sInstrumentation.runOnMainSync(() -> { -            assertEquals(viewRootImpl.isFrameRateConflicted(), false); -            viewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_GTE); -            assertEquals(viewRootImpl.getPreferredFrameRate(), 60, 0.1); -            assertEquals(viewRootImpl.getFrameRateCompatibility(), +            assertEquals(mViewRootImpl.isFrameRateConflicted(), false); +            mViewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_GTE); +            assertEquals(mViewRootImpl.getPreferredFrameRate(), 60, 0.1); +            assertEquals(mViewRootImpl.getFrameRateCompatibility(),                      FRAME_RATE_COMPATIBILITY_GTE); -            assertEquals(viewRootImpl.isFrameRateConflicted(), false); -            viewRootImpl.votePreferredFrameRate(120, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); -            assertEquals(viewRootImpl.getPreferredFrameRate(), 120, 0.1); -            assertEquals(viewRootImpl.getFrameRateCompatibility(), +            assertEquals(mViewRootImpl.isFrameRateConflicted(), false); +            mViewRootImpl.votePreferredFrameRate(120, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); +            assertEquals(mViewRootImpl.getPreferredFrameRate(), 120, 0.1); +            assertEquals(mViewRootImpl.getFrameRateCompatibility(),                      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE);              // Should be false since 60 is a divisor of 120. -            assertEquals(viewRootImpl.isFrameRateConflicted(), false); -            viewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_GTE); -            assertEquals(viewRootImpl.getPreferredFrameRate(), 120, 0.1); +            assertEquals(mViewRootImpl.isFrameRateConflicted(), false); +            mViewRootImpl.votePreferredFrameRate(60, FRAME_RATE_COMPATIBILITY_GTE); +            assertEquals(mViewRootImpl.getPreferredFrameRate(), 120, 0.1);              // compatibility should be remained the same (FRAME_RATE_COMPATIBILITY_FIXED_SOURCE)              // since the frame rate 60 is smaller than 120. -            assertEquals(viewRootImpl.getFrameRateCompatibility(), +            assertEquals(mViewRootImpl.getFrameRateCompatibility(),                      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE);              // Should be false since 60 is a divisor of 120. -            assertEquals(viewRootImpl.isFrameRateConflicted(), false); +            assertEquals(mViewRootImpl.isFrameRateConflicted(), false);          });      } @@ -795,37 +857,49 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) -    public void votePreferredFrameRate_voteFrameRate_category() { -        View view = new View(sContext); -        attachViewToWindow(view); +    public void votePreferredFrameRate_voteFrameRate_category() throws Throwable { +        mView = new View(sContext); +        attachViewToWindow(mView);          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        mViewRootImpl = mView.getViewRootImpl();          sInstrumentation.runOnMainSync(() -> { -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), +            assertEquals(mViewRootImpl.getPreferredFrameRateCategory(),                      FRAME_RATE_CATEGORY_NO_PREFERENCE);          });          // reset the frame rate category counts          for (int i = 0; i < 5; i++) {              sInstrumentation.runOnMainSync(() -> { -                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); -                view.invalidate(); +                mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); +                mView.invalidate();              });              sInstrumentation.waitForIdleSync();          } +        waitForFrameRateCategoryToSettle(mView); +          sInstrumentation.runOnMainSync(() -> { -            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_LOW); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW); -            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NORMAL); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_NORMAL); -            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_HIGH); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH); +            mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_LOW); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                    FRAME_RATE_CATEGORY_LOW)); +        }); +        waitForAfterDraw(); +        sInstrumentation.runOnMainSync(() -> { +            mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_NORMAL); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                    FRAME_RATE_CATEGORY_NORMAL)); +        }); +        waitForAfterDraw(); +        sInstrumentation.runOnMainSync(() -> { +            mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_HIGH); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                    FRAME_RATE_CATEGORY_HIGH));          }); +        waitForAfterDraw();      }      /** @@ -837,8 +911,8 @@ public class ViewRootImplTest {              FLAG_VIEW_VELOCITY_API,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) -    public void votePreferredFrameRate_voteFrameRateCategory_velocityToHigh() { -        View view = new View(sContext); +    public void votePreferredFrameRate_voteFrameRateCategory_velocityToHigh() throws Throwable { +        mView = new View(sContext);          WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);          wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check          wmlp.width = 1; @@ -846,21 +920,30 @@ public class ViewRootImplTest {          sInstrumentation.runOnMainSync(() -> {              WindowManager wm = sContext.getSystemService(WindowManager.class); -            wm.addView(view, wmlp); +            wm.addView(mView, wmlp);          });          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        mViewRootImpl = mView.getViewRootImpl(); +        waitForFrameRateCategoryToSettle(mView);          sInstrumentation.runOnMainSync(() -> { -            assertEquals(viewRootImpl.getPreferredFrameRate(), 0, 0.1); -            view.setFrameContentVelocity(100); -            view.invalidate(); -            assertTrue(viewRootImpl.getPreferredFrameRate() > 0); +            assertEquals(mViewRootImpl.getPreferredFrameRate(), 0, 0.1); +            mView.setFrameContentVelocity(100); +            mView.invalidate(); +            runAfterDraw(() -> assertTrue(mViewRootImpl.getLastPreferredFrameRate() > 0));          }); +        waitForAfterDraw();          sInstrumentation.waitForIdleSync(); -        assertEquals(viewRootImpl.getLastPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_HIGH); -        assertEquals(viewRootImpl.getLastPreferredFrameRate(), 0 , 0.1); +        if (toolkitFrameRateVelocityMappingReadOnly()) { +            assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                    FRAME_RATE_CATEGORY_HIGH); +            assertTrue(mViewRootImpl.getLastPreferredFrameRate() >= 60f); +        } else { +            assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                    FRAME_RATE_CATEGORY_HIGH); +            assertEquals(mViewRootImpl.getLastPreferredFrameRate(), 0, 0.1); +        }      }      /** @@ -870,7 +953,7 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY})      public void votePreferredFrameRate_insetsAnimation() { -        View view = new View(sContext); +        mView = new View(sContext);          WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);          wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check @@ -881,15 +964,15 @@ public class ViewRootImplTest {              display.getMetrics(metrics);              wmlp.width = (int) (metrics.widthPixels * 0.9);              wmlp.height = (int) (metrics.heightPixels * 0.9); -            wm.addView(view, wmlp); +            wm.addView(mView, wmlp);          });          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        ViewRootImpl viewRootImpl = mView.getViewRootImpl();          sInstrumentation.runOnMainSync(() -> { -            view.invalidate(); +            mView.invalidate();              viewRootImpl.notifyInsetsAnimationRunningStateChanged(true); -            view.invalidate(); +            mView.invalidate();          });          sInstrumentation.waitForIdleSync(); @@ -907,11 +990,11 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY})      public void votePreferredFrameRate_frameRateBoostOnTouch() { -        View view = new View(sContext); -        attachViewToWindow(view); +        mView = new View(sContext); +        attachViewToWindow(mView);          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        ViewRootImpl viewRootImpl = mView.getViewRootImpl();          final WindowManager.LayoutParams attrs = viewRootImpl.mWindowAttributes;          assertEquals(attrs.getFrameRateBoostOnTouchEnabled(), true);          assertEquals(viewRootImpl.getFrameRateBoostOnTouchEnabled(), @@ -942,10 +1025,10 @@ public class ViewRootImplTest {      public void votePreferredFrameRate_voteFrameRateTimeOut() throws InterruptedException {          final long delay = 200L; -        View view = new View(sContext); -        attachViewToWindow(view); +        mView = new View(sContext); +        attachViewToWindow(mView);          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        ViewRootImpl viewRootImpl = mView.getViewRootImpl();          sInstrumentation.runOnMainSync(() -> {              assertEquals(viewRootImpl.getPreferredFrameRate(), 0, 0.1); @@ -957,7 +1040,7 @@ public class ViewRootImplTest {              assertEquals(viewRootImpl.getFrameRateCompatibility(),                      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE);              assertEquals(viewRootImpl.isFrameRateConflicted(), false); -            view.invalidate(); +            mView.invalidate();              assertEquals(viewRootImpl.getPreferredFrameRate(), 24, 0.1);              assertEquals(viewRootImpl.getFrameRateCompatibility(),                      FRAME_RATE_COMPATIBILITY_FIXED_SOURCE); @@ -978,38 +1061,44 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) -    public void votePreferredFrameRate_voteFrameRateOnly() { -        View view = new View(sContext); +    public void votePreferredFrameRate_voteFrameRateOnly() throws Throwable { +        mView = new View(sContext);          float frameRate = 20; -        attachViewToWindow(view); +        attachViewToWindow(mView);          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        mViewRootImpl = mView.getViewRootImpl(); +        waitForFrameRateCategoryToSettle(mView);          sInstrumentation.runOnMainSync(() -> { -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), +            assertEquals(mViewRootImpl.getPreferredFrameRateCategory(),                      FRAME_RATE_CATEGORY_NO_PREFERENCE); -            view.setRequestedFrameRate(frameRate); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), -                    FRAME_RATE_CATEGORY_NO_PREFERENCE); -            assertEquals(viewRootImpl.getPreferredFrameRate(), frameRate, 0.1); +            mView.setRequestedFrameRate(frameRate); +            mView.invalidate(); +            runAfterDraw(() -> { +                assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                        FRAME_RATE_CATEGORY_NO_PREFERENCE); +                assertEquals(mViewRootImpl.getLastPreferredFrameRate(), frameRate, 0.1); +            });          }); +        waitForAfterDraw();          // reset the frame rate category counts          for (int i = 0; i < 5; i++) {              sInstrumentation.runOnMainSync(() -> { -                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); -                view.invalidate(); +                mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); +                mView.invalidate();              });              sInstrumentation.waitForIdleSync();          }          sInstrumentation.runOnMainSync(() -> { -            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_LOW); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_LOW); +            mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_LOW); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                    FRAME_RATE_CATEGORY_LOW));          }); +        waitForAfterDraw();      }      /** @@ -1022,10 +1111,10 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) -    public void votePreferredFrameRate_infrequentLayer_defaultHigh() throws InterruptedException { +    public void votePreferredFrameRate_infrequentLayer_defaultHigh() throws Throwable {          final long delay = 200L; -        View view = new View(sContext); +        mView = new View(sContext);          WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);          wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check @@ -1036,26 +1125,29 @@ public class ViewRootImplTest {              display.getMetrics(metrics);              wmlp.width = (int) (metrics.widthPixels * 0.9);              wmlp.height = (int) (metrics.heightPixels * 0.9); -            wm.addView(view, wmlp); +            wm.addView(mView, wmlp);          });          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        mViewRootImpl = mView.getViewRootImpl(); +        waitForFrameRateCategoryToSettle(mView);          // In transition from frequent update to infrequent update          Thread.sleep(delay);          sInstrumentation.runOnMainSync(() -> { -            view.invalidate(); +            mView.invalidate();              int expected = toolkitFrameRateDefaultNormalReadOnly()                      ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; -            assertEquals(expected, viewRootImpl.getPreferredFrameRateCategory()); +            runAfterDraw(() -> assertEquals(expected, +                    mViewRootImpl.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw();          // reset the frame rate category counts          for (int i = 0; i < 5; i++) {              sInstrumentation.runOnMainSync(() -> { -                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); -                view.invalidate(); +                mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); +                mView.invalidate();              });              sInstrumentation.waitForIdleSync();          } @@ -1063,26 +1155,30 @@ public class ViewRootImplTest {          // In transition from frequent update to infrequent update          Thread.sleep(delay);          sInstrumentation.runOnMainSync(() -> { -            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), -                    FRAME_RATE_CATEGORY_NO_PREFERENCE); +            mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                    FRAME_RATE_CATEGORY_NO_PREFERENCE));          }); +        waitForAfterDraw();          Thread.sleep(delay);          sInstrumentation.runOnMainSync(() -> { -            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), -                    FRAME_RATE_CATEGORY_NO_PREFERENCE); +            mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                    FRAME_RATE_CATEGORY_NO_PREFERENCE));          }); +        waitForAfterDraw();          // Infrequent update          Thread.sleep(delay);          sInstrumentation.runOnMainSync(() -> { -            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), FRAME_RATE_CATEGORY_NORMAL); +            mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                    FRAME_RATE_CATEGORY_NORMAL));          }); +        waitForAfterDraw();      }      /** @@ -1092,11 +1188,11 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY})      public void votePreferredFrameRate_isFrameRatePowerSavingsBalanced() { -        View view = new View(sContext); -        attachViewToWindow(view); +        mView = new View(sContext); +        attachViewToWindow(mView);          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRoot = view.getViewRootImpl(); +        ViewRootImpl viewRoot = mView.getViewRootImpl();          final WindowManager.LayoutParams attrs = viewRoot.mWindowAttributes;          assertEquals(attrs.isFrameRatePowerSavingsBalanced(), true);          assertEquals(viewRoot.isFrameRatePowerSavingsBalanced(), @@ -1125,10 +1221,10 @@ public class ViewRootImplTest {      @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_FUNCTION_ENABLING_READ_ONLY,              FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) -    public void votePreferredFrameRate_applyTextureViewHeuristic() throws InterruptedException { +    public void votePreferredFrameRate_applyTextureViewHeuristic() throws Throwable {          final long delay = 30L; -        TextureView view = new TextureView(sContext); +        mView = new TextureView(sContext);          WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);          wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check @@ -1139,38 +1235,44 @@ public class ViewRootImplTest {              display.getMetrics(metrics);              wmlp.width = (int) (metrics.widthPixels * 0.9);              wmlp.height = (int) (metrics.heightPixels * 0.9); -            wm.addView(view, wmlp); +            wm.addView(mView, wmlp);          });          sInstrumentation.waitForIdleSync(); -        ViewRootImpl viewRootImpl = view.getViewRootImpl(); +        mViewRootImpl = mView.getViewRootImpl(); +        waitForFrameRateCategoryToSettle(mView);          sInstrumentation.runOnMainSync(() -> { -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), +            assertEquals(mViewRootImpl.getPreferredFrameRateCategory(),                      FRAME_RATE_CATEGORY_NO_PREFERENCE); -            view.invalidate(); +            mView.invalidate();              int expected = toolkitFrameRateDefaultNormalReadOnly()                      ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; -            assertEquals(expected, viewRootImpl.getPreferredFrameRateCategory()); +            runAfterDraw(() -> assertEquals(expected, +                    mViewRootImpl.getLastPreferredFrameRateCategory()));          }); +        waitForAfterDraw(); + +        waitForFrameRateCategoryToSettle(mView);           // reset the frame rate category counts          for (int i = 0; i < 5; i++) {              Thread.sleep(delay);              sInstrumentation.runOnMainSync(() -> { -                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); -                view.invalidate(); +                mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); +                mView.invalidate();              });              sInstrumentation.waitForIdleSync();          }          Thread.sleep(delay);          sInstrumentation.runOnMainSync(() -> { -            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT); -            view.invalidate(); -            assertEquals(viewRootImpl.getPreferredFrameRateCategory(), -                    FRAME_RATE_CATEGORY_NORMAL); +            mView.setRequestedFrameRate(mView.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT); +            mView.invalidate(); +            runAfterDraw(() -> assertEquals(mViewRootImpl.getLastPreferredFrameRateCategory(), +                    FRAME_RATE_CATEGORY_NORMAL));          }); +        waitForAfterDraw();      }      @Test @@ -1287,6 +1389,7 @@ public class ViewRootImplTest {       */      private void checkKeyEvent(Runnable setup, boolean shouldReceiveKey) {          final KeyView view = new KeyView(sContext); +        mView = view;          attachViewToWindow(view); @@ -1313,4 +1416,48 @@ public class ViewRootImplTest {          });          sInstrumentation.waitForIdleSync();      } + +    private void runAfterDraw(@NonNull Runnable runnable) { +        mAfterDrawLatch = new CountDownLatch(1); +        ViewTreeObserver.OnDrawListener listener = new ViewTreeObserver.OnDrawListener() { +            @Override +            public void onDraw() { +                mView.getHandler().postAtFrontOfQueue(() -> { +                    mView.getViewTreeObserver().removeOnDrawListener(this); +                    try { +                        runnable.run(); +                    } catch (Throwable t) { +                        mAfterDrawThrowable = t; +                    } +                    mAfterDrawLatch.countDown(); +                }); +            } +        }; +        mView.getViewTreeObserver().addOnDrawListener(listener); +    } + +    private void waitForAfterDraw() throws Throwable { +        assertTrue(mAfterDrawLatch.await(1, TimeUnit.SECONDS)); +        if (mAfterDrawThrowable != null) { +            throw mAfterDrawThrowable; +        } +    } + +    private void waitForFrameRateCategoryToSettle(View view) throws Throwable { +        for (int i = 0; i < 5 || mViewRootImpl.getIsFrameRateBoosting(); i++) { +            final CountDownLatch drawLatch = new CountDownLatch(1); + +            // Now that it is small, any invalidation should have a normal category +            ViewTreeObserver.OnDrawListener listener = drawLatch::countDown; + +            sInstrumentation.runOnMainSync(() -> { +                view.invalidate(); +                view.getViewTreeObserver().addOnDrawListener(listener); +            }); + +            assertTrue(drawLatch.await(1, TimeUnit.SECONDS)); +            sInstrumentation.runOnMainSync( +                    () -> view.getViewTreeObserver().removeOnDrawListener(listener)); +        } +    }  } diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java index 5fab1a0f3c8e..d560ef243a06 100644 --- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java +++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java @@ -420,7 +420,7 @@ public class AccessibilityShortcutControllerTest {      }      @Test -    @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void testClickingDisableButtonInDialog_shouldClearShortcutId() throws Exception {          configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);          configureValidShortcutService(); @@ -443,7 +443,7 @@ public class AccessibilityShortcutControllerTest {      }      @Test -    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void testClickingDisableButtonInDialog_shouldClearShortcutId_old() throws Exception {          configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);          configureValidShortcutService(); @@ -467,7 +467,7 @@ public class AccessibilityShortcutControllerTest {      @Test      @EnableFlags(Flags.FLAG_UPDATE_ALWAYS_ON_A11Y_SERVICE) -    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void turnOffVolumeShortcutForAlwaysOnA11yService_shouldTurnOffA11yService()              throws Exception {          configureApplicationTargetSdkVersion(Build.VERSION_CODES.R); @@ -480,7 +480,7 @@ public class AccessibilityShortcutControllerTest {      @Test      @EnableFlags(Flags.FLAG_UPDATE_ALWAYS_ON_A11Y_SERVICE) -    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void turnOffVolumeShortcutForAlwaysOnA11yService_hasOtherTypesShortcut_shouldNotTurnOffA11yService()              throws Exception {          configureApplicationTargetSdkVersion(Build.VERSION_CODES.R); @@ -527,7 +527,7 @@ public class AccessibilityShortcutControllerTest {      }      @Test -    @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void testTurnOnDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOn()              throws Exception {          configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); @@ -551,7 +551,7 @@ public class AccessibilityShortcutControllerTest {      }      @Test -    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void testTurnOnDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOn_old()              throws Exception {          configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); @@ -574,7 +574,7 @@ public class AccessibilityShortcutControllerTest {      }      @Test -    @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void testTurnOffDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOff()              throws Exception {          configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); @@ -598,7 +598,7 @@ public class AccessibilityShortcutControllerTest {      }      @Test -    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void testTurnOffDefaultA11yServiceInDialog_defaultServiceShortcutTurnsOff_old()              throws Exception {          configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN); diff --git a/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java b/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java index a14d8e034b32..9cac3120d1d9 100644 --- a/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java +++ b/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java @@ -117,7 +117,7 @@ public class InvisibleToggleAccessibilityServiceTargetTest {      }      @Test -    @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void onCheckedChanged_true_callA11yManagerToUpdateShortcuts() throws Exception {          mSut.onCheckedChanged(true); @@ -130,7 +130,7 @@ public class InvisibleToggleAccessibilityServiceTargetTest {      }      @Test -    @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void onCheckedChanged_false_callA11yManagerToUpdateShortcuts() throws Exception {          mSut.onCheckedChanged(false);          verify(mAccessibilityManagerService).enableShortcutsForTargets( @@ -142,7 +142,7 @@ public class InvisibleToggleAccessibilityServiceTargetTest {      }      @Test -    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void onCheckedChanged_turnOnShortcut_hasOtherShortcut_serviceKeepsOn() {          enableA11yService(/* enable= */ true);          addShortcutForA11yService( @@ -155,7 +155,7 @@ public class InvisibleToggleAccessibilityServiceTargetTest {      }      @Test -    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void onCheckedChanged_turnOnShortcut_noOtherShortcut_shouldTurnOnService() {          enableA11yService(/* enable= */ false);          addShortcutForA11yService( @@ -168,7 +168,7 @@ public class InvisibleToggleAccessibilityServiceTargetTest {      }      @Test -    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void onCheckedChanged_turnOffShortcut_hasOtherShortcut_serviceKeepsOn() {          enableA11yService(/* enable= */ true);          addShortcutForA11yService( @@ -181,7 +181,7 @@ public class InvisibleToggleAccessibilityServiceTargetTest {      }      @Test -    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    @DisableFlags(Flags.FLAG_MIGRATE_ENABLE_SHORTCUTS)      public void onCheckedChanged_turnOffShortcut_noOtherShortcut_shouldTurnOffService() {          enableA11yService(/* enable= */ true);          addShortcutForA11yService( diff --git a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java index 533b799341c1..fa5d72a04b88 100644 --- a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java +++ b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java @@ -55,6 +55,21 @@ public class LongArrayMultiStateCounterTest {      }      @Test +    public void copyStatesFrom() { +        LongArrayMultiStateCounter source = new LongArrayMultiStateCounter(2, 1); +        updateValue(source, new long[]{0}, 1000); +        source.setState(0, 1000); +        source.setState(1, 2000); + +        LongArrayMultiStateCounter target = new LongArrayMultiStateCounter(2, 1); +        target.copyStatesFrom(source); +        updateValue(target, new long[]{1000}, 5000); + +        assertCounts(target, 0, new long[]{250}); +        assertCounts(target, 1, new long[]{750}); +    } + +    @Test      public void setValue() {          LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4); diff --git a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java index c0f0714e52cc..951fa98caf27 100644 --- a/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java +++ b/core/tests/coretests/src/com/android/internal/os/PowerProfileTest.java @@ -21,20 +21,21 @@ import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_AMBIENT;  import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_FULL;  import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_ON; +import static com.google.common.truth.Truth.assertThat; +  import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -import android.annotation.XmlRes;  import android.content.Context;  import android.content.res.Resources; -import android.content.res.XmlResourceParser; -import android.platform.test.annotations.IgnoreUnderRavenwood; +import android.platform.test.annotations.DisabledOnRavenwood;  import android.platform.test.ravenwood.RavenwoodRule; +import android.util.Xml; -import androidx.test.InstrumentationRegistry;  import androidx.test.filters.SmallTest;  import androidx.test.runner.AndroidJUnit4; -import com.android.frameworks.coretests.R;  import com.android.internal.power.ModemPowerProfile;  import com.android.internal.util.XmlUtils; @@ -43,6 +44,11 @@ import org.junit.Before;  import org.junit.Rule;  import org.junit.Test;  import org.junit.runner.RunWith; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.io.StringReader;  /*   * Keep this file in sync with frameworks/base/core/res/res/xml/power_profile_test.xml and @@ -53,7 +59,6 @@ import org.junit.runner.RunWith;   */  @SmallTest  @RunWith(AndroidJUnit4.class) -@IgnoreUnderRavenwood(blockedBy = PowerProfile.class)  public class PowerProfileTest {      @Rule      public final RavenwoodRule mRavenwood = new RavenwoodRule(); @@ -62,17 +67,15 @@ public class PowerProfileTest {      static final String ATTR_NAME = "name";      private PowerProfile mProfile; -    private Context mContext;      @Before      public void setUp() { -        mContext = InstrumentationRegistry.getContext(); -        mProfile = new PowerProfile(mContext); +        mProfile = new PowerProfile();      }      @Test      public void testPowerProfile() { -        mProfile.forceInitForTesting(mContext, R.xml.power_profile_test); +        mProfile.initForTesting(resolveParser("power_profile_test"));          assertEquals(5.0, mProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND));          assertEquals(1.11, mProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE)); @@ -127,11 +130,36 @@ public class PowerProfileTest {                  PowerProfile.SUBSYSTEM_MODEM | ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT                          | ModemPowerProfile.MODEM_DRAIN_TYPE_TX                          | ModemPowerProfile.MODEM_TX_LEVEL_4)); + +        assertEquals(0.02, mProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE)); +        assertEquals(3, mProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX)); +        assertEquals(5, mProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX)); +        assertEquals(3300, mProfile.getAveragePower( +                PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE)); +    } + +    @DisabledOnRavenwood +    @Test +    public void configDefaults() throws XmlPullParserException { +        Resources mockResources = mock(Resources.class); +        when(mockResources.getInteger(com.android.internal.R.integer.config_bluetooth_rx_cur_ma)) +                .thenReturn(123); +        XmlPullParser parser = Xml.newPullParser(); +        parser.setInput(new StringReader( +                "<device name='Android'>" +                + "<item name='bluetooth.controller.idle'>10</item>" +                + "</device>")); +        mProfile.initForTesting(parser, mockResources); +        assertThat(mProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE)) +                .isEqualTo(10); +        assertThat(mProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX)) +                .isEqualTo(123);      } +      @Test      public void testPowerProfile_legacyCpuConfig() {          // This power profile has per-cluster data, rather than per-policy -        mProfile.forceInitForTesting(mContext, R.xml.power_profile_test_cpu_legacy); +        mProfile.initForTesting(resolveParser("power_profile_test_cpu_legacy"));          assertEquals(2.11, mProfile.getAveragePowerForCpuScalingPolicy(0));          assertEquals(2.22, mProfile.getAveragePowerForCpuScalingPolicy(4)); @@ -148,7 +176,7 @@ public class PowerProfileTest {      @Test      public void testModemPowerProfile_defaultRat() throws Exception { -        final XmlResourceParser parser = getTestModemElement(R.xml.power_profile_test_modem, +        final XmlPullParser parser = getTestModemElement("power_profile_test_modem",                  "testModemPowerProfile_defaultRat");          ModemPowerProfile mpp = new ModemPowerProfile();          mpp.parseFromXml(parser); @@ -216,7 +244,7 @@ public class PowerProfileTest {      @Test      public void testModemPowerProfile_partiallyDefined() throws Exception { -        final XmlResourceParser parser = getTestModemElement(R.xml.power_profile_test_modem, +        final XmlPullParser parser = getTestModemElement("power_profile_test_modem",                  "testModemPowerProfile_partiallyDefined");          ModemPowerProfile mpp = new ModemPowerProfile();          mpp.parseFromXml(parser); @@ -369,7 +397,7 @@ public class PowerProfileTest {      @Test      public void testModemPowerProfile_fullyDefined() throws Exception { -        final XmlResourceParser parser = getTestModemElement(R.xml.power_profile_test_modem, +        final XmlPullParser parser = getTestModemElement("power_profile_test_modem",                  "testModemPowerProfile_fullyDefined");          ModemPowerProfile mpp = new ModemPowerProfile();          mpp.parseFromXml(parser); @@ -519,11 +547,10 @@ public class PowerProfileTest {                  | ModemPowerProfile.MODEM_DRAIN_TYPE_TX | ModemPowerProfile.MODEM_TX_LEVEL_4));      } -    private XmlResourceParser getTestModemElement(@XmlRes int xmlId, String elementName) +    private XmlPullParser getTestModemElement(String resourceName, String elementName)              throws Exception { +        XmlPullParser parser = resolveParser(resourceName);          final String element = TAG_TEST_MODEM; -        final Resources resources = mContext.getResources(); -        XmlResourceParser parser = resources.getXml(xmlId);          while (true) {              XmlUtils.nextElement(parser);              final String e = parser.getName(); @@ -535,10 +562,26 @@ public class PowerProfileTest {              return parser;          } -        fail("Unanable to find element " + element + " with name " + elementName); +        fail("Unable to find element " + element + " with name " + elementName);          return null;      } +    private XmlPullParser resolveParser(String resourceName) { +        if (RavenwoodRule.isOnRavenwood()) { +            try { +                return Xml.resolvePullParser(getClass().getClassLoader() +                        .getResourceAsStream("res/xml/" + resourceName + ".xml")); +            } catch (IOException e) { +                throw new RuntimeException(e); +            } +        } else { +            Context context = androidx.test.InstrumentationRegistry.getContext(); +            Resources resources = context.getResources(); +            int resId = resources.getIdentifier(resourceName, "xml", context.getPackageName()); +            return resources.getXml(resId); +        } +    } +      private void assertEquals(double expected, double actual) {          Assert.assertEquals(expected, actual, 0.1);      } diff --git a/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java b/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java index b99e2026ef26..6402206410b5 100644 --- a/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/PowerStatsTest.java @@ -21,20 +21,27 @@ import static com.google.common.truth.Truth.assertThat;  import android.os.BatteryConsumer;  import android.os.Parcel;  import android.os.PersistableBundle; -import android.platform.test.annotations.IgnoreUnderRavenwood;  import android.platform.test.ravenwood.RavenwoodRule; +import android.util.SparseArray; +import android.util.Xml;  import androidx.test.filters.SmallTest;  import androidx.test.runner.AndroidJUnit4; +import com.android.modules.utils.TypedXmlPullParser; +import com.android.modules.utils.TypedXmlSerializer; +  import org.junit.Before;  import org.junit.Rule;  import org.junit.Test;  import org.junit.runner.RunWith; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +  @RunWith(AndroidJUnit4.class)  @SmallTest -@IgnoreUnderRavenwood(reason = "Needs kernel support")  public class PowerStatsTest {      @Rule      public final RavenwoodRule mRavenwood = new RavenwoodRule(); @@ -47,7 +54,10 @@ public class PowerStatsTest {          mRegistry = new PowerStats.DescriptorRegistry();          PersistableBundle extras = new PersistableBundle();          extras.putBoolean("hasPowerMonitor", true); -        mDescriptor = new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_CPU, 3, 2, extras); +        SparseArray<String> stateLabels = new SparseArray<>(); +        stateLabels.put(0x0F, "idle"); +        mDescriptor = new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_CPU, 3, stateLabels, +                1, 2, extras);          mRegistry.register(mDescriptor);      } @@ -58,6 +68,8 @@ public class PowerStatsTest {          stats.stats[0] = 10;          stats.stats[1] = 20;          stats.stats[2] = 30; +        stats.stateStats.put(0x0F, new long[]{16}); +        stats.stateStats.put(0xF0, new long[]{17});          stats.uidStats.put(42, new long[]{40, 50});          stats.uidStats.put(99, new long[]{60, 70}); @@ -73,6 +85,7 @@ public class PowerStatsTest {          assertThat(newDescriptor.powerComponentId).isEqualTo(BatteryConsumer.POWER_COMPONENT_CPU);          assertThat(newDescriptor.name).isEqualTo("cpu");          assertThat(newDescriptor.statsArrayLength).isEqualTo(3); +        assertThat(newDescriptor.stateStatsArrayLength).isEqualTo(1);          assertThat(newDescriptor.uidStatsArrayLength).isEqualTo(2);          assertThat(newDescriptor.extras.getBoolean("hasPowerMonitor")).isTrue(); @@ -81,6 +94,11 @@ public class PowerStatsTest {          PowerStats newStats = PowerStats.readFromParcel(newParcel, mRegistry);          assertThat(newStats.durationMs).isEqualTo(1234);          assertThat(newStats.stats).isEqualTo(new long[]{10, 20, 30}); +        assertThat(newStats.stateStats.size()).isEqualTo(2); +        assertThat(newStats.stateStats.get(0x0F)).isEqualTo(new long[]{16}); +        assertThat(newStats.descriptor.getStateLabel(0x0F)).isEqualTo("idle"); +        assertThat(newStats.stateStats.get(0xF0)).isEqualTo(new long[]{17}); +        assertThat(newStats.descriptor.getStateLabel(0xF0)).isEqualTo("cpu-f0");          assertThat(newStats.uidStats.size()).isEqualTo(2);          assertThat(newStats.uidStats.get(42)).isEqualTo(new long[]{40, 50});          assertThat(newStats.uidStats.get(99)).isEqualTo(new long[]{60, 70}); @@ -90,9 +108,33 @@ public class PowerStatsTest {      }      @Test +    public void xmlFormat() throws Exception { +        ByteArrayOutputStream out = new ByteArrayOutputStream(); +        TypedXmlSerializer serializer = Xml.newBinarySerializer(); +        serializer.setOutput(out, StandardCharsets.UTF_8.name()); +        mDescriptor.writeXml(serializer); +        serializer.flush(); + +        byte[] bytes = out.toByteArray(); + +        TypedXmlPullParser parser = Xml.newBinaryPullParser(); +        parser.setInput(new ByteArrayInputStream(bytes), StandardCharsets.UTF_8.name()); +        PowerStats.Descriptor actual = PowerStats.Descriptor.createFromXml(parser); + +        assertThat(actual.powerComponentId).isEqualTo(BatteryConsumer.POWER_COMPONENT_CPU); +        assertThat(actual.name).isEqualTo("cpu"); +        assertThat(actual.statsArrayLength).isEqualTo(3); +        assertThat(actual.stateStatsArrayLength).isEqualTo(1); +        assertThat(actual.getStateLabel(0x0F)).isEqualTo("idle"); +        assertThat(actual.getStateLabel(0xF0)).isEqualTo("cpu-f0"); +        assertThat(actual.uidStatsArrayLength).isEqualTo(2); +        assertThat(actual.extras.getBoolean("hasPowerMonitor")).isEqualTo(true); +    } + +    @Test      public void parceling_unrecognizedPowerComponent() {          PowerStats stats = new PowerStats( -                new PowerStats.Descriptor(777, "luck", 3, 2, new PersistableBundle())); +                new PowerStats.Descriptor(777, "luck", 3, null, 1, 2, new PersistableBundle()));          stats.durationMs = 1234;          Parcel parcel = Parcel.obtain(); diff --git a/core/tests/mockingcoretests/Android.bp b/core/tests/mockingcoretests/Android.bp index 2d778b1218d2..aca52a870655 100644 --- a/core/tests/mockingcoretests/Android.bp +++ b/core/tests/mockingcoretests/Android.bp @@ -40,6 +40,7 @@ android_test {          "platform-test-annotations",          "truth",          "testables", +        "flag-junit",      ],      libs: [ diff --git a/core/tests/mockingcoretests/src/android/widget/OWNERS b/core/tests/mockingcoretests/src/android/widget/OWNERS new file mode 100644 index 000000000000..c0cbea98cc57 --- /dev/null +++ b/core/tests/mockingcoretests/src/android/widget/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/notification/OWNERS
\ No newline at end of file diff --git a/core/tests/mockingcoretests/src/android/widget/ToastTest.java b/core/tests/mockingcoretests/src/android/widget/ToastTest.java new file mode 100644 index 000000000000..79bc81d57727 --- /dev/null +++ b/core/tests/mockingcoretests/src/android/widget/ToastTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.widget; + +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.anyString; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; + +import android.app.INotificationManager; +import android.content.Context; +import android.os.Looper; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.view.View; +import android.widget.flags.Flags; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.dx.mockito.inline.extended.ExtendedMockito; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; + + +/** + * ToastTest tests {@link Toast}. + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ToastTest { + +    @Rule +    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + +    private Context mContext; +    private MockitoSession mMockingSession; +    private static INotificationManager.Stub sMockNMS; + +    @Before +    public void setup() { +        mContext = InstrumentationRegistry.getContext(); +        mMockingSession = +              ExtendedMockito.mockitoSession() +                  .strictness(Strictness.LENIENT) +                  .mockStatic(ServiceManager.class) +                  .startMocking(); + +        //Toast caches the NotificationManager service as static class member +        if (sMockNMS == null) { +            sMockNMS = mock(INotificationManager.Stub.class); +        } +        doReturn(sMockNMS).when(sMockNMS).queryLocalInterface("android.app.INotificationManager"); +        doReturn(sMockNMS).when(() -> ServiceManager.getService(Context.NOTIFICATION_SERVICE)); +    } + +    @After +    public void tearDown() { +        if (mMockingSession != null) { +            mMockingSession.finishMocking(); +        } +        reset(sMockNMS); +    } + +    @Test +    @EnableFlags(Flags.FLAG_TOAST_NO_WEAKREF) +    public void enqueueFail_nullifiesNextView() throws RemoteException { +        Looper.prepare(); + +        // allow 1st toast and fail on the 2nd +        when(sMockNMS.enqueueToast(anyString(), any(), any(), anyInt(), anyBoolean(), +              anyInt())).thenReturn(true, false); + +        // first toast is enqueued +        Toast t = Toast.makeText(mContext, "Toast1", Toast.LENGTH_SHORT); +        t.setView(mock(View.class)); +        t.show(); +        Toast.TN tn = t.getTn(); +        assertThat(tn.getNextView()).isNotNull(); + +        // second toast is not enqueued +        t = Toast.makeText(mContext, "Toast2", Toast.LENGTH_SHORT); +        t.setView(mock(View.class)); +        t.show(); +        tn = t.getTn(); +        assertThat(tn.getNextView()).isNull(); +    } + +    @Test +    @DisableFlags(Flags.FLAG_TOAST_NO_WEAKREF) +    public void enqueueFail_doesNotNullifyNextView() throws RemoteException { +        Looper.prepare(); + +        // allow 1st toast and fail on the 2nd +        when(sMockNMS.enqueueToast(anyString(), any(), any(), anyInt(), anyBoolean(), +              anyInt())).thenReturn(true, false); + +        // first toast is enqueued +        Toast t = Toast.makeText(mContext, "Toast1", Toast.LENGTH_SHORT); +        t.setView(mock(View.class)); +        t.show(); +        Toast.TN tn = t.getTn(); +        assertThat(tn.getNextView()).isNotNull(); + +        // second toast is not enqueued +        t = Toast.makeText(mContext, "Toast2", Toast.LENGTH_SHORT); +        t.setView(mock(View.class)); +        t.show(); +        tn = t.getTn(); +        assertThat(tn.getNextView()).isNotNull(); +    } +} diff --git a/core/tests/overlaytests/device_non_system/Android.bp b/core/tests/overlaytests/device_non_system/Android.bp new file mode 100644 index 000000000000..dd7786a4e43f --- /dev/null +++ b/core/tests/overlaytests/device_non_system/Android.bp @@ -0,0 +1,39 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +//      http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { +    // See: http://go/android-license-faq +    // A large-scale-change added 'default_applicable_licenses' to import +    // all of the 'license_kinds' from "frameworks_base_license" +    // to get the below license kinds: +    //   SPDX-license-identifier-Apache-2.0 +    default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { +    name: "OverlayDeviceTestsNonSystem", +    team: "trendy_team_android_resources", +    srcs: ["src/**/*.java"], +    platform_apis: true, +    certificate: "platform", +    static_libs: [ +        "androidx.test.rules", +        "testng", +        "compatibility-device-util-axt", +    ], +    test_suites: ["device-tests"], +    data: [ +        ":OverlayDeviceTestsNonSystem_AppOverlay", +    ], +} diff --git a/core/tests/overlaytests/device_non_system/AndroidManifest.xml b/core/tests/overlaytests/device_non_system/AndroidManifest.xml new file mode 100644 index 000000000000..a37d1689e80e --- /dev/null +++ b/core/tests/overlaytests/device_non_system/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + +     Licensed under the Apache License, Version 2.0 (the "License"); +     you may not use this file except in compliance with the License. +     You may obtain a copy of the License at + +          http://www.apache.org/licenses/LICENSE-2.0 + +     Unless required by applicable law or agreed to in writing, software +     distributed under the License is distributed on an "AS IS" BASIS, +     WITHOUT 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.non_system"> + +    <uses-sdk android:minSdkVersion="34" /> + +    <application> +        <uses-library android:name="android.test.runner"/> +    </application> + +    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" +        android:targetPackage="com.android.overlaytest.non_system" +        android:label="Runtime resource overlay tests for non system app" /> +</manifest> diff --git a/core/tests/overlaytests/device_non_system/AndroidTest.xml b/core/tests/overlaytests/device_non_system/AndroidTest.xml new file mode 100644 index 000000000000..fc47e6a90880 --- /dev/null +++ b/core/tests/overlaytests/device_non_system/AndroidTest.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + +     Licensed under the Apache License, Version 2.0 (the "License"); +     you may not use this file except in compliance with the License. +     You may obtain a copy of the License at + +          http://www.apache.org/licenses/LICENSE-2.0 + +     Unless required by applicable law or agreed to in writing, software +     distributed under the License is distributed on an "AS IS" BASIS, +     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +     See the License for the specific language governing permissions and +     limitations under the License. +--> + +<configuration description="Test module config for OverlayDeviceTestsNonSystem"> +    <option name="test-tag" value="OverlayDeviceTestsNonSystem" /> +    <option name="test-suite-tag" value="apct" /> +    <option name="test-suite-tag" value="apct-instrumentation" /> + +    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> +        <option name="cleanup-apks" value="true" /> +        <option name="test-file-name" value="OverlayDeviceTestsNonSystem_AppOverlay.apk" /> +    </target_preparer> + +    <target_preparer class="com.android.tradefed.targetprep.RunOnSecondaryUserTargetPreparer"> +        <option name="test-package-name" value="com.android.overlaytest.non_system" /> +    </target_preparer> + +    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> +        <option name="test-user-token" value="%TEST_USER%"/> +        <option name="run-command" +            value="cmd overlay enable --user %TEST_USER% com.android.overlaytest.non_system.app_overlay" /> +    </target_preparer> + +    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> +        <option name="cleanup-apks" value="true" /> +        <option name="test-file-name" value="OverlayDeviceTestsNonSystem.apk" /> +    </target_preparer> + +    <test class="com.android.tradefed.testtype.AndroidJUnitTest"> +        <option name="package" value="com.android.overlaytest.non_system" /> +    </test> +</configuration> diff --git a/core/tests/overlaytests/device_non_system/res/layout/layout.xml b/core/tests/overlaytests/device_non_system/res/layout/layout.xml new file mode 100644 index 000000000000..2cb201377d52 --- /dev/null +++ b/core/tests/overlaytests/device_non_system/res/layout/layout.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2024 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT 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" +    xmlns:app="http://schemas.android.com/apk/res-auto" +    android:orientation="vertical" +    android:layout_width="match_parent" +    android:layout_height="match_parent"> + +    <TextView +        android:id="@+id/text_view_id" +        android:layout_height="wrap_content" +        android:layout_width="wrap_content" +        android:text="@string/test_string" /> +</LinearLayout>
\ No newline at end of file diff --git a/core/tests/overlaytests/device_non_system/res/values/overlayable.xml b/core/tests/overlaytests/device_non_system/res/values/overlayable.xml new file mode 100644 index 000000000000..f8017bc35d5d --- /dev/null +++ b/core/tests/overlaytests/device_non_system/res/values/overlayable.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2024 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT 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="string" name="test_string" /> +        </policy> +    </overlayable> +</resources>
\ No newline at end of file diff --git a/core/tests/overlaytests/device_non_system/res/values/strings.xml b/core/tests/overlaytests/device_non_system/res/values/strings.xml new file mode 100644 index 000000000000..ff501a0639ff --- /dev/null +++ b/core/tests/overlaytests/device_non_system/res/values/strings.xml @@ -0,0 +1,3 @@ +<resources> +    <string name="test_string">Original</string> +</resources>
\ No newline at end of file diff --git a/core/tests/overlaytests/device_non_system/src/com/android/overlaytest/OverlayTest.java b/core/tests/overlaytests/device_non_system/src/com/android/overlaytest/OverlayTest.java new file mode 100644 index 000000000000..2b0fe6cdc559 --- /dev/null +++ b/core/tests/overlaytests/device_non_system/src/com/android/overlaytest/OverlayTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import androidx.test.InstrumentationRegistry; + +import com.android.overlaytest.non_system.R; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * This test class is to verify overlay behavior for non-system apps. + */ +@RunWith(JUnit4.class) +public class OverlayTest { +    @Test +    public void testStringOverlay() throws Throwable { +        final LayoutInflater inflater = LayoutInflater.from(InstrumentationRegistry.getContext()); +        final View layout = inflater.inflate(R.layout.layout, null); +        TextView tv = layout.findViewById(R.id.text_view_id); +        assertNotNull(tv); +        assertEquals("Overlaid", tv.getText().toString()); +    } +} diff --git a/core/tests/overlaytests/device_non_system/test-apps/AppOverlay/Android.bp b/core/tests/overlaytests/device_non_system/test-apps/AppOverlay/Android.bp new file mode 100644 index 000000000000..b5e6d9c692bd --- /dev/null +++ b/core/tests/overlaytests/device_non_system/test-apps/AppOverlay/Android.bp @@ -0,0 +1,30 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +//      http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { +    // See: http://go/android-license-faq +    // A large-scale-change added 'default_applicable_licenses' to import +    // all of the 'license_kinds' from "frameworks_base_license" +    // to get the below license kinds: +    //   SPDX-license-identifier-Apache-2.0 +    default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { +    name: "OverlayDeviceTestsNonSystem_AppOverlay", +    team: "trendy_team_android_resources", +    sdk_version: "current", +    certificate: "platform", +    aaptflags: ["--no-resource-removal"], +} diff --git a/core/tests/overlaytests/device_non_system/test-apps/AppOverlay/AndroidManifest.xml b/core/tests/overlaytests/device_non_system/test-apps/AppOverlay/AndroidManifest.xml new file mode 100644 index 000000000000..4df80c085602 --- /dev/null +++ b/core/tests/overlaytests/device_non_system/test-apps/AppOverlay/AndroidManifest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + +     Licensed under the Apache License, Version 2.0 (the "License"); +     you may not use this file except in compliance with the License. +     You may obtain a copy of the License at + +          http://www.apache.org/licenses/LICENSE-2.0 + +     Unless required by applicable law or agreed to in writing, software +     distributed under the License is distributed on an "AS IS" BASIS, +     WITHOUT 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.non_system.app_overlay" +    android:versionCode="1" +    android:versionName="1.0"> +    <application android:hasCode="false" /> +    <overlay android:targetPackage="com.android.overlaytest.non_system" +        android:targetName="TestResources" +        android:isStatic="true" +        android:resourcesMap="@xml/overlays"/> +</manifest>
\ No newline at end of file diff --git a/core/tests/overlaytests/device_non_system/test-apps/AppOverlay/res/xml/overlays.xml b/core/tests/overlaytests/device_non_system/test-apps/AppOverlay/res/xml/overlays.xml new file mode 100644 index 000000000000..d0d4bfed94ed --- /dev/null +++ b/core/tests/overlaytests/device_non_system/test-apps/AppOverlay/res/xml/overlays.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2024 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  ~ See the License for the specific language governing permissions and +  ~ limitations under the License. +  --> +<overlay> +    <item target="string/test_string" value="Overlaid"/> +</overlay>
\ No newline at end of file diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 6cf12deea928..483b6934ee8c 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1045,12 +1045,6 @@        "group": "WM_DEBUG_BACK_PREVIEW",        "at": "com\/android\/server\/wm\/BackNavigationController.java"      }, -    "-1459414342866553129": { -      "message": "Current focused window being animated by recents. Overriding back callback to recents controller callback.", -      "level": "DEBUG", -      "group": "WM_DEBUG_BACK_PREVIEW", -      "at": "com\/android\/server\/wm\/BackNavigationController.java" -    },      "2881085074175114605": {        "message": "Focused window didn't have a valid surface drawn.",        "level": "DEBUG", diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 2f2215fd51a2..d1d7c145680f 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -16,8 +16,6 @@  package android.security; -import android.compat.annotation.UnsupportedAppUsage; -  /**   * This class provides some constants and helper methods related to Android's Keystore service.   * This class was originally much larger, but its functionality was superseded by other classes. @@ -30,11 +28,4 @@ public class KeyStore {      // Used for UID field to indicate the calling UID.      public static final int UID_SELF = -1; - -    private static final KeyStore KEY_STORE = new KeyStore(); - -    @UnsupportedAppUsage -    public static KeyStore getInstance() { -        return KEY_STORE; -    }  } diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt index e73d8802f0b2..8487e3792993 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt @@ -18,6 +18,7 @@ package com.android.wm.shell.bubbles  import android.content.Context  import android.content.Intent  import android.content.pm.ShortcutInfo +import android.content.res.Resources  import android.graphics.Insets  import android.graphics.PointF  import android.graphics.Rect @@ -43,6 +44,9 @@ class BubblePositionerTest {      private lateinit var positioner: BubblePositioner      private val context = ApplicationProvider.getApplicationContext<Context>() +    private val resources: Resources +        get() = context.resources +      private val defaultDeviceConfig =          DeviceConfig(              windowBounds = Rect(0, 0, 1000, 2000), @@ -205,6 +209,58 @@ class BubblePositionerTest {      }      @Test +    fun testBubbleBarExpandedViewHeightAndWidth() { +        val deviceConfig = +            defaultDeviceConfig.copy( +                // portrait orientation +                isLandscape = false, +                isLargeScreen = true, +                insets = Insets.of(10, 20, 5, 15), +                windowBounds = Rect(0, 0, 1800, 2600) +            ) +        val bubbleBarBounds = Rect(1700, 2500, 1780, 2600) + +        positioner.setShowingInBubbleBar(true) +        positioner.update(deviceConfig) +        positioner.bubbleBarBounds = bubbleBarBounds + +        val spaceBetweenTopInsetAndBubbleBarInLandscape = 1680 +        val expandedViewVerticalSpacing = +            resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) +        val expectedHeight = +            spaceBetweenTopInsetAndBubbleBarInLandscape - 2 * expandedViewVerticalSpacing +        val expectedWidth = resources.getDimensionPixelSize(R.dimen.bubble_bar_expanded_view_width) + +        assertThat(positioner.getExpandedViewWidthForBubbleBar(false)).isEqualTo(expectedWidth) +        assertThat(positioner.getExpandedViewHeightForBubbleBar(false)).isEqualTo(expectedHeight) +    } + +    @Test +    fun testBubbleBarExpandedViewHeightAndWidth_screenWidthTooSmall() { +        val screenWidth = 300 +        val deviceConfig = +            defaultDeviceConfig.copy( +                // portrait orientation +                isLandscape = false, +                isLargeScreen = true, +                insets = Insets.of(10, 20, 5, 15), +                windowBounds = Rect(0, 0, screenWidth, 2600) +            ) +        val bubbleBarBounds = Rect(100, 2500, 280, 2550) +        positioner.setShowingInBubbleBar(true) +        positioner.update(deviceConfig) +        positioner.bubbleBarBounds = bubbleBarBounds + +        val spaceBetweenTopInsetAndBubbleBarInLandscape = 180 +        val expandedViewSpacing = +            resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) +        val expectedHeight = spaceBetweenTopInsetAndBubbleBarInLandscape - 2 * expandedViewSpacing +        val expectedWidth = screenWidth - 15 /* horizontal insets */ - 2 * expandedViewSpacing +        assertThat(positioner.getExpandedViewWidthForBubbleBar(false)).isEqualTo(expectedWidth) +        assertThat(positioner.getExpandedViewHeightForBubbleBar(false)).isEqualTo(expectedHeight) +    } + +    @Test      fun testGetExpandedViewHeight_max() {          val deviceConfig =              defaultDeviceConfig.copy( diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml index ef7478c04dda..c0ff1922edc8 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml @@ -22,14 +22,15 @@      android:layout_height="wrap_content"      android:gravity="center_horizontal"> -    <ImageButton +    <com.android.wm.shell.windowdecor.HandleImageButton          android:id="@+id/caption_handle"          android:layout_width="@dimen/desktop_mode_fullscreen_decor_caption_width"          android:layout_height="@dimen/desktop_mode_fullscreen_decor_caption_height"          android:paddingVertical="16dp" +        android:paddingHorizontal="10dp"          android:contentDescription="@string/handle_text"          android:src="@drawable/decor_handle_dark"          tools:tint="@color/desktop_mode_caption_handle_bar_dark"          android:scaleType="fitXY" -        android:background="?android:selectableItemBackground"/> +        android:background="@android:color/transparent"/>  </com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml index dd6f8455f82a..b9ff5c682b42 100644 --- a/libs/WindowManager/Shell/res/values-af/strings.xml +++ b/libs/WindowManager/Shell/res/values-af/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Maak toe"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Maak kieslys toe"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Maak kieslys oop"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimeer skerm"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Gryp skerm vas"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml index 18a4ccf5c16d..81ab3ab15aad 100644 --- a/libs/WindowManager/Shell/res/values-am/strings.xml +++ b/libs/WindowManager/Shell/res/values-am/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"ዝጋ"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"ምናሌ ዝጋ"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"ምናሌን ክፈት"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"የማያ ገጹ መጠን አሳድግ"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ማያ ገጹን አሳድግ"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml index 7ca335e4a655..3974c39d4803 100644 --- a/libs/WindowManager/Shell/res/values-ar/strings.xml +++ b/libs/WindowManager/Shell/res/values-ar/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"إغلاق"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"إغلاق القائمة"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"فتح القائمة"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"تكبير الشاشة إلى أقصى حدّ"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"التقاط صورة للشاشة"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml index 944c4f25bf2a..a1ce1b3b9513 100644 --- a/libs/WindowManager/Shell/res/values-as/strings.xml +++ b/libs/WindowManager/Shell/res/values-as/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"বন্ধ কৰক"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"মেনু বন্ধ কৰক"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"মেনু খোলক"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্ৰীন মেক্সিমাইজ কৰক"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"স্ক্ৰীন স্নেপ কৰক"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml index c320e415d604..71dfe5ac6bed 100644 --- a/libs/WindowManager/Shell/res/values-az/strings.xml +++ b/libs/WindowManager/Shell/res/values-az/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Bağlayın"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Menyunu bağlayın"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Menyunu açın"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı maksimum böyüdün"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranı çəkin"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml index 19ca4d300b7e..f48360991d49 100644 --- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml +++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Otvorite meni"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Povećaj ekran"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Uklopi ekran"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml index 74ae1d7637d0..81d066f82261 100644 --- a/libs/WindowManager/Shell/res/values-be/strings.xml +++ b/libs/WindowManager/Shell/res/values-be/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Закрыць"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Закрыць меню"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Адкрыць меню"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Разгарнуць на ўвесь экран"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Размясціць на палавіне экрана"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml index 1b753f5359ba..8f828badcf47 100644 --- a/libs/WindowManager/Shell/res/values-bg/strings.xml +++ b/libs/WindowManager/Shell/res/values-bg/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Затваряне"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Затваряне на менюто"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Отваряне на менюто"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Увеличаване на екрана"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Прилепване на екрана"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml index 2ea22cc1455a..e0a2ea824be0 100644 --- a/libs/WindowManager/Shell/res/values-bn/strings.xml +++ b/libs/WindowManager/Shell/res/values-bn/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"বন্ধ করুন"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"\'মেনু\' বন্ধ করুন"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"মেনু খুলুন"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্রিন বড় করুন"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"স্ক্রিনে অ্যাপ মানানসই হিসেবে ছোট বড় করুন"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml index 13655b3c5c85..41c72c1d3a03 100644 --- a/libs/WindowManager/Shell/res/values-bs/strings.xml +++ b/libs/WindowManager/Shell/res/values-bs/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Zatvaranje"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvaranje menija"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Otvaranje menija"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiziraj ekran"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snimi ekran"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml index cb897c5b612d..679227248ea5 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Tanca"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Tanca el menú"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Obre el menú"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximitza la pantalla"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajusta la pantalla"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml index ded2707afd1d..aafb2e16b703 100644 --- a/libs/WindowManager/Shell/res/values-cs/strings.xml +++ b/libs/WindowManager/Shell/res/values-cs/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Zavřít"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Zavřít nabídku"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Otevřít nabídku"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovat obrazovku"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Rozpůlit obrazovku"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml index 2bdb29d67447..8878910a4d2c 100644 --- a/libs/WindowManager/Shell/res/values-da/strings.xml +++ b/libs/WindowManager/Shell/res/values-da/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Luk"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Luk menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Åbn menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimér skærm"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Tilpas skærm"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index e99d9d0c269a..7b5c471e074f 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Schließen"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Menü schließen"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Menü öffnen"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Bildschirm maximieren"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Bildschirm teilen"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml index d8bb740535fc..14e5e2f87ab8 100644 --- a/libs/WindowManager/Shell/res/values-el/strings.xml +++ b/libs/WindowManager/Shell/res/values-el/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Κλείσιμο"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Κλείσιμο μενού"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Άνοιγμα μενού"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Μεγιστοποίηση οθόνης"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Προβολή στο μισό της οθόνης"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml index 5e1b274705dd..7427b62679be 100644 --- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Close"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml index 2525b321d9d7..cb9ee4f6b6b3 100644 --- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Close"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Close Menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Open Menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximize Screen"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap Screen"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml index 5e1b274705dd..7427b62679be 100644 --- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Close"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml index 5e1b274705dd..7427b62679be 100644 --- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Close"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Open menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap screen"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml index 0623bef925e2..8498807f9fdb 100644 --- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Close"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Close Menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Open Menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximize Screen"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Snap Screen"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml index 9fe77ddf7e28..406c1f37c455 100644 --- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml +++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Cerrar"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Abrir el menú"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar pantalla"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml index b88f215eb54e..0583d79da127 100644 --- a/libs/WindowManager/Shell/res/values-es/strings.xml +++ b/libs/WindowManager/Shell/res/values-es/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Cerrar"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Abrir menú"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar pantalla"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml index 529b6d10b3c6..70547f566ea6 100644 --- a/libs/WindowManager/Shell/res/values-et/strings.xml +++ b/libs/WindowManager/Shell/res/values-et/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Sule"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Sule menüü"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Ava menüü"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Kuva täisekraanil"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Kuva poolel ekraanil"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml index 7438f4240eae..4be35eac6c1f 100644 --- a/libs/WindowManager/Shell/res/values-eu/strings.xml +++ b/libs/WindowManager/Shell/res/values-eu/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Itxi"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Itxi menua"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Ireki menua"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Handitu pantaila"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Zatitu pantaila"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml index f7fcb2162603..32d5f5f34fb8 100644 --- a/libs/WindowManager/Shell/res/values-fa/strings.xml +++ b/libs/WindowManager/Shell/res/values-fa/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"بستن"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"بستن منو"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"باز کردن منو"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"بزرگ کردن صفحه"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"بزرگ کردن صفحه"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml index 400107317637..6f03545e5542 100644 --- a/libs/WindowManager/Shell/res/values-fi/strings.xml +++ b/libs/WindowManager/Shell/res/values-fi/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Sulje"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Sulje valikko"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Avaa valikko"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Suurenna näyttö"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Jaa näyttö"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml index b54f9cf2f15d..1fde4cfb76f8 100644 --- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Fermer"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Ouvrir le menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Agrandir l\'écran"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Aligner l\'écran"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml index 357ff91df06d..e7233ae029b5 100644 --- a/libs/WindowManager/Shell/res/values-fr/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Fermer"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Ouvrir le menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mettre en plein écran"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fractionner l\'écran"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml index a62190754129..89db32793b32 100644 --- a/libs/WindowManager/Shell/res/values-gl/strings.xml +++ b/libs/WindowManager/Shell/res/values-gl/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Pechar"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Pechar o menú"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Abrir menú"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Encaixar pantalla"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml index 43c178f50d15..7e3d7a373be4 100644 --- a/libs/WindowManager/Shell/res/values-gu/strings.xml +++ b/libs/WindowManager/Shell/res/values-gu/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"બંધ કરો"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"મેનૂ બંધ કરો"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"મેનૂ ખોલો"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"સ્ક્રીન કરો મોટી કરો"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"સ્ક્રીન સ્નૅપ કરો"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml index 9f6a57fa0d73..cd0f4e3618f7 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"बंद करें"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"मेन्यू बंद करें"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"मेन्यू खोलें"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन को बड़ा करें"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्नैप स्क्रीन"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml index 4378c5642f5c..fc3942095fdf 100644 --- a/libs/WindowManager/Shell/res/values-hr/strings.xml +++ b/libs/WindowManager/Shell/res/values-hr/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite izbornik"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Otvaranje izbornika"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimalno povećaj zaslon"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Izradi snimku zaslona"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml index e5f199fea647..a8cc5c120efc 100644 --- a/libs/WindowManager/Shell/res/values-hu/strings.xml +++ b/libs/WindowManager/Shell/res/values-hu/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Bezárás"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Menü bezárása"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Menü megnyitása"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Képernyő méretének maximalizálása"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Igazodás a képernyő adott részéhez"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml index e0a5afe13827..7f372774241a 100644 --- a/libs/WindowManager/Shell/res/values-hy/strings.xml +++ b/libs/WindowManager/Shell/res/values-hy/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Փակել"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Փակել ընտրացանկը"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Բացել ընտրացանկը"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ծավալել էկրանը"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ծալել էկրանը"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml index 802583771852..3cf55fa0ede2 100644 --- a/libs/WindowManager/Shell/res/values-in/strings.xml +++ b/libs/WindowManager/Shell/res/values-in/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Tutup"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Buka Menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Perbesar Layar"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Gabungkan Layar"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml index cece56ec960f..6aa56f9858ad 100644 --- a/libs/WindowManager/Shell/res/values-is/strings.xml +++ b/libs/WindowManager/Shell/res/values-is/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Loka"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Loka valmynd"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Opna valmynd"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Stækka skjá"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Smelluskjár"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml index 731db8c12825..3c1d5e4dac02 100644 --- a/libs/WindowManager/Shell/res/values-it/strings.xml +++ b/libs/WindowManager/Shell/res/values-it/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Chiudi"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Chiudi il menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Apri menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Massimizza schermo"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Aggancia schermo"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml index adf55f3696c3..a0c3b3a95ca8 100644 --- a/libs/WindowManager/Shell/res/values-iw/strings.xml +++ b/libs/WindowManager/Shell/res/values-iw/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"סגירה"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"פתיחת התפריט"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"הגדלת המסך"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"כיווץ המסך"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml index 35432229dc7b..fb726c180997 100644 --- a/libs/WindowManager/Shell/res/values-ja/strings.xml +++ b/libs/WindowManager/Shell/res/values-ja/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"閉じる"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"メニューを閉じる"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"メニューを開く"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"画面の最大化"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"画面のスナップ"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml index 1e6e657b5cf8..e9f620a17203 100644 --- a/libs/WindowManager/Shell/res/values-ka/strings.xml +++ b/libs/WindowManager/Shell/res/values-ka/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"დახურვა"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"მენიუს დახურვა"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"მენიუს გახსნა"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"აპლიკაციის გაშლა სრულ ეკრანზე"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"აპლიკაციის დაპატარავება ეკრანზე"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml index 6d9ff26132ea..34e41038f285 100644 --- a/libs/WindowManager/Shell/res/values-kk/strings.xml +++ b/libs/WindowManager/Shell/res/values-kk/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Жабу"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Мәзірді жабу"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Мәзірді ашу"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды ұлғайту"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Экранды бөлу"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml index 586ef7327a70..362bbad4ec12 100644 --- a/libs/WindowManager/Shell/res/values-km/strings.xml +++ b/libs/WindowManager/Shell/res/values-km/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"បិទ"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"បិទម៉ឺនុយ"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"បើកម៉ឺនុយ"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ពង្រីកអេក្រង់"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ថតអេក្រង់"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml index 78ca0c7979a9..77cc4a44f81a 100644 --- a/libs/WindowManager/Shell/res/values-kn/strings.xml +++ b/libs/WindowManager/Shell/res/values-kn/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"ಮುಚ್ಚಿ"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"ಮೆನು ಮುಚ್ಚಿ"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"ಮೆನು ತೆರೆಯಿರಿ"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ಸ್ಕ್ರೀನ್ ಅನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ಸ್ನ್ಯಾಪ್ ಸ್ಕ್ರೀನ್"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index 70aa3767d7dd..e8b5522838b7 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"닫기"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"메뉴 닫기"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"메뉴 열기"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"화면 최대화"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"화면 분할"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml index b2a0a49b401a..7b7779d85d78 100644 --- a/libs/WindowManager/Shell/res/values-ky/strings.xml +++ b/libs/WindowManager/Shell/res/values-ky/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Жабуу"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Менюну жабуу"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Менюну ачуу"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды чоңойтуу"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Экранды сүрөткө тартып алуу"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml index 1cbdbd412631..a3519636b71f 100644 --- a/libs/WindowManager/Shell/res/values-lo/strings.xml +++ b/libs/WindowManager/Shell/res/values-lo/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"ປິດ"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"ປິດເມນູ"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"ເປີດເມນູ"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ປັບຈໍໃຫຍ່ສຸດ"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ສະແນັບໜ້າຈໍ"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml index d154c57704a1..e4dd7398f679 100644 --- a/libs/WindowManager/Shell/res/values-lt/strings.xml +++ b/libs/WindowManager/Shell/res/values-lt/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Uždaryti"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Uždaryti meniu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Atidaryti meniu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Išskleisti ekraną"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Sutraukti ekraną"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml index ce269503ceef..99aebf626322 100644 --- a/libs/WindowManager/Shell/res/values-lv/strings.xml +++ b/libs/WindowManager/Shell/res/values-lv/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Aizvērt"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Aizvērt izvēlni"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Atvērt izvēlni"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizēt ekrānu"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fiksēt ekrānu"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml index 9d69c50626be..c152c60fa631 100644 --- a/libs/WindowManager/Shell/res/values-mk/strings.xml +++ b/libs/WindowManager/Shell/res/values-mk/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Затворете"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Затворете го менито"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Отвори го менито"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Максимизирај го екранот"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Подели го екранот на половина"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml index c0e83386d572..90275cdb517a 100644 --- a/libs/WindowManager/Shell/res/values-ml/strings.xml +++ b/libs/WindowManager/Shell/res/values-ml/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"അടയ്ക്കുക"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"മെനു അടയ്ക്കുക"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"മെനു തുറക്കുക"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"സ്ക്രീൻ വലുതാക്കുക"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"സ്ക്രീൻ സ്നാപ്പ് ചെയ്യുക"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml index ba5d283fb8a7..4a9fab92f11f 100644 --- a/libs/WindowManager/Shell/res/values-mn/strings.xml +++ b/libs/WindowManager/Shell/res/values-mn/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Хаах"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Цэс нээх"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Дэлгэцийг томруулах"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Дэлгэцийг таллах"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml index 17601c18366a..5874bffc9199 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"बंद करा"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"मेनू बंद करा"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"मेनू उघडा"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन मोठी करा"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्क्रीन स्नॅप करा"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml index d5547fa8a056..4de8a7b03547 100644 --- a/libs/WindowManager/Shell/res/values-ms/strings.xml +++ b/libs/WindowManager/Shell/res/values-ms/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Tutup"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Buka Menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimumkan Skrin"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Tangkap Skrin"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml index 07bfc990d62d..5b9e9cb7353e 100644 --- a/libs/WindowManager/Shell/res/values-my/strings.xml +++ b/libs/WindowManager/Shell/res/values-my/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"ပိတ်ရန်"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"မီနူး ပိတ်ရန်"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"မီနူး ဖွင့်ရန်"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"စခရင်ကို ချဲ့မည်"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"စခရင်ကို ချုံ့မည်"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml index f609d019daae..9f03d8b5b178 100644 --- a/libs/WindowManager/Shell/res/values-nb/strings.xml +++ b/libs/WindowManager/Shell/res/values-nb/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Lukk"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Lukk menyen"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Åpne menyen"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimer skjermen"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fest skjermen"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index 9a26b7e25187..e4830af1bad6 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"बन्द गर्नुहोस्"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"मेनु बन्द गर्नुहोस्"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"मेनु खोल्नुहोस्"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रिन ठुलो बनाउनुहोस्"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"स्क्रिन स्न्याप गर्नुहोस्"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml index a38cb7547385..0cd27c5c1457 100644 --- a/libs/WindowManager/Shell/res/values-nl/strings.xml +++ b/libs/WindowManager/Shell/res/values-nl/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Sluiten"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Menu sluiten"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Menu openen"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Scherm maximaliseren"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Scherm halveren"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml index e3097beb6166..bf751852a255 100644 --- a/libs/WindowManager/Shell/res/values-or/strings.xml +++ b/libs/WindowManager/Shell/res/values-or/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"ବନ୍ଦ କରନ୍ତୁ"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"ମେନୁ ବନ୍ଦ କରନ୍ତୁ"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"ମେନୁ ଖୋଲନ୍ତୁ"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ସ୍କ୍ରିନକୁ ବଡ଼ କରନ୍ତୁ"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ସ୍କ୍ରିନକୁ ସ୍ନାପ କରନ୍ତୁ"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml index 3aea6f69749f..325c1e80c433 100644 --- a/libs/WindowManager/Shell/res/values-pa/strings.xml +++ b/libs/WindowManager/Shell/res/values-pa/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"ਬੰਦ ਕਰੋ"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"ਮੀਨੂ ਬੰਦ ਕਰੋ"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"ਮੀਨੂ ਖੋਲ੍ਹੋ"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ਸਕ੍ਰੀਨ ਦਾ ਆਕਾਰ ਵਧਾਓ"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ਸਕ੍ਰੀਨ ਨੂੰ ਸਨੈਪ ਕਰੋ"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml index aec3722cefa5..a7648c8e323b 100644 --- a/libs/WindowManager/Shell/res/values-pl/strings.xml +++ b/libs/WindowManager/Shell/res/values-pl/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Zamknij"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Zamknij menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Otwórz menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksymalizuj ekran"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Przyciągnij ekran"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml index ba24d7b3eb07..e47d151337b2 100644 --- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Fechar"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Abrir o menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar tela"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml index f636da7997eb..ff77d3b2d150 100644 --- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Fechar"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Abrir menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar ecrã"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Encaixar ecrã"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml index ba24d7b3eb07..e47d151337b2 100644 --- a/libs/WindowManager/Shell/res/values-pt/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Fechar"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Abrir o menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ajustar tela"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml index c20f350ae198..ae871f3dd42b 100644 --- a/libs/WindowManager/Shell/res/values-ro/strings.xml +++ b/libs/WindowManager/Shell/res/values-ro/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Închide"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Închide meniul"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Deschide meniul"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizează fereastra"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Micșorează fereastra și fixeaz-o"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml index 49347d2d8086..e23c1ff19563 100644 --- a/libs/WindowManager/Shell/res/values-ru/strings.xml +++ b/libs/WindowManager/Shell/res/values-ru/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Закрыть"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Закрыть меню"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Открыть меню"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Развернуть на весь экран"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Свернуть"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml index e5a974683e49..ef1381cbe635 100644 --- a/libs/WindowManager/Shell/res/values-si/strings.xml +++ b/libs/WindowManager/Shell/res/values-si/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"වසන්න"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"මෙනුව වසන්න"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"මෙනුව විවෘත කරන්න"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"තිරය උපරිම කරන්න"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"ස්නැප් තිරය"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml index c2d20ddb0d3b..55a03122483b 100644 --- a/libs/WindowManager/Shell/res/values-sk/strings.xml +++ b/libs/WindowManager/Shell/res/values-sk/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Zavrieť"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Zavrieť ponuku"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Otvoriť ponuku"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovať obrazovku"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Zobraziť polovicu obrazovky"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml index cfe4480c6e1a..bb123dcdbfb6 100644 --- a/libs/WindowManager/Shell/res/values-sl/strings.xml +++ b/libs/WindowManager/Shell/res/values-sl/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Zapri"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Zapri meni"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Odpri meni"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiraj zaslon"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Pripni zaslon"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index cba98c2fb61a..c74a8cd23338 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Mbyll"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Mbyll menynë"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Hap menynë"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizo ekranin"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Regjistro ekranin"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml index 5031f5bf5d64..0694a973dc1e 100644 --- a/libs/WindowManager/Shell/res/values-sr/strings.xml +++ b/libs/WindowManager/Shell/res/values-sr/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Затворите"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Отворите мени"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Повећај екран"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Уклопи екран"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml index 742be37b67ef..8e0bcfe91679 100644 --- a/libs/WindowManager/Shell/res/values-sv/strings.xml +++ b/libs/WindowManager/Shell/res/values-sv/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Stäng"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Stäng menyn"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Öppna menyn"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximera skärmen"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Fäst skärmen"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml index 68a7262d0eaf..41180abcf712 100644 --- a/libs/WindowManager/Shell/res/values-sw/strings.xml +++ b/libs/WindowManager/Shell/res/values-sw/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Funga"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Funga Menyu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Fungua Menyu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Panua Dirisha kwenye Skrini"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Panga Madirisha kwenye Skrini"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml index fe8fa057dc95..01ac78d984f3 100644 --- a/libs/WindowManager/Shell/res/values-ta/strings.xml +++ b/libs/WindowManager/Shell/res/values-ta/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"மூடும்"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"மெனுவை மூடும்"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"மெனுவைத் திற"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"திரையைப் பெரிதாக்கு"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"திரையை ஸ்னாப் செய்"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml index 9be3f3354635..6224e72c19fe 100644 --- a/libs/WindowManager/Shell/res/values-te/strings.xml +++ b/libs/WindowManager/Shell/res/values-te/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"మూసివేయండి"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"మెనూను మూసివేయండి"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"మెనూను తెరవండి"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"స్క్రీన్ సైజ్ను పెంచండి"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"స్క్రీన్ను స్నాప్ చేయండి"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml index cd3bf6a626c0..407fbbbb1707 100644 --- a/libs/WindowManager/Shell/res/values-th/strings.xml +++ b/libs/WindowManager/Shell/res/values-th/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"ปิด"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"ปิดเมนู"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"เปิดเมนู"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ขยายหน้าจอให้ใหญ่สุด"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"สแนปหน้าจอ"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml index bf05e149ea57..786e99cfe8c8 100644 --- a/libs/WindowManager/Shell/res/values-tl/strings.xml +++ b/libs/WindowManager/Shell/res/values-tl/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Isara"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Isara ang Menu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Buksan ang Menu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"I-maximize ang Screen"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"I-snap ang Screen"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml index 2dfa38a76dfa..e953f5808aff 100644 --- a/libs/WindowManager/Shell/res/values-tr/strings.xml +++ b/libs/WindowManager/Shell/res/values-tr/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Kapat"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Menüyü kapat"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Menüyü Aç"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı Büyüt"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranın Yarısına Tuttur"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml index 57ca64f5b159..fbdf42e582d1 100644 --- a/libs/WindowManager/Shell/res/values-uk/strings.xml +++ b/libs/WindowManager/Shell/res/values-uk/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Закрити"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Закрити меню"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Відкрити меню"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Розгорнути екран"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Зафіксувати екран"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml index 077037373aa2..5562fa70bf09 100644 --- a/libs/WindowManager/Shell/res/values-ur/strings.xml +++ b/libs/WindowManager/Shell/res/values-ur/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"بند کریں"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"مینیو بند کریں"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"مینو کھولیں"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"اسکرین کو بڑا کریں"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"اسکرین کا اسناپ شاٹ لیں"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml index e2d1f47c210b..50e42329a1a0 100644 --- a/libs/WindowManager/Shell/res/values-uz/strings.xml +++ b/libs/WindowManager/Shell/res/values-uz/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Yopish"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Menyuni yopish"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Menyuni ochish"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranni yoyish"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Ekranni biriktirish"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml index 4608b2b10c3f..6da85881210d 100644 --- a/libs/WindowManager/Shell/res/values-vi/strings.xml +++ b/libs/WindowManager/Shell/res/values-vi/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Đóng"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Đóng trình đơn"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Mở Trình đơn"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mở rộng màn hình"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Điều chỉnh kích thước màn hình"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index cbb857c58611..4318caf26199 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"关闭"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"关闭菜单"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"打开菜单"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"最大化屏幕"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"屏幕快照"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml index d89b2c29216e..72cd39d8e00a 100644 --- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"關閉"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"打開選單"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"貼齊畫面"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml index 4ce50a44e12a..c06d7b105694 100644 --- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"關閉"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"開啟選單"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"貼齊畫面"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml index fa680f6eee89..755414e52762 100644 --- a/libs/WindowManager/Shell/res/values-zu/strings.xml +++ b/libs/WindowManager/Shell/res/values-zu/strings.xml @@ -117,4 +117,6 @@      <string name="close_text" msgid="4986518933445178928">"Vala"</string>      <string name="collapse_menu_text" msgid="7515008122450342029">"Vala Imenyu"</string>      <string name="expand_menu_text" msgid="3847736164494181168">"Vula Imenyu"</string> +    <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Khulisa Isikrini Sifike Ekugcineni"</string> +    <string name="desktop_mode_maximize_menu_snap_text" msgid="2065251022783880154">"Thwebula Isikrini"</string>  </resources> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 39dd4d3af98d..4ee2c1a1da60 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -254,6 +254,8 @@      <dimen name="bubble_bar_expanded_view_caption_dot_size">4dp</dimen>      <!-- The spacing between the dots for the caption menu in the bubble bar expanded view.. -->      <dimen name="bubble_bar_expanded_view_caption_dot_spacing">4dp</dimen> +    <!-- Width of the expanded bubble bar view shown when the bubble is expanded. --> +    <dimen name="bubble_bar_expanded_view_width">412dp</dimen>      <!-- Minimum width of the bubble bar manage menu. -->      <dimen name="bubble_bar_manage_menu_min_width">200dp</dimen>      <!-- Size of the dismiss icon in the bubble bar manage menu. --> @@ -423,8 +425,9 @@      <!-- Height of desktop mode caption for fullscreen tasks. -->      <dimen name="desktop_mode_fullscreen_decor_caption_height">36dp</dimen> -    <!-- Width of desktop mode caption for fullscreen tasks. --> -    <dimen name="desktop_mode_fullscreen_decor_caption_width">128dp</dimen> +    <!-- Width of desktop mode caption for fullscreen tasks. +        80 dp for handle + 20 dp for room to grow on the sides when hovered. --> +    <dimen name="desktop_mode_fullscreen_decor_caption_width">100dp</dimen>      <!-- Required empty space to be visible for partially offscreen tasks. -->      <dimen name="freeform_required_visible_empty_space_in_header">48dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java index 19963675ff86..ce0bf8b29374 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java @@ -17,6 +17,7 @@  package com.android.wm.shell.animation;  import android.graphics.Path; +import android.view.animation.BackGestureInterpolator;  import android.view.animation.Interpolator;  import android.view.animation.LinearInterpolator;  import android.view.animation.PathInterpolator; @@ -95,6 +96,15 @@ public class Interpolators {      public static final PathInterpolator DIM_INTERPOLATOR =              new PathInterpolator(.23f, .87f, .52f, -0.11f); +    /** +     * Use this interpolator for animating progress values coming from the back callback to get +     * the predictive-back-typical decelerate motion. +     * +     * This interpolator is similar to {@link Interpolators#STANDARD_DECELERATE} but has a slight +     * acceleration phase at the start. +     */ +    public static final Interpolator BACK_GESTURE = new BackGestureInterpolator(); +      // Create the default emphasized interpolator      private static PathInterpolator createEmphasizedInterpolator() {          Path path = new Path(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index 73b2656d596a..d3fe4f82daf7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -837,6 +837,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont          // The next callback should be {@link #onBackAnimationFinished}.          if (mCurrentTracker.getTriggerBack()) { +            // notify gesture finished +            mBackNavigationInfo.onBackGestureFinished(true);              dispatchOrAnimateOnBackInvoked(mActiveCallback, mCurrentTracker);          } else {              tryDispatchOnBackCancelled(mActiveCallback); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java index a32b435ff99e..4988a9481d21 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java @@ -28,6 +28,7 @@ import android.view.RemoteAnimationTarget;  import android.window.IBackAnimationRunner;  import android.window.IOnBackInvokedCallback; +import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.jank.Cuj.CujType;  import com.android.wm.shell.common.InteractionJankMonitorUtils; @@ -108,7 +109,8 @@ public class BackAnimationRunner {          }      } -    private boolean shouldMonitorCUJ(RemoteAnimationTarget[] apps) { +    @VisibleForTesting +    boolean shouldMonitorCUJ(RemoteAnimationTarget[] apps) {          return apps.length > 0 && mCujType != NO_CUJ;      } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt index 112ed0941122..7cb56605cc12 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt @@ -87,7 +87,7 @@ class CrossActivityBackAnimation @Inject constructor(      private val enteringStartOffset =          context.resources.getDimension(R.dimen.cross_activity_back_entering_start_offset) -    private val gestureInterpolator = Interpolators.STANDARD_DECELERATE +    private val gestureInterpolator = Interpolators.BACK_GESTURE      private val postCommitInterpolator = Interpolators.FAST_OUT_SLOW_IN      private val verticalMoveInterpolator: Interpolator = DecelerateInterpolator() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java index c34f30df33a2..ee898a73a291 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java @@ -93,7 +93,7 @@ public class CrossTaskBackAnimation extends ShellBackAnimation {      private final PointF mInitialTouchPos = new PointF();      private final Interpolator mPostAnimationInterpolator = Interpolators.EMPHASIZED; -    private final Interpolator mProgressInterpolator = Interpolators.STANDARD_DECELERATE; +    private final Interpolator mProgressInterpolator = Interpolators.BACK_GESTURE;      private final Interpolator mVerticalMoveInterpolator = new DecelerateInterpolator();      private final Matrix mTransformMatrix = new Matrix(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java index 00daddc13346..7a6032c60cce 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java @@ -28,7 +28,7 @@ public class ShellBackAnimationRegistry {      private static final String TAG = "ShellBackPreview";      private final SparseArray<BackAnimationRunner> mAnimationDefinition = new SparseArray<>(); -    private final ShellBackAnimation mDefaultCrossActivityAnimation; +    private ShellBackAnimation mDefaultCrossActivityAnimation;      private final ShellBackAnimation mCustomizeActivityAnimation;      private final ShellBackAnimation mCrossTaskAnimation; @@ -67,10 +67,18 @@ public class ShellBackAnimationRegistry {      void registerAnimation(              @BackNavigationInfo.BackTargetType int type, @NonNull BackAnimationRunner runner) {          mAnimationDefinition.set(type, runner); +        // Only happen in test +        if (BackNavigationInfo.TYPE_CROSS_ACTIVITY == type) { +            mDefaultCrossActivityAnimation = null; +        }      }      void unregisterAnimation(@BackNavigationInfo.BackTargetType int type) {          mAnimationDefinition.remove(type); +        // Only happen in test +        if (BackNavigationInfo.TYPE_CROSS_ACTIVITY == type) { +            mDefaultCrossActivityAnimation = null; +        }      }      /** @@ -129,9 +137,15 @@ public class ShellBackAnimationRegistry {      }      void onConfigurationChanged(Configuration newConfig) { -        mCustomizeActivityAnimation.onConfigurationChanged(newConfig); -        mDefaultCrossActivityAnimation.onConfigurationChanged(newConfig); -        mCrossTaskAnimation.onConfigurationChanged(newConfig); +        if (mCustomizeActivityAnimation != null) { +            mCustomizeActivityAnimation.onConfigurationChanged(newConfig); +        } +        if (mDefaultCrossActivityAnimation != null) { +            mDefaultCrossActivityAnimation.onConfigurationChanged(newConfig); +        } +        if (mCrossTaskAnimation != null) { +            mCrossTaskAnimation.onConfigurationChanged(newConfig); +        }      }      BackAnimationRunner getAnimationRunnerAndInit(BackNavigationInfo backNavigationInfo) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java index 4d5e516f76e5..14c3a0701c83 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java @@ -149,9 +149,10 @@ public class BubblePositioner {          mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);          if (mShowingInBubbleBar) { -            mExpandedViewLargeScreenWidth = isLandscape() -                    ? (int) (bounds.width() * EXPANDED_VIEW_BUBBLE_BAR_LANDSCAPE_WIDTH_PERCENT) -                    : (int) (bounds.width() * EXPANDED_VIEW_BUBBLE_BAR_PORTRAIT_WIDTH_PERCENT); +            mExpandedViewLargeScreenWidth = Math.min( +                    res.getDimensionPixelSize(R.dimen.bubble_bar_expanded_view_width), +                    mPositionRect.width() - 2 * mExpandedViewPadding +            );          } else if (mDeviceConfig.isSmallTablet()) {              mExpandedViewLargeScreenWidth = (int) (bounds.width()                      * EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT); @@ -839,11 +840,42 @@ public class BubblePositioner {       * How tall the expanded view should be when showing from the bubble bar.       */      public int getExpandedViewHeightForBubbleBar(boolean isOverflow) { -        return isOverflow -                ? mOverflowHeight -                : getExpandedViewBottomForBubbleBar() - mInsets.top - mExpandedViewPadding; +        if (isOverflow) { +            return mOverflowHeight; +        } else { +            return getBubbleBarExpandedViewHeightForLandscape(); +        }      } +    /** +     * Calculate the height of expanded view in landscape mode regardless current orientation. +     * Here is an explanation: +     * ------------------------ mScreenRect.top +     * |         top inset ↕  | +     * |----------------------- +     * |      16dp spacing ↕  | +     * |           ---------  | --- expanded view top +     * |           |       |  |   ↑ +     * |           |       |  |   ↓ expanded view height +     * |           ---------  | --- expanded view bottom +     * |      16dp spacing ↕  |   ↑ +     * |         @bubble bar@ |   | height of the bubble bar container +     * ------------------------   | already includes bottom inset and spacing +     * |      bottom inset ↕  |   ↓ +     * |----------------------| --- mScreenRect.bottom +     */ +    private int getBubbleBarExpandedViewHeightForLandscape() { +        int heightOfBubbleBarContainer = +                mScreenRect.height() - getExpandedViewBottomForBubbleBar(); +        // getting landscape height from screen rect +        int expandedViewHeight = Math.min(mScreenRect.width(), mScreenRect.height()); +        expandedViewHeight -= heightOfBubbleBarContainer; /* removing bubble container height */ +        expandedViewHeight -= mInsets.top; /* removing top inset */ +        expandedViewHeight -= mExpandedViewPadding; /* removing spacing */ +        return expandedViewHeight; +    } + +      /** The bottom position of the expanded view when showing above the bubble bar. */      public int getExpandedViewBottomForBubbleBar() {          return mBubbleBarBounds.top - mExpandedViewPadding; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index e210ea731f7a..58942ec92a71 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -1354,6 +1354,13 @@ class DesktopTasksController(                      "setTaskListener"              ) { _ -> listener?.let { remoteListener.register(it) } ?: remoteListener.unregister() }          } + +        override fun moveToDesktop(taskId: Int) { +            ExecutorUtils.executeRemoteCallWithTaskPermission( +                controller, +                "moveToDesktop" +            ) { c -> c.moveToDesktop(taskId) } +        }      }      companion object { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl index 6bdaf1eadb8a..fa4352241193 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl @@ -45,4 +45,7 @@ interface IDesktopMode {      /** Set listener that will receive callbacks about updates to desktop tasks */      oneway void setTaskListener(IDesktopTaskListener listener); + +    /** Move a task with given `taskId` to desktop */ +    void moveToDesktop(int taskId);  }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index b179b5bc3cf6..a454d48ac863 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -159,7 +159,7 @@ public class PipTransition extends PipTransitionController {              @NonNull SurfaceControl.Transaction startTransaction,              @NonNull SurfaceControl.Transaction finishTransaction,              @NonNull Transitions.TransitionFinishCallback finishCallback) { -        if (transition == mEnterTransition) { +        if (transition == mEnterTransition || info.getType() == TRANSIT_PIP) {              mEnterTransition = null;              if (mPipScheduler.isInSwipePipToHomeTransition()) {                  // If this is the second transition as a part of swipe PiP to home cuj, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index 3b4fb9fbd8a1..24cf3706e25a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;  import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;  import static android.view.WindowManager.TRANSIT_CHANGE;  import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED; +import static android.view.WindowManager.TRANSIT_PIP;  import static android.view.WindowManager.TRANSIT_SLEEP;  import static android.view.WindowManager.TRANSIT_TO_FRONT;  import static android.window.TransitionInfo.FLAG_TRANSLUCENT; @@ -59,6 +60,7 @@ import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.os.IResultReceiver;  import com.android.internal.protolog.common.ProtoLog;  import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.pip.PipUtils;  import com.android.wm.shell.protolog.ShellProtoLogGroup;  import com.android.wm.shell.shared.TransitionUtil;  import com.android.wm.shell.sysui.ShellInit; @@ -1023,13 +1025,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {                  }                  if (mPipTransaction != null && sendUserLeaveHint) {                      SurfaceControl pipLeash = null; +                    TransitionInfo.Change pipChange = null;                      if (mPipTask != null) { -                        pipLeash = mInfo.getChange(mPipTask).getLeash(); +                        pipChange = mInfo.getChange(mPipTask); +                        pipLeash = pipChange.getLeash();                      } else if (mPipTaskId != -1) {                          // find a task with taskId from #setFinishTaskTransaction()                          for (TransitionInfo.Change change : mInfo.getChanges()) {                              if (change.getTaskInfo() != null                                      && change.getTaskInfo().taskId == mPipTaskId) { +                                pipChange = change;                                  pipLeash = change.getLeash();                                  ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,                                          "RecentsController.finishInner:" @@ -1048,6 +1053,28 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {                          ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,                                  "RecentsController.finishInner: PiP transaction %s merged",                                  mPipTransaction); +                        if (PipUtils.isPip2ExperimentEnabled()) { +                            // If this path is triggered, we are in auto-enter PiP flow in gesture +                            // navigation mode, which means "Recents" transition should be followed +                            // by a TRANSIT_PIP. Hence, we take the WCT was about to be sent +                            // to Core to be applied during finishTransition(), we modify it to +                            // factor in PiP changes, and we send it as a direct startWCT for +                            // a new TRANSIT_PIP type transition. Recents still sends +                            // finishTransition() to update visibilities, but with finishWCT=null. +                            TransitionRequestInfo requestInfo = new TransitionRequestInfo( +                                    TRANSIT_PIP, null /* triggerTask */, pipChange.getTaskInfo(), +                                    null /* remote */, null /* displayChange */, 0 /* flags */); +                            // Use mTransition IBinder token temporarily just to get PipTransition +                            // to return from its handleRequest(). The actual TRANSIT_PIP will have +                            // anew token once it arrives into PipTransition#startAnimation(). +                            Pair<Transitions.TransitionHandler, WindowContainerTransaction> +                                    requestRes = mTransitions.dispatchRequest(mTransition, +                                            requestInfo, null /* skip */); +                            wct.merge(requestRes.second, true); +                            mTransitions.startTransition(TRANSIT_PIP, wct, null /* handler */); +                            // We need to clear the WCT to send finishWCT=null for Recents. +                            wct.clear(); +                        }                      }                      mPipTaskId = -1;                      mPipTask = null; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java index 576219769e61..6aad4e2c9da4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java @@ -18,9 +18,14 @@ package com.android.wm.shell.splitscreen;  import android.annotation.IntDef;  import android.annotation.NonNull; +import android.annotation.Nullable;  import android.app.ActivityManager;  import android.graphics.Rect; +import android.os.Bundle; +import android.window.RemoteTransition; +import com.android.internal.logging.InstanceId; +import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;  import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;  import com.android.wm.shell.shared.annotations.ExternalThread; @@ -72,6 +77,12 @@ public interface SplitScreen {          }      } +    /** Launches a pair of tasks into splitscreen */ +    void startTasks(int taskId1, @Nullable Bundle options1, int taskId2, +            @Nullable Bundle options2, @SplitPosition int splitPosition, +            @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition, +            InstanceId instanceId); +      /** Registers listener that gets split screen callback. */      void registerSplitScreenListener(@NonNull SplitScreenListener listener,              @NonNull Executor executor); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 088bb4814491..547457b018a1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -506,6 +506,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,          return mStageCoordinator.getActivateSplitPosition(taskInfo);      } +    /** Start two tasks in parallel as a splitscreen pair. */ +    public void startTasks(int taskId1, @Nullable Bundle options1, int taskId2, +            @Nullable Bundle options2, @SplitPosition int splitPosition, +            @PersistentSnapPosition int snapPosition, +            @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { +        mStageCoordinator.startTasks(taskId1, options1, taskId2, options2, splitPosition, +                snapPosition, remoteTransition, instanceId); +    } +      /**       * Move a task to split select       * @param taskInfo the task being moved to split select @@ -1120,6 +1129,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,          };          @Override +        public void startTasks(int taskId1, @Nullable Bundle options1, int taskId2, +                @Nullable Bundle options2, int splitPosition, int snapPosition, +                @Nullable RemoteTransition remoteTransition, InstanceId instanceId) { +            mMainExecutor.execute(() -> SplitScreenController.this.startTasks( +                    taskId1, options1, taskId2, options2, splitPosition, snapPosition, +                    remoteTransition, instanceId)); +        } + +        @Override          public void registerSplitScreenListener(SplitScreenListener listener, Executor executor) {              if (mExecutors.containsKey(listener)) return; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 74e85f8dd468..9adb67c8a65e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -507,6 +507,15 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {                  final Point animRelOffset = new Point(                          change.getEndAbsBounds().left - animRoot.getOffset().x,                          change.getEndAbsBounds().top - animRoot.getOffset().y); + +                if (change.getActivityComponent() != null) { +                    // For appcompat letterbox: we intentionally report the task-bounds so that we +                    // can animate as-if letterboxes are "part of" the activity. This means we can't +                    // always rely solely on endAbsBounds and need to also max with endRelOffset. +                    animRelOffset.x = Math.max(animRelOffset.x, change.getEndRelOffset().x); +                    animRelOffset.y = Math.max(animRelOffset.y, change.getEndRelOffset().y); +                } +                  if (change.getActivityComponent() != null && !isActivityLevel) {                      // At this point, this is an independent activity change in a non-activity                      // transition. This means that an activity transition got erroneously combined diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java index c26604a84a61..7c2ba455c0c9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java @@ -293,7 +293,13 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene      @Override      public void onFoldStateChanged(boolean isFolded) {          if (isFolded) { +            // Reset unfold animation finished flag on folding, so it could be used next time +            // when we unfold the device as an indication that animation hasn't finished yet              mAnimationFinished = false; + +            // If we are currently animating unfold animation we should finish it because +            // the animation might not start and finish as the device was folded +            finishTransitionIfNeeded();          }      } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index d0879434657d..963b1303c379 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -19,6 +19,7 @@ package com.android.wm.shell.windowdecor;  import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;  import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;  import static android.app.WindowConfiguration.windowingModeToString; +import static android.view.MotionEvent.ACTION_CANCEL;  import static android.view.MotionEvent.ACTION_DOWN;  import static android.view.MotionEvent.ACTION_UP; @@ -28,6 +29,7 @@ import android.annotation.NonNull;  import android.app.ActivityManager;  import android.app.WindowConfiguration.WindowingMode;  import android.content.Context; +import android.content.pm.ActivityInfo;  import android.content.pm.ApplicationInfo;  import android.content.pm.PackageManager;  import android.content.res.Configuration; @@ -39,6 +41,7 @@ import android.graphics.Rect;  import android.graphics.Region;  import android.graphics.drawable.Drawable;  import android.os.Handler; +import android.util.Log;  import android.view.Choreographer;  import android.view.MotionEvent;  import android.view.SurfaceControl; @@ -433,15 +436,20 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin      }      private void loadAppInfo() { +        final ActivityInfo activityInfo = mTaskInfo.topActivityInfo; +        if (activityInfo == null) { +            Log.e(TAG, "Top activity info not found in task"); +            return; +        }          PackageManager pm = mContext.getApplicationContext().getPackageManager();          final IconProvider provider = new IconProvider(mContext); -        mAppIconDrawable = provider.getIcon(mTaskInfo.topActivityInfo); +        mAppIconDrawable = provider.getIcon(activityInfo);          final Resources resources = mContext.getResources();          final BaseIconFactory factory = new BaseIconFactory(mContext,                  resources.getDisplayMetrics().densityDpi,                  resources.getDimensionPixelSize(R.dimen.desktop_mode_caption_icon_radius));          mAppIconBitmap = factory.createScaledBitmap(mAppIconDrawable, MODE_DEFAULT); -        final ApplicationInfo applicationInfo = mTaskInfo.topActivityInfo.applicationInfo; +        final ApplicationInfo applicationInfo = activityInfo.applicationInfo;          mAppName = pm.getApplicationLabel(applicationInfo);      } @@ -752,7 +760,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin          final int action = ev.getActionMasked();          // The comparison against ACTION_UP is needed for the cancel drag to desktop case.          handle.setHovered(inHandle && action != ACTION_UP); -        handle.setPressed(inHandle && action == ACTION_DOWN); +        // We want handle to remain pressed if the pointer moves outside of it during a drag. +        handle.setPressed((inHandle && action == ACTION_DOWN) +                || (handle.isPressed() && action != ACTION_UP && action != ACTION_CANCEL));          if (isHandleMenuActive()) {              mHandleMenu.checkMotionEvent(ev);          } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt new file mode 100644 index 000000000000..b21c3f522eab --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleImageButton.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.wm.shell.windowdecor + +import android.animation.ValueAnimator +import android.content.Context +import android.util.AttributeSet +import android.widget.ImageButton + +/** + * [ImageButton] for the handle at the top of fullscreen apps. Has custom hover + * and press handling to grow the handle on hover enter and shrink the handle on + * hover exit and press. + */ +class HandleImageButton (context: Context?, attrs: AttributeSet?) : +    ImageButton(context, attrs) { +    private val handleAnimator = ValueAnimator() + +    override fun onHoverChanged(hovered: Boolean) { +        super.onHoverChanged(hovered) +        if (hovered) { +            animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_HOVER_ENTER_SCALE) +        } else { +            if (!isPressed) { +                animateHandle(HANDLE_HOVER_ANIM_DURATION, HANDLE_DEFAULT_SCALE) +            } +        } +    } + +    override fun setPressed(pressed: Boolean) { +        if (isPressed != pressed) { +            super.setPressed(pressed) +            if (pressed) { +                animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_PRESS_DOWN_SCALE) +            } else { +                animateHandle(HANDLE_PRESS_ANIM_DURATION, HANDLE_DEFAULT_SCALE) +            } +        } +    } + +    private fun animateHandle(duration: Long, endScale: Float) { +        if (handleAnimator.isRunning) { +            handleAnimator.cancel() +        } +        handleAnimator.duration = duration +        handleAnimator.setFloatValues(scaleX, endScale) +        handleAnimator.addUpdateListener { animator -> +            scaleX = animator.animatedValue as Float +        } +        handleAnimator.start() +    } + +    companion object { +        /** The duration of animations related to hover state. **/ +        private const val HANDLE_HOVER_ANIM_DURATION = 300L +        /** The duration of animations related to pressed state. **/ +        private const val HANDLE_PRESS_ANIM_DURATION = 200L +        /** Ending scale for hover enter. **/ +        private const val HANDLE_HOVER_ENTER_SCALE = 1.2f +        /** Ending scale for press down. **/ +        private const val HANDLE_PRESS_DOWN_SCALE = 0.85f +        /** Default scale for handle. **/ +        private const val HANDLE_DEFAULT_SCALE = 1f +    } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt index 2fda3ea8daee..7898567b70e9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuImageButton.kt @@ -21,7 +21,7 @@ import android.view.MotionEvent  import android.widget.ImageButton  /** - * A custom [ImageButton] that intentionally does not handle hover events. + * A custom [ImageButton] for buttons inside handle menu that intentionally doesn't handle hovers.   * This is due to the hover events being handled by [DesktopModeWindowDecorViewModel]   * in order to take the status bar layer into account. Handling it in both classes results in a   * flicker when the hover moves from outside to inside status bar layer. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt index 987aadfbdef2..74499c7e429e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt @@ -33,6 +33,7 @@ class MoveToDesktopAnimator @JvmOverloads constructor(          get() = dragToDesktopAnimator.animatedValue as Float * startBounds.width()      val scale: Float          get() = dragToDesktopAnimator.animatedValue as Float +    private val mostRecentInput = PointF()      private val dragToDesktopAnimator: ValueAnimator = ValueAnimator.ofFloat(1f,              DRAG_FREEFORM_SCALE)              .setDuration(ANIMATION_DURATION.toLong()) @@ -40,9 +41,13 @@ class MoveToDesktopAnimator @JvmOverloads constructor(                  val t = SurfaceControl.Transaction()                  val cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)                  addUpdateListener { +                    setTaskPosition(mostRecentInput.x, mostRecentInput.y)                      t.setScale(taskSurface, scale, scale) -                            .setCornerRadius(taskSurface, cornerRadius) -                            .apply() +                        .setCornerRadius(taskSurface, cornerRadius) +                        .setScale(taskSurface, scale, scale) +                        .setCornerRadius(taskSurface, cornerRadius) +                        .setPosition(taskSurface, position.x, position.y) +                        .apply()                  }              } @@ -78,19 +83,28 @@ class MoveToDesktopAnimator @JvmOverloads constructor(          // allow dragging beyond its stage across any region of the display. Because of that, the          // rawX/Y are more true to where the gesture is on screen and where the surface should be          // positioned. -        position.x = ev.rawX - animatedTaskWidth / 2 -        position.y = ev.rawY +        mostRecentInput.set(ev.rawX, ev.rawY) -        if (!allowSurfaceChangesOnMove) { +        // If animator is running, allow it to set scale and position at the same time. +        if (!allowSurfaceChangesOnMove || dragToDesktopAnimator.isRunning) {              return          } - +        setTaskPosition(ev.rawX, ev.rawY)          val t = transactionFactory()          t.setPosition(taskSurface, position.x, position.y)          t.apply()      }      /** +     * Calculates the top left corner of task from input coordinates. +     * Top left will be needed for the resulting surface control transaction. +     */ +    private fun setTaskPosition(x: Float, y: Float) { +        position.x = x - animatedTaskWidth / 2 +        position.y = y +    } + +    /**       * Cancels the animation, intended to be used when another animator will take over.       */      fun cancelAnimator() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index 32c2d1e9b257..51b0a246f3e9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -40,7 +40,6 @@ import android.view.LayoutInflater;  import android.view.SurfaceControl;  import android.view.SurfaceControlViewHost;  import android.view.View; -import android.view.ViewRootImpl;  import android.view.WindowInsets;  import android.view.WindowManager;  import android.view.WindowlessWindowManager; @@ -293,60 +292,56 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>                  .setLayer(mCaptionContainerSurface, CAPTION_LAYER_Z_ORDER)                  .show(mCaptionContainerSurface); -        if (ViewRootImpl.CAPTION_ON_SHELL) { -            outResult.mRootView.setTaskFocusState(mTaskInfo.isFocused); - -            // Caption insets -            if (mIsCaptionVisible) { -                // Caption inset is the full width of the task with the |captionHeight| and -                // positioned at the top of the task bounds, also in absolute coordinates. -                // So just reuse the task bounds and adjust the bottom coordinate. -                mCaptionInsetsRect.set(taskBounds); -                mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + outResult.mCaptionHeight; - -                // Caption bounding rectangles: these are optional, and are used to present finer -                // insets than traditional |Insets| to apps about where their content is occluded. -                // These are also in absolute coordinates. -                final Rect[] boundingRects; -                final int numOfElements = params.mOccludingCaptionElements.size(); -                if (numOfElements == 0) { -                    boundingRects = null; -                } else { -                    // The customizable region can at most be equal to the caption bar. +        outResult.mRootView.setTaskFocusState(mTaskInfo.isFocused); + +        // Caption insets +        if (mIsCaptionVisible) { +            // Caption inset is the full width of the task with the |captionHeight| and +            // positioned at the top of the task bounds, also in absolute coordinates. +            // So just reuse the task bounds and adjust the bottom coordinate. +            mCaptionInsetsRect.set(taskBounds); +            mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + outResult.mCaptionHeight; + +            // Caption bounding rectangles: these are optional, and are used to present finer +            // insets than traditional |Insets| to apps about where their content is occluded. +            // These are also in absolute coordinates. +            final Rect[] boundingRects; +            final int numOfElements = params.mOccludingCaptionElements.size(); +            if (numOfElements == 0) { +                boundingRects = null; +            } else { +                // The customizable region can at most be equal to the caption bar. +                if (params.mAllowCaptionInputFallthrough) { +                    outResult.mCustomizableCaptionRegion.set(mCaptionInsetsRect); +                } +                boundingRects = new Rect[numOfElements]; +                for (int i = 0; i < numOfElements; i++) { +                    final OccludingCaptionElement element = +                            params.mOccludingCaptionElements.get(i); +                    final int elementWidthPx = +                            resources.getDimensionPixelSize(element.mWidthResId); +                    boundingRects[i] = +                            calculateBoundingRect(element, elementWidthPx, mCaptionInsetsRect); +                    // Subtract the regions used by the caption elements, the rest is +                    // customizable.                      if (params.mAllowCaptionInputFallthrough) { -                        outResult.mCustomizableCaptionRegion.set(mCaptionInsetsRect); -                    } -                    boundingRects = new Rect[numOfElements]; -                    for (int i = 0; i < numOfElements; i++) { -                        final OccludingCaptionElement element = -                                params.mOccludingCaptionElements.get(i); -                        final int elementWidthPx = -                                resources.getDimensionPixelSize(element.mWidthResId); -                        boundingRects[i] = -                                calculateBoundingRect(element, elementWidthPx, mCaptionInsetsRect); -                        // Subtract the regions used by the caption elements, the rest is -                        // customizable. -                        if (params.mAllowCaptionInputFallthrough) { -                            outResult.mCustomizableCaptionRegion.op(boundingRects[i], -                                    Region.Op.DIFFERENCE); -                        } +                        outResult.mCustomizableCaptionRegion.op(boundingRects[i], +                                Region.Op.DIFFERENCE);                      }                  } -                // Add this caption as an inset source. -                wct.addInsetsSource(mTaskInfo.token, -                        mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect, -                        boundingRects); -                wct.addInsetsSource(mTaskInfo.token, -                        mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures(), -                        mCaptionInsetsRect, null /* boundingRects */); -            } else { -                wct.removeInsetsSource(mTaskInfo.token, mOwner, 0 /* index */, -                        WindowInsets.Type.captionBar()); -                wct.removeInsetsSource(mTaskInfo.token, mOwner, 0 /* index */, -                        WindowInsets.Type.mandatorySystemGestures());              } +            // Add this caption as an inset source. +            wct.addInsetsSource(mTaskInfo.token, +                    mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect, +                    boundingRects); +            wct.addInsetsSource(mTaskInfo.token, +                    mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures(), +                    mCaptionInsetsRect, null /* boundingRects */);          } else { -            startT.hide(mCaptionContainerSurface); +            wct.removeInsetsSource(mTaskInfo.token, mOwner, 0 /* index */, +                    WindowInsets.Type.captionBar()); +            wct.removeInsetsSource(mTaskInfo.token, mOwner, 0 /* index */, +                    WindowInsets.Type.mandatorySystemGestures());          }          // Task surface itself @@ -594,8 +589,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>       */      public void addCaptionInset(WindowContainerTransaction wct) {          final int captionHeightId = getCaptionHeightId(mTaskInfo.getWindowingMode()); -        if (!ViewRootImpl.CAPTION_ON_SHELL || captionHeightId == Resources.ID_NULL -                || !mIsCaptionVisible) { +        if (captionHeightId == Resources.ID_NULL || !mIsCaptionVisible) {              return;          } diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt index 3380adac0b3f..e9eabb4162e3 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt @@ -17,10 +17,10 @@  package com.android.wm.shell.flicker.appcompat  import android.content.Context -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.FlickerTestData  import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher  import com.android.server.wm.flicker.helpers.LetterboxAppHelper  import com.android.server.wm.flicker.helpers.setRotation  import com.android.wm.shell.flicker.BaseTest diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt index f08eba5a73a3..16c2d47f9db3 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt @@ -18,11 +18,11 @@ package com.android.wm.shell.flicker.appcompat  import android.platform.test.annotations.Postsubmit  import android.tools.flicker.assertions.FlickerTest -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher  import androidx.test.filters.RequiresDevice  import org.junit.Test  import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt index 826fc541687e..d85b7718aa56 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt @@ -19,11 +19,11 @@ package com.android.wm.shell.flicker.appcompat  import android.platform.test.annotations.Postsubmit  import android.tools.Rotation  import android.tools.flicker.assertions.FlickerTest -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher  import androidx.test.filters.RequiresDevice  import org.junit.Test  import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt index 26e78bf625ba..164534c14d28 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt @@ -16,17 +16,17 @@  package com.android.wm.shell.flicker.appcompat +import android.graphics.Rect  import android.platform.test.annotations.Postsubmit  import android.platform.test.annotations.RequiresDevice  import android.tools.NavBar  import android.tools.Rotation -import android.tools.datatypes.Rect  import android.tools.flicker.assertions.FlickerTest -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher  import org.junit.FixMethodOrder  import org.junit.Test  import org.junit.runner.RunWith @@ -260,7 +260,7 @@ class QuickSwitchLauncherToLetterboxAppTest(flicker: LegacyFlickerTest) : BaseAp      companion object {          /** {@inheritDoc} */ -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          @Parameterized.Parameters(name = "{0}")          @JvmStatic diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt index 2aa84b4e55b8..034d54b185ed 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt @@ -53,7 +53,7 @@ import org.junit.runners.Parameterized  @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)  class RepositionFixedPortraitAppTest(flicker: LegacyFlickerTest) : BaseAppCompat(flicker) { -    val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation).bounds +    val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)      /** {@inheritDoc} */      override val transition: FlickerBuilder.() -> Unit          get() = { diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt index 7ffa23345589..22543aa9f773 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt @@ -16,19 +16,19 @@  package com.android.wm.shell.flicker.appcompat +import android.graphics.Rect  import android.os.Build  import android.platform.test.annotations.Postsubmit  import android.system.helpers.CommandsHelper  import android.tools.NavBar  import android.tools.Rotation -import android.tools.datatypes.Rect  import android.tools.flicker.assertions.FlickerTest -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory  import android.tools.helpers.FIND_TIMEOUT +import android.tools.traces.component.ComponentNameMatcher  import android.tools.traces.parsers.toFlickerComponent  import androidx.test.uiautomator.By  import androidx.test.uiautomator.UiDevice @@ -167,7 +167,7 @@ class RotateImmersiveAppInFullscreenTest(flicker: LegacyFlickerTest) : BaseAppCo      }      companion object { -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          const val LAUNCHER_PACKAGE = "com.google.android.apps.nexuslauncher"          /** diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt index 521c0d0aaeb7..2a9b1078afe3 100644 --- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt @@ -19,11 +19,11 @@ package com.android.wm.shell.flicker.bubble  import android.content.Context  import android.graphics.Point  import android.platform.test.annotations.Presubmit -import android.tools.flicker.subject.layers.LayersTraceSubject -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.subject.layers.LayersTraceSubject +import android.tools.traces.component.ComponentNameMatcher  import android.util.DisplayMetrics  import android.view.WindowManager  import androidx.test.uiautomator.By diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt index e059ac78dc6b..9ef49c1c9e7e 100644 --- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt @@ -17,10 +17,10 @@  package com.android.wm.shell.flicker.bubble  import android.platform.test.annotations.Postsubmit -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher  import android.view.WindowInsets  import android.view.WindowManager  import androidx.test.filters.FlakyTest diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt index a0edcfb17971..371fee225b34 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt @@ -17,10 +17,10 @@  package com.android.wm.shell.flicker.pip  import android.platform.test.annotations.Presubmit -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher  import org.junit.FixMethodOrder  import org.junit.Test  import org.junit.runner.RunWith @@ -66,9 +66,7 @@ class AutoEnterPipWithSourceRectHintTest(flicker: LegacyFlickerTest) :      @Test      fun pipOverlayNotShown() {          val overlay = ComponentNameMatcher.PIP_CONTENT_OVERLAY -        flicker.assertLayers { -            this.notContains(overlay) -        } +        flicker.assertLayers { this.notContains(overlay) }      }      @Presubmit      @Test @@ -83,4 +81,4 @@ class AutoEnterPipWithSourceRectHintTest(flicker: LegacyFlickerTest) :          // auto enter and sourceRectHint that causes the app to move outside of the display          // bounds during the transition.      } -}
\ No newline at end of file +} diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt index 031acf4919eb..1c0820a2b0db 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt @@ -17,10 +17,10 @@  package com.android.wm.shell.flicker.pip  import android.platform.test.annotations.Presubmit -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher  import com.android.wm.shell.flicker.pip.common.ClosePipTransition  import org.junit.FixMethodOrder  import org.junit.Test @@ -69,7 +69,8 @@ class ClosePipBySwipingDownTest(flicker: LegacyFlickerTest) : ClosePipTransition                  wmHelper.currentState.layerState                      .getLayerWithBuffer(barComponent)                      ?.visibleRegion -                    ?.height +                    ?.bounds +                    ?.height()                      ?: error("Couldn't find Nav or Task bar layer")              // The dismiss button doesn't appear at the complete bottom of the screen,              // it appears above the hot seat but `hotseatBarSize` is not available outside diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt index 9a1bd267ea1f..270ebf5dd29b 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt @@ -21,12 +21,12 @@ import android.platform.test.annotations.Postsubmit  import android.platform.test.annotations.Presubmit  import android.tools.Rotation  import android.tools.flicker.assertions.FlickerTest -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory  import android.tools.helpers.WindowUtils +import android.tools.traces.component.ComponentNameMatcher  import androidx.test.filters.FlakyTest  import com.android.server.wm.flicker.entireScreenCovered  import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt index 25614ef63ccc..eeff167b1fc4 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt @@ -18,11 +18,11 @@ package com.android.wm.shell.flicker.pip  import android.platform.test.annotations.Presubmit  import android.tools.Rotation -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher  import com.android.wm.shell.flicker.pip.common.PipTransition  import org.junit.FixMethodOrder  import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt index 5f25d70acf7c..f81e8490b0eb 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt @@ -191,8 +191,9 @@ class FromSplitScreenEnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) :      companion object {          @Parameterized.Parameters(name = "{0}")          @JvmStatic -        fun getParams() = LegacyFlickerTestFactory.nonRotationTests( -            supportedRotations = listOf(Rotation.ROTATION_0) -        ) +        fun getParams() = +            LegacyFlickerTestFactory.nonRotationTests( +                supportedRotations = listOf(Rotation.ROTATION_0) +            )      }  } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt index e184cf04e4ae..ad3c69eae06a 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt @@ -19,12 +19,12 @@ package com.android.wm.shell.flicker.pip  import android.platform.test.annotations.Presubmit  import android.tools.Rotation  import android.tools.flicker.assertions.FlickerTest -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory  import android.tools.helpers.WindowUtils +import android.tools.traces.component.ComponentNameMatcher  import com.android.server.wm.flicker.helpers.ImeAppHelper  import com.android.server.wm.flicker.helpers.setRotation  import com.android.wm.shell.flicker.pip.common.PipTransition diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt index 68417066ac0a..16d08e5e9055 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt @@ -18,11 +18,11 @@ package com.android.wm.shell.flicker.pip  import android.platform.test.annotations.Presubmit  import android.tools.Rotation -import android.tools.flicker.subject.exceptions.IncorrectRegionException  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.subject.exceptions.IncorrectRegionException  import androidx.test.filters.RequiresDevice  import com.android.wm.shell.flicker.pip.common.PipTransition  import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt index c9f4a6ca75b1..65b60ce1022b 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt @@ -18,12 +18,12 @@ package com.android.wm.shell.flicker.pip.apps  import android.platform.test.annotations.Postsubmit  import android.tools.Rotation -import android.tools.traces.component.ComponentNameMatcher  import android.tools.device.apphelpers.StandardAppHelper  import android.tools.flicker.junit.FlickerBuilderProvider  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher  import com.android.wm.shell.flicker.pip.common.EnterPipTransition  import org.junit.Test  import org.junit.runners.Parameterized diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt index 88650107e63a..1fc9d9910a15 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt @@ -65,8 +65,8 @@ import org.junit.runners.Parameterized  open class MapsEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition(flicker) {      override val standardAppHelper: MapsAppHelper = MapsAppHelper(instrumentation) -    override val permissions: Array<String> = arrayOf(Manifest.permission.POST_NOTIFICATIONS, -        Manifest.permission.ACCESS_FINE_LOCATION) +    override val permissions: Array<String> = +        arrayOf(Manifest.permission.POST_NOTIFICATIONS, Manifest.permission.ACCESS_FINE_LOCATION)      val locationManager: LocationManager =          instrumentation.context.getSystemService(Context.LOCATION_SERVICE) as LocationManager diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt index e85da30440cf..3a0eeb67995b 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt @@ -19,13 +19,13 @@ package com.android.wm.shell.flicker.pip.apps  import android.Manifest  import android.platform.test.annotations.Postsubmit  import android.tools.Rotation -import android.tools.traces.component.ComponentNameMatcher  import android.tools.device.apphelpers.NetflixAppHelper  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory  import android.tools.helpers.WindowUtils +import android.tools.traces.component.ComponentNameMatcher  import androidx.test.filters.RequiresDevice  import com.android.server.wm.flicker.statusBarLayerPositionAtEnd  import org.junit.Assume diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt index 3ae5937df4d0..35ed8de3a464 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt @@ -18,11 +18,11 @@ package com.android.wm.shell.flicker.pip.apps  import android.Manifest  import android.platform.test.annotations.Postsubmit -import android.tools.traces.component.ComponentNameMatcher  import android.tools.device.apphelpers.YouTubeAppHelper  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher  import androidx.test.filters.RequiresDevice  import org.junit.Assume  import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt index de8e7c3b35b1..879034f32514 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt @@ -19,13 +19,13 @@ package com.android.wm.shell.flicker.pip.apps  import android.Manifest  import android.platform.test.annotations.Postsubmit  import android.tools.Rotation -import android.tools.traces.component.ComponentNameMatcher  import android.tools.device.apphelpers.YouTubeAppHelper  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory  import android.tools.helpers.WindowUtils +import android.tools.traces.component.ComponentNameMatcher  import androidx.test.filters.RequiresDevice  import com.android.server.wm.flicker.statusBarLayerPositionAtEnd  import org.junit.Assume diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt index dc122590388f..8cb81b46cf4d 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt @@ -18,10 +18,10 @@ package com.android.wm.shell.flicker.pip.common  import android.platform.test.annotations.Presubmit  import android.tools.Rotation -import android.tools.traces.component.ComponentNameMatcher.Companion.LAUNCHER  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher.Companion.LAUNCHER  import com.android.server.wm.flicker.helpers.setRotation  import org.junit.Test  import org.junit.runners.Parameterized diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt index 3d9eae62b499..6dd3a175da65 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt @@ -18,10 +18,10 @@ package com.android.wm.shell.flicker.pip.common  import android.platform.test.annotations.Presubmit  import android.tools.Rotation -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher  import org.junit.Test  import org.junit.runners.Parameterized diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt index 7b6839dc123f..0742cf9c5887 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt @@ -18,9 +18,9 @@ package com.android.wm.shell.flicker.pip.common  import android.platform.test.annotations.Presubmit  import android.tools.Rotation -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher  import com.android.server.wm.flicker.helpers.SimpleAppHelper  import org.junit.Test  import org.junit.runners.Parameterized diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt index f4baf5f75928..c4881e7e17a1 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt @@ -18,9 +18,9 @@ package com.android.wm.shell.flicker.pip.common  import android.platform.test.annotations.Presubmit  import android.tools.Rotation -import android.tools.flicker.subject.region.RegionSubject  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.subject.region.RegionSubject  import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper  import com.android.wm.shell.flicker.utils.Direction  import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt index fd467e32e0dc..99c1ad2aaa4e 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt @@ -20,11 +20,11 @@ import android.app.Instrumentation  import android.content.Intent  import android.platform.test.annotations.Presubmit  import android.tools.Rotation -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome  import android.tools.helpers.WindowUtils +import android.tools.traces.component.ComponentNameMatcher  import com.android.server.wm.flicker.helpers.PipAppHelper  import com.android.server.wm.flicker.helpers.setRotation  import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt index 9e6a686861c8..bcd0f126daef 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt @@ -24,6 +24,7 @@ import android.tools.traces.parsers.WindowManagerStateHelper  import androidx.test.platform.app.InstrumentationRegistry  import androidx.test.uiautomator.UiDevice  import com.android.launcher3.tapl.LauncherInstrumentation +import com.android.server.wm.flicker.helpers.MultiWindowUtils  import com.android.wm.shell.flicker.service.common.Utils  import com.android.wm.shell.flicker.utils.SplitScreenUtils  import org.junit.After @@ -51,6 +52,10 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) {      fun setup() {          Assume.assumeTrue(tapl.isTablet) +        MultiWindowUtils.executeShellCommand( +                instrumentation, +                "settings put system notification_cooldown_enabled 0" +        )          // Send a notification          sendNotificationApp.launchViaIntent(wmHelper)          sendNotificationApp.postNotification(wmHelper) @@ -74,5 +79,10 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) {          primaryApp.exit(wmHelper)          secondaryApp.exit(wmHelper)          sendNotificationApp.exit(wmHelper) + +        MultiWindowUtils.executeShellCommand( +                instrumentation, +                "settings reset system notification_cooldown_enabled" +        )      }  } diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt index 9312c0aebf98..db962e717a3b 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt @@ -141,7 +141,7 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) {      private fun isLandscape(rotation: Rotation): Boolean {          val displayBounds = WindowUtils.getDisplayBounds(rotation) -        return displayBounds.width > displayBounds.height +        return displayBounds.width() > displayBounds.height()      }      private fun isTablet(): Boolean { diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt index d74c59ef0879..7f48499b0558 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt @@ -17,12 +17,12 @@  package com.android.wm.shell.flicker.splitscreen  import android.platform.test.annotations.Presubmit -import android.tools.traces.component.ComponentNameMatcher -import android.tools.traces.component.EdgeExtensionComponentMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.component.EdgeExtensionComponentMatcher  import androidx.test.filters.FlakyTest  import androidx.test.filters.RequiresDevice  import com.android.wm.shell.flicker.splitscreen.benchmark.CopyContentInSplitBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt index 8724346427f4..a72b3d15eb9e 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt @@ -18,11 +18,11 @@ package com.android.wm.shell.flicker.splitscreen  import android.platform.test.annotations.Presubmit  import android.tools.NavBar -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher  import androidx.test.filters.RequiresDevice  import com.android.server.wm.flicker.helpers.PipAppHelper  import com.android.wm.shell.flicker.splitscreen.benchmark.SplitScreenBase diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt index 16d73318bd3a..90453640c91a 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt @@ -19,13 +19,13 @@ package com.android.wm.shell.flicker.splitscreen  import android.platform.test.annotations.Postsubmit  import android.platform.test.annotations.Presubmit  import android.tools.NavBar -import android.tools.flicker.subject.layers.LayersTraceSubject -import android.tools.flicker.subject.region.RegionSubject -import android.tools.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.subject.layers.LayersTraceSubject +import android.tools.flicker.subject.region.RegionSubject +import android.tools.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER  import androidx.test.filters.FlakyTest  import androidx.test.filters.RequiresDevice  import com.android.wm.shell.flicker.splitscreen.benchmark.UnlockKeyguardToSplitScreenBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt index 9c5a3fe35bfe..7e8e50843b90 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt @@ -16,11 +16,11 @@  package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher  import androidx.test.filters.RequiresDevice  import com.android.wm.shell.flicker.utils.SplitScreenUtils  import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt index 38206c396efb..6a6aa1abc9f3 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt @@ -128,7 +128,7 @@ abstract class SwitchAppByDoubleTapDividerBenchmark(override val flicker: Legacy      private fun isLandscape(rotation: Rotation): Boolean {          val displayBounds = WindowUtils.getDisplayBounds(rotation) -        return displayBounds.width > displayBounds.height +        return displayBounds.width() > displayBounds.height()      }      companion object { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt index a19d232c9a2f..90d2635f6a51 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt @@ -17,8 +17,8 @@  package com.android.wm.shell.flicker  import android.app.Instrumentation -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher  import androidx.test.platform.app.InstrumentationRegistry  import com.android.launcher3.tapl.LauncherInstrumentation  import com.android.wm.shell.flicker.utils.ICommonAssertions diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt index 3df0954da2e9..509f4f202b6b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt @@ -18,13 +18,13 @@  package com.android.wm.shell.flicker.utils +import android.graphics.Region  import android.tools.Rotation -import android.tools.datatypes.Region +import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.flicker.subject.layers.LayerTraceEntrySubject  import android.tools.flicker.subject.layers.LayersTraceSubject -import android.tools.traces.component.IComponentMatcher -import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.helpers.WindowUtils +import android.tools.traces.component.IComponentMatcher  fun LegacyFlickerTest.appPairsDividerIsVisibleAtEnd() {      assertLayersEnd { this.isVisible(APP_PAIR_SPLIT_DIVIDER_COMPONENT) } @@ -263,41 +263,41 @@ fun LayerTraceEntrySubject.splitAppLayerBoundsSnapToDivider(      val displayBounds = WindowUtils.getDisplayBounds(rotation)      return invoke {          val dividerRegion = -            layer(SPLIT_SCREEN_DIVIDER_COMPONENT)?.visibleRegion?.region +            layer(SPLIT_SCREEN_DIVIDER_COMPONENT)?.visibleRegion?.region?.bounds                  ?: error("$SPLIT_SCREEN_DIVIDER_COMPONENT component not found")          visibleRegion(component).isNotEmpty()          visibleRegion(component)              .coversAtMost( -                if (displayBounds.width > displayBounds.height) { +                if (displayBounds.width() > displayBounds.height()) {                      if (landscapePosLeft) { -                        Region.from( +                        Region(                              0,                              0, -                            (dividerRegion.bounds.left + dividerRegion.bounds.right) / 2, -                            displayBounds.bounds.bottom +                            (dividerRegion.left + dividerRegion.right) / 2, +                            displayBounds.bottom                          )                      } else { -                        Region.from( -                            (dividerRegion.bounds.left + dividerRegion.bounds.right) / 2, +                        Region( +                            (dividerRegion.left + dividerRegion.right) / 2,                              0, -                            displayBounds.bounds.right, -                            displayBounds.bounds.bottom +                            displayBounds.right, +                            displayBounds.bottom                          )                      }                  } else {                      if (portraitPosTop) { -                        Region.from( +                        Region(                              0,                              0, -                            displayBounds.bounds.right, -                            (dividerRegion.bounds.top + dividerRegion.bounds.bottom) / 2 +                            displayBounds.right, +                            (dividerRegion.top + dividerRegion.bottom) / 2                          )                      } else { -                        Region.from( +                        Region(                              0, -                            (dividerRegion.bounds.top + dividerRegion.bounds.bottom) / 2, -                            displayBounds.bounds.right, -                            displayBounds.bounds.bottom +                            (dividerRegion.top + dividerRegion.bottom) / 2, +                            displayBounds.right, +                            displayBounds.bottom                          )                      }                  } @@ -420,17 +420,17 @@ fun LegacyFlickerTest.dockedStackSecondaryBoundsIsVisibleAtEnd(  fun getPrimaryRegion(dividerRegion: Region, rotation: Rotation): Region {      val displayBounds = WindowUtils.getDisplayBounds(rotation)      return if (rotation.isRotated()) { -        Region.from( +        Region(              0,              0,              dividerRegion.bounds.left + WindowUtils.dockedStackDividerInset, -            displayBounds.bounds.bottom +            displayBounds.bottom          )      } else { -        Region.from( +        Region(              0,              0, -            displayBounds.bounds.right, +            displayBounds.right,              dividerRegion.bounds.top + WindowUtils.dockedStackDividerInset          )      } @@ -439,18 +439,18 @@ fun getPrimaryRegion(dividerRegion: Region, rotation: Rotation): Region {  fun getSecondaryRegion(dividerRegion: Region, rotation: Rotation): Region {      val displayBounds = WindowUtils.getDisplayBounds(rotation)      return if (rotation.isRotated()) { -        Region.from( +        Region(              dividerRegion.bounds.right - WindowUtils.dockedStackDividerInset,              0, -            displayBounds.bounds.right, -            displayBounds.bounds.bottom +            displayBounds.right, +            displayBounds.bottom          )      } else { -        Region.from( +        Region(              0,              dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset, -            displayBounds.bounds.right, -            displayBounds.bounds.bottom +            displayBounds.right, +            displayBounds.bottom          )      }  } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt index 50c04354528f..4465a16a8e0f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt @@ -17,8 +17,8 @@  package com.android.wm.shell.flicker.utils  import android.platform.test.annotations.Presubmit -import android.tools.traces.component.ComponentNameMatcher  import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher  import com.android.server.wm.flicker.entireScreenCovered  import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd  import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt index 9cc3a989894e..c4954f90179c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt @@ -20,11 +20,11 @@ import android.app.Instrumentation  import android.graphics.Point  import android.os.SystemClock  import android.tools.Rotation +import android.tools.device.apphelpers.StandardAppHelper +import android.tools.flicker.rules.ChangeDisplayOrientationRule  import android.tools.traces.component.ComponentNameMatcher  import android.tools.traces.component.IComponentMatcher  import android.tools.traces.component.IComponentNameMatcher -import android.tools.device.apphelpers.StandardAppHelper -import android.tools.flicker.rules.ChangeDisplayOrientationRule  import android.tools.traces.parsers.WindowManagerStateHelper  import android.tools.traces.parsers.toFlickerComponent  import android.view.InputDevice @@ -182,13 +182,7 @@ object SplitScreenUtils {          val swipeXCoordinate = displayBounds.centerX() / 2          // Pull down the notifications -        device.swipe( -            swipeXCoordinate, -            5, -            swipeXCoordinate, -            displayBounds.bottom, -            50 /* steps */ -        ) +        device.swipe(swipeXCoordinate, 5, swipeXCoordinate, displayBounds.bottom, 50 /* steps */)          SystemClock.sleep(TIMEOUT_MS)          // Find the target notification @@ -211,7 +205,7 @@ object SplitScreenUtils {          // Drag to split          val dragStart = notificationContent.visibleCenter          val dragMiddle = Point(dragStart.x + 50, dragStart.y) -        val dragEnd = Point(displayBounds.width / 4, displayBounds.width / 4) +        val dragEnd = Point(displayBounds.width() / 4, displayBounds.width() / 4)          val downTime = SystemClock.uptimeMillis()          touch(instrumentation, MotionEvent.ACTION_DOWN, downTime, downTime, TIMEOUT_MS, dragStart) @@ -318,7 +312,7 @@ object SplitScreenUtils {              wmHelper.currentState.layerState.displays.firstOrNull { !it.isVirtual }?.layerStackSpace                  ?: error("Display not found")          val dividerBar = device.wait(Until.findObject(dividerBarSelector), TIMEOUT_MS) -        dividerBar.drag(Point(displayBounds.width * 1 / 3, displayBounds.height * 2 / 3), 200) +        dividerBar.drag(Point(displayBounds.width() * 1 / 3, displayBounds.height() * 2 / 3), 200)          wmHelper              .StateSyncBuilder() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java index 9c623bd5b76f..65169e36a225 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java @@ -16,7 +16,7 @@  package com.android.wm.shell.back; -import static android.window.BackNavigationInfo.KEY_TRIGGER_BACK; +import static android.window.BackNavigationInfo.KEY_NAVIGATION_FINISHED;  import static org.junit.Assert.assertTrue;  import static org.mockito.ArgumentMatchers.any; @@ -596,6 +596,7 @@ public class BackAnimationControllerTest extends ShellTestCase {          // Set up the monitoring objects.          doNothing().when(runner).onAnimationStart(anyInt(), any(), any(), any(), any()); +        doReturn(false).when(animationRunner).shouldMonitorCUJ(any());          doReturn(runner).when(animationRunner).getRunner();          doReturn(callback).when(animationRunner).getCallback(); @@ -677,7 +678,7 @@ public class BackAnimationControllerTest extends ShellTestCase {          @Override          public void onResult(@Nullable Bundle result) {              mBackNavigationDone = true; -            mTriggerBack = result.getBoolean(KEY_TRIGGER_BACK); +            mTriggerBack = result.getBoolean(KEY_NAVIGATION_FINISHED);          }      }  } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java index e9da25813510..2366917a0158 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java @@ -83,6 +83,7 @@ import android.window.IRemoteTransition;  import android.window.IRemoteTransitionFinishedCallback;  import android.window.IWindowContainerToken;  import android.window.RemoteTransition; +import android.window.RemoteTransitionStub;  import android.window.TransitionFilter;  import android.window.TransitionInfo;  import android.window.TransitionRequestInfo; @@ -280,7 +281,7 @@ public class ShellTransitionTests extends ShellTestCase {          final boolean[] remoteCalled = new boolean[]{false};          final WindowContainerTransaction remoteFinishWCT = new WindowContainerTransaction(); -        IRemoteTransition testRemote = new IRemoteTransition.Stub() { +        IRemoteTransition testRemote = new RemoteTransitionStub() {              @Override              public void startAnimation(IBinder token, TransitionInfo info,                      SurfaceControl.Transaction t, @@ -288,16 +289,6 @@ public class ShellTransitionTests extends ShellTestCase {                  remoteCalled[0] = true;                  finishCallback.onTransitionFinished(remoteFinishWCT, null /* sct */);              } - -            @Override -            public void mergeAnimation(IBinder token, TransitionInfo info, -                    SurfaceControl.Transaction t, IBinder mergeTarget, -                    IRemoteTransitionFinishedCallback finishCallback) throws RemoteException { -            } - -            @Override -            public void onTransitionConsumed(IBinder iBinder, boolean b) throws RemoteException { -            }          };          IBinder transitToken = new Binder();          transitions.requestStartTransition(transitToken, @@ -450,7 +441,7 @@ public class ShellTransitionTests extends ShellTestCase {          transitions.replaceDefaultHandlerForTest(mDefaultHandler);          final boolean[] remoteCalled = new boolean[]{false}; -        IRemoteTransition testRemote = new IRemoteTransition.Stub() { +        IRemoteTransition testRemote = new RemoteTransitionStub() {              @Override              public void startAnimation(IBinder token, TransitionInfo info,                      SurfaceControl.Transaction t, @@ -458,16 +449,6 @@ public class ShellTransitionTests extends ShellTestCase {                  remoteCalled[0] = true;                  finishCallback.onTransitionFinished(null /* wct */, null /* sct */);              } - -            @Override -            public void mergeAnimation(IBinder token, TransitionInfo info, -                    SurfaceControl.Transaction t, IBinder mergeTarget, -                    IRemoteTransitionFinishedCallback finishCallback) throws RemoteException { -            } - -            @Override -            public void onTransitionConsumed(IBinder iBinder, boolean b) throws RemoteException { -            }          };          TransitionFilter filter = new TransitionFilter(); @@ -500,7 +481,7 @@ public class ShellTransitionTests extends ShellTestCase {          final boolean[] remoteCalled = new boolean[]{false};          final WindowContainerTransaction remoteFinishWCT = new WindowContainerTransaction(); -        IRemoteTransition testRemote = new IRemoteTransition.Stub() { +        IRemoteTransition testRemote = new RemoteTransitionStub() {              @Override              public void startAnimation(IBinder token, TransitionInfo info,                      SurfaceControl.Transaction t, @@ -508,16 +489,6 @@ public class ShellTransitionTests extends ShellTestCase {                  remoteCalled[0] = true;                  finishCallback.onTransitionFinished(remoteFinishWCT, null /* sct */);              } - -            @Override -            public void mergeAnimation(IBinder token, TransitionInfo info, -                    SurfaceControl.Transaction t, IBinder mergeTarget, -                    IRemoteTransitionFinishedCallback finishCallback) throws RemoteException { -            } - -            @Override -            public void onTransitionConsumed(IBinder iBinder, boolean b) throws RemoteException { -            }          };          final int transitType = TRANSIT_FIRST_CUSTOM + 1; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TestRemoteTransition.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TestRemoteTransition.java index 87330d2dc877..184e8955d08c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TestRemoteTransition.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/TestRemoteTransition.java @@ -20,6 +20,7 @@ import android.os.RemoteException;  import android.view.SurfaceControl;  import android.window.IRemoteTransition;  import android.window.IRemoteTransitionFinishedCallback; +import android.window.RemoteTransitionStub;  import android.window.TransitionInfo;  import android.window.WindowContainerTransaction; @@ -29,7 +30,7 @@ import android.window.WindowContainerTransaction;   * {@link #startAnimation(IBinder, TransitionInfo, SurfaceControl.Transaction,   * IRemoteTransitionFinishedCallback)} being called.   */ -public class TestRemoteTransition extends IRemoteTransition.Stub { +public class TestRemoteTransition extends RemoteTransitionStub {      private boolean mCalled = false;      private boolean mConsumed = false;      final WindowContainerTransaction mRemoteFinishWCT = new WindowContainerTransaction(); @@ -44,12 +45,6 @@ public class TestRemoteTransition extends IRemoteTransition.Stub {      }      @Override -    public void mergeAnimation(IBinder transition, TransitionInfo info, -            SurfaceControl.Transaction t, IBinder mergeTarget, -            IRemoteTransitionFinishedCallback finishCallback) throws RemoteException { -    } - -    @Override      public void onTransitionConsumed(IBinder iBinder, boolean b) throws RemoteException {          mConsumed = true;      } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java index c5e229feaba7..acc0bce5cce9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java @@ -298,6 +298,32 @@ public class UnfoldTransitionHandlerTest {      }      @Test +    public void fold_animationInProgress_finishesTransition() { +        TransitionRequestInfo requestInfo = createUnfoldTransitionRequestInfo(); +        TransitionFinishCallback finishCallback = mock(TransitionFinishCallback.class); + +        // Unfold +        mShellUnfoldProgressProvider.onFoldStateChanged(/* isFolded= */ false); +        mUnfoldTransitionHandler.handleRequest(mTransition, requestInfo); +        mUnfoldTransitionHandler.startAnimation( +                mTransition, +                mock(TransitionInfo.class), +                mock(SurfaceControl.Transaction.class), +                mock(SurfaceControl.Transaction.class), +                finishCallback +        ); + +        // Start animation but don't finish it +        mShellUnfoldProgressProvider.onStateChangeStarted(); +        mShellUnfoldProgressProvider.onStateChangeProgress(0.5f); + +        // Fold +        mShellUnfoldProgressProvider.onFoldStateChanged(/* isFolded= */ true); + +        verify(finishCallback).onTransitionFinished(any()); +    } + +    @Test      public void mergeAnimation_eatsDisplayOnlyTransitions() {          TransitionRequestInfo requestInfo = createUnfoldTransitionRequestInfo();          mUnfoldTransitionHandler.handleRequest(mTransition, requestInfo); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index 228b25ccb1ba..546493746da6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -61,7 +61,6 @@ import android.view.InsetsState;  import android.view.SurfaceControl;  import android.view.SurfaceControlViewHost;  import android.view.View; -import android.view.ViewRootImpl;  import android.view.WindowInsets;  import android.view.WindowManager.LayoutParams;  import android.window.SurfaceSyncGroup; @@ -252,16 +251,14 @@ public class WindowDecorationTests extends ShellTestCase {                          argThat(lp -> lp.height == 64                                  && lp.width == 300                                  && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0)); -        if (ViewRootImpl.CAPTION_ON_SHELL) { -            verify(mMockView).setTaskFocusState(true); -            verify(mMockWindowContainerTransaction).addInsetsSource( -                    eq(taskInfo.token), -                    any(), -                    eq(0 /* index */), -                    eq(WindowInsets.Type.captionBar()), -                    eq(new Rect(100, 300, 400, 364)), -                    any()); -        } +        verify(mMockView).setTaskFocusState(true); +        verify(mMockWindowContainerTransaction).addInsetsSource( +                eq(taskInfo.token), +                any(), +                eq(0 /* index */), +                eq(WindowInsets.Type.captionBar()), +                eq(new Rect(100, 300, 400, 364)), +                any());          verify(mMockSurfaceControlStartT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS);          verify(mMockSurfaceControlFinishT).setCornerRadius(mMockTaskSurface, CORNER_RADIUS); diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp index 9d4b426a6759..34a6bc27b93f 100644 --- a/libs/androidfw/ZipFileRO.cpp +++ b/libs/androidfw/ZipFileRO.cpp @@ -310,3 +310,7 @@ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const      return true;  } + +const char* ZipFileRO::getZipFileName() { +    return mFileName; +} diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h index be1f98f4843d..031d2e8fd48f 100644 --- a/libs/androidfw/include/androidfw/ZipFileRO.h +++ b/libs/androidfw/include/androidfw/ZipFileRO.h @@ -187,6 +187,8 @@ public:       */      bool uncompressEntry(ZipEntryRO entry, int fd) const; +    const char* getZipFileName(); +      ~ZipFileRO();  private: diff --git a/libs/hostgraphics/ANativeWindow.cpp b/libs/hostgraphics/ANativeWindow.cpp new file mode 100644 index 000000000000..fcfaf0235293 --- /dev/null +++ b/libs/hostgraphics/ANativeWindow.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <system/window.h> + +static int32_t query(ANativeWindow* window, int what) { +    int value; +    int res = window->query(window, what, &value); +    return res < 0 ? res : value; +} + +static int64_t query64(ANativeWindow* window, int what) { +    int64_t value; +    int res = window->perform(window, what, &value); +    return res < 0 ? res : value; +} + +int ANativeWindow_setCancelBufferInterceptor(ANativeWindow* window, +                                             ANativeWindow_cancelBufferInterceptor interceptor, +                                             void* data) { +    return window->perform(window, NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR, interceptor, data); +} + +int ANativeWindow_setDequeueBufferInterceptor(ANativeWindow* window, +                                              ANativeWindow_dequeueBufferInterceptor interceptor, +                                              void* data) { +    return window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR, interceptor, data); +} + +int ANativeWindow_setQueueBufferInterceptor(ANativeWindow* window, +                                            ANativeWindow_queueBufferInterceptor interceptor, +                                            void* data) { +    return window->perform(window, NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR, interceptor, data); +} + +int ANativeWindow_setPerformInterceptor(ANativeWindow* window, +                                        ANativeWindow_performInterceptor interceptor, void* data) { +    return window->perform(window, NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR, interceptor, data); +} + +int ANativeWindow_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) { +    return window->dequeueBuffer(window, buffer, fenceFd); +} + +int ANativeWindow_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) { +    return window->cancelBuffer(window, buffer, fenceFd); +} + +int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout) { +    return window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, timeout); +} + +// extern "C", so that it can be used outside libhostgraphics (in host hwui/.../CanvasContext.cpp) +extern "C" void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { +    if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { +        return; +    } +    window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS); +} + +int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window) { +    return query64(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START); +} + +int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window) { +    return query64(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION); +} + +int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window) { +    return query64(window, NATIVE_WINDOW_GET_LAST_QUEUE_DURATION); +} + +int32_t ANativeWindow_getWidth(ANativeWindow* window) { +    return query(window, NATIVE_WINDOW_WIDTH); +} + +int32_t ANativeWindow_getHeight(ANativeWindow* window) { +    return query(window, NATIVE_WINDOW_HEIGHT); +} + +int32_t ANativeWindow_getFormat(ANativeWindow* window) { +    return query(window, NATIVE_WINDOW_FORMAT); +} + +void ANativeWindow_acquire(ANativeWindow* window) { +    // incStrong/decStrong token must be the same, doesn't matter what it is +    window->incStrong((void*)ANativeWindow_acquire); +} + +void ANativeWindow_release(ANativeWindow* window) { +    // incStrong/decStrong token must be the same, doesn't matter what it is +    window->decStrong((void*)ANativeWindow_acquire); +} diff --git a/libs/hostgraphics/Android.bp b/libs/hostgraphics/Android.bp index 4407af68de99..09232b64616d 100644 --- a/libs/hostgraphics/Android.bp +++ b/libs/hostgraphics/Android.bp @@ -17,26 +17,18 @@ cc_library_host_static {      static_libs: [          "libbase",          "libmath", +        "libui-types",          "libutils",      ],      srcs: [ -        ":libui_host_common",          "ADisplay.cpp", +        "ANativeWindow.cpp",          "Fence.cpp",          "HostBufferQueue.cpp",          "PublicFormat.cpp",      ], -    include_dirs: [ -        // Here we override all the headers automatically included with frameworks/native/include. -        // When frameworks/native/include will be removed from the list of automatic includes. -        // We will have to copy necessary headers with a pre-build step (generated headers). -        ".", -        "frameworks/native/libs/arect/include", -        "frameworks/native/libs/ui/include_private", -    ], -      header_libs: [          "libnativebase_headers",          "libnativedisplay_headers", diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 29bb1b9846b4..7439fbc1149c 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -96,6 +96,7 @@ cc_defaults {              ],              cflags: [                  "-Wno-unused-variable", +                "-D__INTRODUCED_IN(n)=",              ],          },      }, @@ -538,7 +539,11 @@ cc_defaults {          "pipeline/skia/RenderNodeDrawable.cpp",          "pipeline/skia/ReorderBarrierDrawables.cpp",          "pipeline/skia/TransformCanvas.cpp", +        "renderstate/RenderState.cpp", +        "renderthread/CanvasContext.cpp", +        "renderthread/DrawFrameTask.cpp",          "renderthread/Frame.cpp", +        "renderthread/RenderProxy.cpp",          "renderthread/RenderTask.cpp",          "renderthread/TimeLord.cpp",          "hwui/AnimatedImageDrawable.cpp", @@ -588,6 +593,7 @@ cc_defaults {          "SkiaCanvas.cpp",          "SkiaInterpolator.cpp",          "Tonemapper.cpp", +        "TreeInfo.cpp",          "VectorDrawable.cpp",      ], @@ -615,16 +621,12 @@ cc_defaults {                  "pipeline/skia/SkiaVulkanPipeline.cpp",                  "pipeline/skia/VkFunctorDrawable.cpp",                  "pipeline/skia/VkInteropFunctorDrawable.cpp", -                "renderstate/RenderState.cpp",                  "renderthread/CacheManager.cpp", -                "renderthread/CanvasContext.cpp", -                "renderthread/DrawFrameTask.cpp",                  "renderthread/EglManager.cpp",                  "renderthread/ReliableSurface.cpp",                  "renderthread/RenderEffectCapabilityQuery.cpp",                  "renderthread/VulkanManager.cpp",                  "renderthread/VulkanSurface.cpp", -                "renderthread/RenderProxy.cpp",                  "renderthread/RenderThread.cpp",                  "renderthread/HintSessionWrapper.cpp",                  "service/GraphicsStatsService.cpp", @@ -636,7 +638,6 @@ cc_defaults {                  "Layer.cpp",                  "ProfileDataContainer.cpp",                  "Readback.cpp", -                "TreeInfo.cpp",                  "WebViewFunctorManager.cpp",                  "protos/graphicsstats.proto",              ], @@ -654,6 +655,8 @@ cc_defaults {              srcs: [                  "platform/host/renderthread/CacheManager.cpp", +                "platform/host/renderthread/HintSessionWrapper.cpp", +                "platform/host/renderthread/ReliableSurface.cpp",                  "platform/host/renderthread/RenderThread.cpp",                  "platform/host/ProfileDataContainer.cpp",                  "platform/host/Readback.cpp", diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index f526a280b113..589abb4d87f4 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -16,18 +16,6 @@  #include "RenderNode.h" -#include "DamageAccumulator.h" -#include "Debug.h" -#include "Properties.h" -#include "TreeInfo.h" -#include "VectorDrawable.h" -#include "private/hwui/WebViewFunctor.h" -#ifdef __ANDROID__ -#include "renderthread/CanvasContext.h" -#else -#include "DamageAccumulator.h" -#include "pipeline/skia/SkiaDisplayList.h" -#endif  #include <SkPathOps.h>  #include <gui/TraceUtils.h>  #include <ui/FatVector.h> @@ -37,6 +25,14 @@  #include <sstream>  #include <string> +#include "DamageAccumulator.h" +#include "Debug.h" +#include "Properties.h" +#include "TreeInfo.h" +#include "VectorDrawable.h" +#include "private/hwui/WebViewFunctor.h" +#include "renderthread/CanvasContext.h" +  #ifdef __ANDROID__  #include "include/gpu/ganesh/SkImageGanesh.h"  #endif @@ -186,7 +182,6 @@ void RenderNode::prepareLayer(TreeInfo& info, uint32_t dirtyMask) {  }  void RenderNode::pushLayerUpdate(TreeInfo& info) { -#ifdef __ANDROID__ // Layoutlib does not support CanvasContext and Layers      LayerType layerType = properties().effectiveLayerType();      // If we are not a layer OR we cannot be rendered (eg, view was detached)      // we need to destroy any Layers we may have had previously @@ -218,7 +213,6 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {      // That might be us, so tell CanvasContext that this layer is in the      // tree and should not be destroyed.      info.canvasContext.markLayerInUse(this); -#endif  }  /** diff --git a/libs/hwui/RootRenderNode.cpp b/libs/hwui/RootRenderNode.cpp index ddbbf58b3071..5174e27ae587 100644 --- a/libs/hwui/RootRenderNode.cpp +++ b/libs/hwui/RootRenderNode.cpp @@ -18,11 +18,12 @@  #ifdef __ANDROID__ // Layoutlib does not support Looper (windows)  #include <utils/Looper.h> +#else +#include "utils/MessageHandler.h"  #endif  namespace android::uirenderer { -#ifdef __ANDROID__ // Layoutlib does not support Looper  class FinishAndInvokeListener : public MessageHandler {  public:      explicit FinishAndInvokeListener(PropertyValuesAnimatorSet* anim) : mAnimator(anim) { @@ -237,9 +238,13 @@ void RootRenderNode::detachVectorDrawableAnimator(PropertyValuesAnimatorSet* ani          // user events, in which case the already posted listener's id will become stale, and          // the onFinished callback will then be ignored.          sp<FinishAndInvokeListener> message = new FinishAndInvokeListener(anim); +#ifdef __ANDROID__  // Layoutlib does not support Looper          auto looper = Looper::getForThread();          LOG_ALWAYS_FATAL_IF(looper == nullptr, "Not on a looper thread?");          looper->sendMessageDelayed(ms2ns(remainingTimeInMs), message, 0); +#else +        message->handleMessage(0); +#endif          anim->clearOneShotListener();      }  } @@ -285,22 +290,5 @@ private:  AnimationContext* ContextFactoryImpl::createAnimationContext(renderthread::TimeLord& clock) {      return new AnimationContextBridge(clock, mRootNode);  } -#else - -void RootRenderNode::prepareTree(TreeInfo& info) { -    info.errorHandler = mErrorHandler.get(); -    info.updateWindowPositions = true; -    RenderNode::prepareTree(info); -    info.updateWindowPositions = false; -    info.errorHandler = nullptr; -} - -void RootRenderNode::attachAnimatingNode(RenderNode* animatingNode) { } - -void RootRenderNode::destroy() { } - -void RootRenderNode::addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) { } - -#endif  }  // namespace android::uirenderer diff --git a/libs/hwui/RootRenderNode.h b/libs/hwui/RootRenderNode.h index 1d3f5a8a51e0..7a5cda7041ed 100644 --- a/libs/hwui/RootRenderNode.h +++ b/libs/hwui/RootRenderNode.h @@ -74,7 +74,6 @@ private:      void detachVectorDrawableAnimator(PropertyValuesAnimatorSet* anim);  }; -#ifdef __ANDROID__ // Layoutlib does not support Animations  class ContextFactoryImpl : public IContextFactory {  public:      explicit ContextFactoryImpl(RootRenderNode* rootNode) : mRootNode(rootNode) {} @@ -84,6 +83,5 @@ public:  private:      RootRenderNode* mRootNode;  }; -#endif  }  // namespace android::uirenderer diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp index efa9b1174a3a..9d16ee86739e 100644 --- a/libs/hwui/WebViewFunctorManager.cpp +++ b/libs/hwui/WebViewFunctorManager.cpp @@ -87,7 +87,7 @@ void WebViewFunctor_release(int functor) {      WebViewFunctorManager::instance().releaseFunctor(functor);  } -void WebViewFunctor_reportRenderingThreads(int functor, const int32_t* thread_ids, size_t size) { +void WebViewFunctor_reportRenderingThreads(int functor, const pid_t* thread_ids, size_t size) {      WebViewFunctorManager::instance().reportRenderingThreads(functor, thread_ids, size);  } @@ -265,8 +265,8 @@ void WebViewFunctor::reparentSurfaceControl(ASurfaceControl* parent) {      funcs.transactionDeleteFunc(transaction);  } -void WebViewFunctor::reportRenderingThreads(const int32_t* thread_ids, size_t size) { -    mRenderingThreads = std::vector<int32_t>(thread_ids, thread_ids + size); +void WebViewFunctor::reportRenderingThreads(const pid_t* thread_ids, size_t size) { +    mRenderingThreads = std::vector<pid_t>(thread_ids, thread_ids + size);  }  WebViewFunctorManager& WebViewFunctorManager::instance() { @@ -355,7 +355,7 @@ void WebViewFunctorManager::destroyFunctor(int functor) {      }  } -void WebViewFunctorManager::reportRenderingThreads(int functor, const int32_t* thread_ids, +void WebViewFunctorManager::reportRenderingThreads(int functor, const pid_t* thread_ids,                                                     size_t size) {      std::lock_guard _lock{mLock};      for (auto& iter : mFunctors) { @@ -366,8 +366,8 @@ void WebViewFunctorManager::reportRenderingThreads(int functor, const int32_t* t      }  } -std::vector<int32_t> WebViewFunctorManager::getRenderingThreadsForActiveFunctors() { -    std::vector<int32_t> renderingThreads; +std::vector<pid_t> WebViewFunctorManager::getRenderingThreadsForActiveFunctors() { +    std::vector<pid_t> renderingThreads;      std::lock_guard _lock{mLock};      for (const auto& iter : mActiveFunctors) {          const auto& functorThreads = iter->getRenderingThreads(); diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h index 2d77dd8d09bc..ec17640f9b5e 100644 --- a/libs/hwui/WebViewFunctorManager.h +++ b/libs/hwui/WebViewFunctorManager.h @@ -17,13 +17,11 @@  #pragma once  #include <private/hwui/WebViewFunctor.h> -#ifdef __ANDROID__ // Layoutlib does not support render thread  #include <renderthread/RenderProxy.h> -#endif -  #include <utils/LightRefBase.h>  #include <utils/Log.h>  #include <utils/StrongPointer.h> +  #include <mutex>  #include <vector> @@ -38,11 +36,7 @@ public:      class Handle : public LightRefBase<Handle> {      public: -        ~Handle() { -#ifdef __ANDROID__ // Layoutlib does not support render thread -            renderthread::RenderProxy::destroyFunctor(id()); -#endif -        } +        ~Handle() { renderthread::RenderProxy::destroyFunctor(id()); }          int id() const { return mReference.id(); } @@ -60,7 +54,7 @@ public:          void onRemovedFromTree() { mReference.onRemovedFromTree(); } -        const std::vector<int32_t>& getRenderingThreads() const { +        const std::vector<pid_t>& getRenderingThreads() const {              return mReference.getRenderingThreads();          } @@ -85,8 +79,8 @@ public:      ASurfaceControl* getSurfaceControl();      void mergeTransaction(ASurfaceTransaction* transaction); -    void reportRenderingThreads(const int32_t* thread_ids, size_t size); -    const std::vector<int32_t>& getRenderingThreads() const { return mRenderingThreads; } +    void reportRenderingThreads(const pid_t* thread_ids, size_t size); +    const std::vector<pid_t>& getRenderingThreads() const { return mRenderingThreads; }      sp<Handle> createHandle() {          LOG_ALWAYS_FATAL_IF(mCreatedHandle); @@ -107,7 +101,7 @@ private:      bool mCreatedHandle = false;      int32_t mParentSurfaceControlGenerationId = 0;      ASurfaceControl* mSurfaceControl = nullptr; -    std::vector<int32_t> mRenderingThreads; +    std::vector<pid_t> mRenderingThreads;  };  class WebViewFunctorManager { @@ -118,8 +112,8 @@ public:      void releaseFunctor(int functor);      void onContextDestroyed();      void destroyFunctor(int functor); -    void reportRenderingThreads(int functor, const int32_t* thread_ids, size_t size); -    std::vector<int32_t> getRenderingThreadsForActiveFunctors(); +    void reportRenderingThreads(int functor, const pid_t* thread_ids, size_t size); +    std::vector<pid_t> getRenderingThreadsForActiveFunctors();      sp<WebViewFunctor::Handle> handleFor(int functor); diff --git a/libs/hwui/apex/LayoutlibLoader.cpp b/libs/hwui/apex/LayoutlibLoader.cpp index 770822a049b7..fd9915a54bb5 100644 --- a/libs/hwui/apex/LayoutlibLoader.cpp +++ b/libs/hwui/apex/LayoutlibLoader.cpp @@ -164,8 +164,10 @@ static vector<string> parseCsv(JNIEnv* env, jstring csvJString) {  } // namespace android  using namespace android; +using namespace android::uirenderer;  void init_android_graphics() { +    Properties::overrideRenderPipelineType(RenderPipelineType::SkiaCpu);      SkGraphics::Init();  } diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp index 0f80c55d0ed0..b01e38d014a9 100644 --- a/libs/hwui/jni/AnimatedImageDrawable.cpp +++ b/libs/hwui/jni/AnimatedImageDrawable.cpp @@ -27,6 +27,8 @@  #include <hwui/ImageDecoder.h>  #ifdef __ANDROID__  #include <utils/Looper.h> +#else +#include "utils/MessageHandler.h"  #endif  #include "ColorFilter.h" @@ -182,23 +184,6 @@ static void AnimatedImageDrawable_nSetRepeatCount(JNIEnv* env, jobject /*clazz*/      drawable->setRepetitionCount(loopCount);  } -#ifndef __ANDROID__ -struct Message { -    Message(int w) {} -}; - -class MessageHandler : public virtual RefBase { -protected: -    virtual ~MessageHandler() override {} - -public: -    /** -     * Handles a message. -     */ -    virtual void handleMessage(const Message& message) = 0; -}; -#endif -  class InvokeListener : public MessageHandler {  public:      InvokeListener(JNIEnv* env, jobject javaObject) { diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp index 9e21f860ce21..d4157008ca46 100644 --- a/libs/hwui/jni/Bitmap.cpp +++ b/libs/hwui/jni/Bitmap.cpp @@ -1,8 +1,14 @@  // #define LOG_NDEBUG 0  #include "Bitmap.h" +#include <android-base/unique_fd.h>  #include <hwui/Bitmap.h>  #include <hwui/Paint.h> +#include <inttypes.h> +#include <renderthread/RenderProxy.h> +#include <string.h> + +#include <memory>  #include "CreateJavaOutputStreamAdaptor.h"  #include "Gainmap.h" @@ -24,16 +30,6 @@  #include "SkTypes.h"  #include "android_nio_utils.h" -#ifdef __ANDROID__ // Layoutlib does not support graphic buffer, parcel or render thread -#include <android-base/unique_fd.h> -#include <renderthread/RenderProxy.h> -#endif - -#include <inttypes.h> -#include <string.h> - -#include <memory> -  #define DEBUG_PARCEL 0  static jclass   gBitmap_class; @@ -1105,11 +1101,9 @@ static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Ha  }  static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) { -#ifdef __ANDROID__ // Layoutlib does not support render thread      LocalScopedBitmap bitmapHandle(bitmapPtr);      if (!bitmapHandle.valid()) return;      android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap()); -#endif  }  static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) { diff --git a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp index 426644ee6a4e..948362c30a31 100644 --- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp +++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp @@ -16,22 +16,19 @@  #include "GraphicsJNI.h" -#ifdef __ANDROID__ // Layoutlib does not support Looper and device properties +#ifdef __ANDROID__  // Layoutlib does not support Looper  #include <utils/Looper.h>  #endif -#include <SkRegion.h> -#include <SkRuntimeEffect.h> - +#include <CanvasProperty.h>  #include <Rect.h>  #include <RenderNode.h> -#include <CanvasProperty.h> +#include <SkRegion.h> +#include <SkRuntimeEffect.h>  #include <hwui/Canvas.h>  #include <hwui/Paint.h>  #include <minikin/Layout.h> -#ifdef __ANDROID__ // Layoutlib does not support RenderThread  #include <renderthread/RenderProxy.h> -#endif  namespace android { @@ -85,11 +82,7 @@ static void android_view_DisplayListCanvas_resetDisplayListCanvas(CRITICAL_JNI_P  }  static jint android_view_DisplayListCanvas_getMaxTextureSize(JNIEnv*, jobject) { -#ifdef __ANDROID__ // Layoutlib does not support RenderProxy (RenderThread)      return android::uirenderer::renderthread::RenderProxy::maxTextureSize(); -#else -    return 4096; -#endif  }  static void android_view_DisplayListCanvas_enableZ(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp index a7d64231da80..6e03bbd0fa16 100644 --- a/libs/hwui/jni/android_graphics_RenderNode.cpp +++ b/libs/hwui/jni/android_graphics_RenderNode.cpp @@ -15,19 +15,17 @@   */  #define ATRACE_TAG ATRACE_TAG_VIEW -#include "GraphicsJNI.h" -  #include <Animator.h>  #include <DamageAccumulator.h>  #include <Matrix.h>  #include <RenderNode.h> -#ifdef __ANDROID__ // Layoutlib does not support CanvasContext -#include <renderthread/CanvasContext.h> -#endif  #include <TreeInfo.h>  #include <effects/StretchEffect.h>  #include <gui/TraceUtils.h>  #include <hwui/Paint.h> +#include <renderthread/CanvasContext.h> + +#include "GraphicsJNI.h"  namespace android { @@ -640,7 +638,6 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,              ATRACE_NAME("Update SurfaceView position"); -#ifdef __ANDROID__ // Layoutlib does not support CanvasContext              JNIEnv* env = jnienv();              // Update the new position synchronously. We cannot defer this to              // a worker pool to process asynchronously because the UI thread @@ -669,7 +666,6 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,                  env->DeleteGlobalRef(mListener);                  mListener = nullptr;              } -#endif          }          virtual void onPositionLost(RenderNode& node, const TreeInfo* info) override { @@ -682,7 +678,6 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,              ATRACE_NAME("SurfaceView position lost");              JNIEnv* env = jnienv(); -#ifdef __ANDROID__ // Layoutlib does not support CanvasContext              // Update the lost position synchronously. We cannot defer this to              // a worker pool to process asynchronously because the UI thread              // may be unblocked by the time a worker thread can process this, @@ -698,7 +693,6 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,                  env->DeleteGlobalRef(mListener);                  mListener = nullptr;              } -#endif          }      private: @@ -750,7 +744,6 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,                  StretchEffectBehavior::Shader) {                  JNIEnv* env = jnienv(); -#ifdef __ANDROID__  // Layoutlib does not support CanvasContext                  SkVector stretchDirection = effect->getStretchDirection();                  jboolean keepListening = env->CallStaticBooleanMethod(                          gPositionListener.clazz, gPositionListener.callApplyStretch, mListener, @@ -762,7 +755,6 @@ static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,                      env->DeleteGlobalRef(mListener);                      mListener = nullptr;                  } -#endif              }          } diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index e0216b680064..36dc933aa7b0 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -15,22 +15,18 @@   */  #include "SkiaDisplayList.h" -#include "FunctorDrawable.h" +#include <SkImagePriv.h> +#include <SkPathOps.h> + +// clang-format off +#include "FunctorDrawable.h" // Must be included before DumpOpsCanvas.h  #include "DumpOpsCanvas.h" -#ifdef __ANDROID__ // Layoutlib does not support SkiaPipeline +// clang-format on  #include "SkiaPipeline.h" -#else -#include "DamageAccumulator.h" -#endif  #include "TreeInfo.h"  #include "VectorDrawable.h" -#ifdef __ANDROID__  #include "renderthread/CanvasContext.h" -#endif - -#include <SkImagePriv.h> -#include <SkPathOps.h>  namespace android {  namespace uirenderer { @@ -101,7 +97,6 @@ bool SkiaDisplayList::prepareListAndChildren(      // If the prepare tree is triggered by the UI thread and no previous call to      // pinImages has failed then we must pin all mutable images in the GPU cache      // until the next UI thread draw. -#ifdef __ANDROID__ // Layoutlib does not support CanvasContext      if (info.prepareTextures && !info.canvasContext.pinImages(mMutableImages)) {          // In the event that pinning failed we prevent future pinImage calls for the          // remainder of this tree traversal and also unpin any currently pinned images @@ -110,11 +105,11 @@ bool SkiaDisplayList::prepareListAndChildren(          info.canvasContext.unpinImages();      } +#ifdef __ANDROID__      auto grContext = info.canvasContext.getGrContext();      for (const auto& bufferData : mMeshBufferData) {          bufferData->updateBuffers(grContext);      } -  #endif      bool hasBackwardProjectedNodesHere = false; diff --git a/libs/hwui/platform/host/WebViewFunctorManager.cpp b/libs/hwui/platform/host/WebViewFunctorManager.cpp index 1d16655bf73c..4ba206b41b39 100644 --- a/libs/hwui/platform/host/WebViewFunctorManager.cpp +++ b/libs/hwui/platform/host/WebViewFunctorManager.cpp @@ -50,6 +50,8 @@ ASurfaceControl* WebViewFunctor::getSurfaceControl() {  void WebViewFunctor::mergeTransaction(ASurfaceTransaction* transaction) {} +void WebViewFunctor::reportRenderingThreads(const pid_t* thread_ids, size_t size) {} +  void WebViewFunctor::reparentSurfaceControl(ASurfaceControl* parent) {}  WebViewFunctorManager& WebViewFunctorManager::instance() { @@ -68,6 +70,13 @@ void WebViewFunctorManager::onContextDestroyed() {}  void WebViewFunctorManager::destroyFunctor(int functor) {} +void WebViewFunctorManager::reportRenderingThreads(int functor, const pid_t* thread_ids, +                                                   size_t size) {} + +std::vector<pid_t> WebViewFunctorManager::getRenderingThreadsForActiveFunctors() { +    return {}; +} +  sp<WebViewFunctor::Handle> WebViewFunctorManager::handleFor(int functor) {      return nullptr;  } diff --git a/libs/hwui/platform/host/renderthread/HintSessionWrapper.cpp b/libs/hwui/platform/host/renderthread/HintSessionWrapper.cpp new file mode 100644 index 000000000000..b1b1d5830834 --- /dev/null +++ b/libs/hwui/platform/host/renderthread/HintSessionWrapper.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "renderthread/HintSessionWrapper.h" + +namespace android { +namespace uirenderer { +namespace renderthread { + +void HintSessionWrapper::HintSessionBinding::init() {} + +HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId) +        : mUiThreadId(uiThreadId) +        , mRenderThreadId(renderThreadId) +        , mBinding(std::make_shared<HintSessionBinding>()) {} + +HintSessionWrapper::~HintSessionWrapper() {} + +void HintSessionWrapper::destroy() {} + +bool HintSessionWrapper::init() { +    return false; +} + +void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) {} + +void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {} + +void HintSessionWrapper::sendLoadResetHint() {} + +void HintSessionWrapper::sendLoadIncreaseHint() {} + +bool HintSessionWrapper::alive() { +    return false; +} + +nsecs_t HintSessionWrapper::getLastUpdate() { +    return -1; +} + +void HintSessionWrapper::delayedDestroy(RenderThread& rt, nsecs_t delay, +                                        std::shared_ptr<HintSessionWrapper> wrapperPtr) {} + +void HintSessionWrapper::setActiveFunctorThreads(std::vector<pid_t> threadIds) {} + +} /* namespace renderthread */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/platform/host/renderthread/ReliableSurface.cpp b/libs/hwui/platform/host/renderthread/ReliableSurface.cpp new file mode 100644 index 000000000000..2deaaf3b909c --- /dev/null +++ b/libs/hwui/platform/host/renderthread/ReliableSurface.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "renderthread/ReliableSurface.h" + +#include <log/log_main.h> +#include <system/window.h> + +namespace android::uirenderer::renderthread { + +ReliableSurface::ReliableSurface(ANativeWindow* window) : mWindow(window) { +    LOG_ALWAYS_FATAL_IF(!mWindow, "Error, unable to wrap a nullptr"); +    ANativeWindow_acquire(mWindow); +} + +ReliableSurface::~ReliableSurface() { +    ANativeWindow_release(mWindow); +} + +void ReliableSurface::init() {} + +int ReliableSurface::reserveNext() { +    return OK; +} + +};  // namespace android::uirenderer::renderthread diff --git a/libs/hwui/platform/host/renderthread/RenderThread.cpp b/libs/hwui/platform/host/renderthread/RenderThread.cpp index 6f08b5979772..f9d0f4704e08 100644 --- a/libs/hwui/platform/host/renderthread/RenderThread.cpp +++ b/libs/hwui/platform/host/renderthread/RenderThread.cpp @@ -17,6 +17,7 @@  #include "renderthread/RenderThread.h"  #include "Readback.h" +#include "renderstate/RenderState.h"  #include "renderthread/VulkanManager.h"  namespace android { @@ -66,6 +67,7 @@ RenderThread::RenderThread()  RenderThread::~RenderThread() {}  void RenderThread::initThreadLocals() { +    mRenderState = new RenderState(*this);      mCacheManager = new CacheManager(*this);  } diff --git a/libs/hwui/platform/host/utils/MessageHandler.h b/libs/hwui/platform/host/utils/MessageHandler.h new file mode 100644 index 000000000000..51ee48e0c6d2 --- /dev/null +++ b/libs/hwui/platform/host/utils/MessageHandler.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <utils/RefBase.h> + +struct Message { +    Message(int w) {} +}; + +class MessageHandler : public virtual android::RefBase { +protected: +    virtual ~MessageHandler() override {} + +public: +    /** +     * Handles a message. +     */ +    virtual void handleMessage(const Message& message) = 0; +}; diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h index e08d32a7735c..60657cf91123 100644 --- a/libs/hwui/renderstate/RenderState.h +++ b/libs/hwui/renderstate/RenderState.h @@ -16,11 +16,13 @@  #ifndef RENDERSTATE_H  #define RENDERSTATE_H -#include "utils/Macros.h" - +#include <pthread.h>  #include <utils/RefBase.h> +  #include <set> +#include "utils/Macros.h" +  namespace android {  namespace uirenderer { diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 22de2f29792d..66e089627a7b 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -35,6 +35,7 @@  #include "Properties.h"  #include "RenderThread.h"  #include "hwui/Canvas.h" +#include "pipeline/skia/SkiaCpuPipeline.h"  #include "pipeline/skia/SkiaGpuPipeline.h"  #include "pipeline/skia/SkiaOpenGLPipeline.h"  #include "pipeline/skia/SkiaVulkanPipeline.h" @@ -72,7 +73,7 @@ CanvasContext* ScopedActiveContext::sActiveContext = nullptr;  CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,                                       RenderNode* rootRenderNode, IContextFactory* contextFactory, -                                     int32_t uiThreadId, int32_t renderThreadId) { +                                     pid_t uiThreadId, pid_t renderThreadId) {      auto renderType = Properties::getRenderPipelineType();      switch (renderType) { @@ -84,6 +85,12 @@ CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,              return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,                                       std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread),                                       uiThreadId, renderThreadId); +#ifndef __ANDROID__ +        case RenderPipelineType::SkiaCpu: +            return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, +                                     std::make_unique<skiapipeline::SkiaCpuPipeline>(thread), +                                     uiThreadId, renderThreadId); +#endif          default:              LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);              break; @@ -182,6 +189,7 @@ static void setBufferCount(ANativeWindow* window) {  }  void CanvasContext::setHardwareBuffer(AHardwareBuffer* buffer) { +#ifdef __ANDROID__      if (mHardwareBuffer) {          AHardwareBuffer_release(mHardwareBuffer);          mHardwareBuffer = nullptr; @@ -192,6 +200,7 @@ void CanvasContext::setHardwareBuffer(AHardwareBuffer* buffer) {          mHardwareBuffer = buffer;      }      mRenderPipeline->setHardwareBuffer(mHardwareBuffer); +#endif  }  void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) { @@ -561,6 +570,7 @@ Frame CanvasContext::getFrame() {  }  void CanvasContext::draw(bool solelyTextureViewUpdates) { +#ifdef __ANDROID__      if (auto grContext = getGrContext()) {          if (grContext->abandoned()) {              if (grContext->isDeviceLost()) { @@ -571,6 +581,7 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) {              return;          }      } +#endif      SkRect dirty;      mDamageAccumulator.finish(&dirty); @@ -594,11 +605,13 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) {      if (skippedFrameReason) {          mCurrentFrameInfo->setSkippedFrameReason(*skippedFrameReason); +#ifdef __ANDROID__          if (auto grContext = getGrContext()) {              // Submit to ensure that any texture uploads complete and Skia can              // free its staging buffers.              grContext->flushAndSubmit();          } +#endif          // Notify the callbacks, even if there's nothing to draw so they aren't waiting          // indefinitely diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 1b333bfccbf1..826d00e1f32f 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -140,12 +140,14 @@ void DrawFrameTask::run() {      if (CC_LIKELY(canDrawThisFrame)) {          context->draw(solelyTextureViewUpdates);      } else { +#ifdef __ANDROID__          // Do a flush in case syncFrameState performed any texture uploads. Since we skipped          // the draw() call, those uploads (or deletes) will end up sitting in the queue.          // Do them now          if (GrDirectContext* grContext = mRenderThread->getGrContext()) {              grContext->flushAndSubmit();          } +#endif          // wait on fences so tasks don't overlap next frame          context->waitOnFences();      } @@ -176,11 +178,13 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) {      bool canDraw = mContext->makeCurrent();      mContext->unpinImages(); +#ifdef __ANDROID__      for (size_t i = 0; i < mLayers.size(); i++) {          if (mLayers[i]) {              mLayers[i]->apply();          }      } +#endif      mLayers.clear();      mContext->setContentDrawBounds(mContentDrawBounds); diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h index 595964741049..d6a4d50d3327 100644 --- a/libs/hwui/renderthread/ReliableSurface.h +++ b/libs/hwui/renderthread/ReliableSurface.h @@ -21,7 +21,9 @@  #include <apex/window.h>  #include <utils/Errors.h>  #include <utils/Macros.h> +#ifdef __ANDROID__  #include <utils/NdkUtils.h> +#endif  #include <utils/StrongPointer.h>  #include <memory> @@ -62,9 +64,11 @@ private:      mutable std::mutex mMutex;      uint64_t mUsage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER; +#ifdef __ANDROID__      AHardwareBuffer_Format mFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;      UniqueAHardwareBuffer mScratchBuffer;      ANativeWindowBuffer* mReservedBuffer = nullptr; +#endif      base::unique_fd mReservedFenceFd;      bool mHasDequeuedBuffer = false;      int mBufferQueueState = OK; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index eab36050896f..715153b5083d 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -42,7 +42,11 @@ namespace renderthread {  RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode,                           IContextFactory* contextFactory)          : mRenderThread(RenderThread::getInstance()), mContext(nullptr) { +#ifdef __ANDROID__      pid_t uiThreadId = pthread_gettid_np(pthread_self()); +#else +    pid_t uiThreadId = 0; +#endif      pid_t renderThreadId = getRenderThreadTid();      mContext = mRenderThread.queue().runSync([=, this]() -> CanvasContext* {          CanvasContext* context = CanvasContext::create(mRenderThread, translucent, rootRenderNode, @@ -90,6 +94,7 @@ void RenderProxy::setName(const char* name) {  }  void RenderProxy::setHardwareBuffer(AHardwareBuffer* buffer) { +#ifdef __ANDROID__      if (buffer) {          AHardwareBuffer_acquire(buffer);      } @@ -99,6 +104,7 @@ void RenderProxy::setHardwareBuffer(AHardwareBuffer* buffer) {              AHardwareBuffer_release(hardwareBuffer);          }      }); +#endif  }  void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) { @@ -216,7 +222,9 @@ void RenderProxy::cancelLayerUpdate(DeferredLayerUpdater* layer) {  }  void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) { +#ifdef __ANDROID__      return mRenderThread.queue().runSync([&]() { layer->detachSurfaceTexture(); }); +#endif  }  void RenderProxy::destroyHardwareResources() { @@ -324,11 +332,13 @@ void RenderProxy::dumpGraphicsMemory(int fd, bool includeProfileData, bool reset              }          });      } +#ifdef __ANDROID__      if (!Properties::isolatedProcess) {          std::string grallocInfo;          GraphicBufferAllocator::getInstance().dump(grallocInfo);          dprintf(fd, "%s\n", grallocInfo.c_str());      } +#endif  }  void RenderProxy::getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage) { @@ -352,7 +362,11 @@ void RenderProxy::rotateProcessStatsBuffer() {  }  int RenderProxy::getRenderThreadTid() { +#ifdef __ANDROID__      return mRenderThread.getTid(); +#else +    return 0; +#endif  }  void RenderProxy::addRenderNode(RenderNode* node, bool placeFront) { @@ -461,7 +475,7 @@ void RenderProxy::prepareToDraw(Bitmap& bitmap) {  int RenderProxy::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) {      ATRACE_NAME("HardwareBitmap readback");      RenderThread& thread = RenderThread::getInstance(); -    if (gettid() == thread.getTid()) { +    if (RenderThread::isCurrent()) {          // TODO: fix everything that hits this. We should never be triggering a readback ourselves.          return (int)thread.readback().copyHWBitmapInto(hwBitmap, bitmap);      } else { @@ -472,7 +486,7 @@ int RenderProxy::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) {  int RenderProxy::copyImageInto(const sk_sp<SkImage>& image, SkBitmap* bitmap) {      RenderThread& thread = RenderThread::getInstance(); -    if (gettid() == thread.getTid()) { +    if (RenderThread::isCurrent()) {          // TODO: fix everything that hits this. We should never be triggering a readback ourselves.          return (int)thread.readback().copyImageInto(image, bitmap);      } else { diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java index 2a0648d87c85..7ed67dcde913 100644 --- a/media/java/android/media/projection/MediaProjectionManager.java +++ b/media/java/android/media/projection/MediaProjectionManager.java @@ -23,6 +23,9 @@ import android.annotation.SystemService;  import android.annotation.TestApi;  import android.app.Activity;  import android.app.ActivityOptions.LaunchCookie; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; +import android.compat.annotation.Overridable;  import android.content.ComponentName;  import android.content.Context;  import android.content.Intent; @@ -66,6 +69,18 @@ public final class MediaProjectionManager {      private static final String TAG = "MediaProjectionManager";      /** +     * This change id ensures that users are presented with a choice of capturing a single app +     * or the entire screen when initiating a MediaProjection session, overriding the usage of +     * MediaProjectionConfig#createConfigForDefaultDisplay. +     * +     * @hide +     */ +    @ChangeId +    @Overridable +    @Disabled +    public static final long OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION = 316897322L; + +    /**       * Intent extra to customize the permission dialog based on the host app's preferences.       * @hide       */ diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl index 207ccbee0b50..871e9ab87299 100644 --- a/media/java/android/media/session/ISessionManager.aidl +++ b/media/java/android/media/session/ISessionManager.aidl @@ -80,4 +80,7 @@ interface ISessionManager {      boolean hasCustomMediaSessionPolicyProvider(String componentName);      int getSessionPolicies(in MediaSession.Token token);      void setSessionPolicies(in MediaSession.Token token, int policies); + +    // For testing of temporarily engaged sessions. +    void expireTempEngagedSessions();  } diff --git a/media/java/android/media/session/ParcelableListBinder.java b/media/java/android/media/session/ParcelableListBinder.java index bbf1e0889b68..d78828462b1e 100644 --- a/media/java/android/media/session/ParcelableListBinder.java +++ b/media/java/android/media/session/ParcelableListBinder.java @@ -45,6 +45,7 @@ public class ParcelableListBinder<T extends Parcelable> extends Binder {      private static final int END_OF_PARCEL = 0;      private static final int ITEM_CONTINUED = 1; +    private final Class<T> mListElementsClass;      private final Consumer<List<T>> mConsumer;      private final Object mLock = new Object(); @@ -61,9 +62,11 @@ public class ParcelableListBinder<T extends Parcelable> extends Binder {      /**       * Creates an instance.       * +     * @param listElementsClass the class of the list elements.       * @param consumer a consumer that consumes the list received       */ -    public ParcelableListBinder(@NonNull Consumer<List<T>> consumer) { +    public ParcelableListBinder(Class<T> listElementsClass, @NonNull Consumer<List<T>> consumer) { +        mListElementsClass = listElementsClass;          mConsumer = consumer;      } @@ -83,7 +86,13 @@ public class ParcelableListBinder<T extends Parcelable> extends Binder {                  mCount = data.readInt();              }              while (i < mCount && data.readInt() != END_OF_PARCEL) { -                mList.add(data.readParcelable(null)); +                Object object = data.readParcelable(null); +                if (mListElementsClass.isAssignableFrom(object.getClass())) { +                    // Checking list items are of compaitible types to validate against malicious +                    // apps calling it directly via reflection with non compilable items. +                    // See b/317048338 for more details +                    mList.add((T) object); +                }                  i++;              }              if (i >= mCount) { diff --git a/nfc/Android.bp b/nfc/Android.bp index c186804d2006..13ac2311bde3 100644 --- a/nfc/Android.bp +++ b/nfc/Android.bp @@ -66,6 +66,7 @@ java_sdk_library {      ],      impl_library_visibility: [          "//frameworks/base:__subpackages__", +        "//cts/hostsidetests/multidevices/nfc:__subpackages__",          "//cts/tests/tests/nfc",          "//packages/apps/Nfc:__subpackages__",      ], diff --git a/packages/BackupRestoreConfirmation/AndroidManifest.xml b/packages/BackupRestoreConfirmation/AndroidManifest.xml index e67b3be43ea1..44aa1b1b8747 100644 --- a/packages/BackupRestoreConfirmation/AndroidManifest.xml +++ b/packages/BackupRestoreConfirmation/AndroidManifest.xml @@ -26,7 +26,8 @@                   android:allowBackup="false"                   android:permission="android.permission.CONFIRM_FULL_BACKUP" > -        <activity android:name=".BackupRestoreConfirmation"  +        <activity android:name=".BackupRestoreConfirmation" +                  android:theme="@style/OptOutEdgeToEdgeEnforcement"                    android:title=""                    android:windowSoftInputMode="stateAlwaysHidden"                    android:excludeFromRecents="true" diff --git a/packages/BackupRestoreConfirmation/res/values/styles.xml b/packages/BackupRestoreConfirmation/res/values/styles.xml new file mode 100644 index 000000000000..ce54568ed6d6 --- /dev/null +++ b/packages/BackupRestoreConfirmation/res/values/styles.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + +     Licensed under the Apache License, Version 2.0 (the "License"); +     you may not use this file except in compliance with the License. +     You may obtain a copy of the License at + +          http://www.apache.org/licenses/LICENSE-2.0 + +     Unless required by applicable law or agreed to in writing, software +     distributed under the License is distributed on an "AS IS" BASIS, +     WITHOUT 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"> +    <!-- +        TODO(b/309578419): Make activities handle insets properly and then remove this. +    --> +    <style name="OptOutEdgeToEdgeEnforcement"> +        <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> +    </style> +</resources> diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml index 183965e6723a..d2df0e4f5d0d 100644 --- a/packages/CompanionDeviceManager/res/values-ar/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml @@ -27,10 +27,10 @@      <string name="summary_glasses" msgid="2872254734959842579">"سيتم السماح لهذا التطبيق بالوصول إلى هذه الأذونات على \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>      <string name="title_app_streaming" msgid="2270331024626446950">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بالوصول إلى هذه المعلومات من هاتفك"</string>      <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"هل تريد منح <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> إذنًا لبث التطبيقات المُثبَّتة على هاتفك؟"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"سيتمكّن \"%1$s\" من الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله على الهاتف، بما في ذلك الملفات الصوتية والصور وكلمات المرور والرسائل.<br/><br/>سيتمكّن \"%1$s\" من بث التطبيقات إلى أنّ توقف إمكانية استخدام هذا الإذن."</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"سيتمكّن %1$s من الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله على الهاتف، بما في ذلك الملفات الصوتية والصور وكلمات المرور والرسائل.<br/><br/>سيتمكّن %1$s من بث التطبيقات إلى أن توقف إمكانية استخدام هذا الإذن."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"الخدمات التي تعمل بين الأجهزة"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"يطلب تطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" لبثّ محتوى التطبيقات بين أجهزتك."</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"يطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" لعرض التطبيقات وبثها بين أجهزتك"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"تطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> لعرض التطبيقات وبثها بين أجهزتك"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"السماح لتطبيق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> بالوصول إلى هذه المعلومات من هاتفك"</string> @@ -39,7 +39,7 @@      <string name="helper_summary_computer" msgid="8774832742608187072">"يطلب تطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" للوصول إلى الصور والوسائط والإشعارات في هاتفك."</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"هل تريد السماح للتطبيق <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> باتّخاذ هذا الإجراء؟"</string>      <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"هل تريد منح <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> إذنًا لبث التطبيقات والوصول إلى ميزات النظام على هاتفك؟"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"سيتمكّن \"%1$s\" من الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله على هاتفك، بما في ذلك الملفات الصوتية والصور ومعلومات الدفع وكلمات المرور والرسائل.<br/><br/>سيتمكّن \"%1$s\" من بث التطبيقات والوصول إلى ميزات النظام إلى أنّ توقف إمكانية استخدام هذا الإذن."</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"سيتمكّن %1$s من الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله على هاتفك، بما في ذلك الملفات الصوتية والصور ومعلومات الدفع وكلمات المرور والرسائل.<br/><br/>سيتمكّن %1$s من بث التطبيقات والوصول إلى ميزات النظام إلى أن توقف إمكانية استخدام هذا الإذن."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"يطلب \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الحصول على إذن نيابةً عن \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" لبثّ التطبيقات وميزات النظام الأخرى إلى أجهزتك المجاورة."</string>      <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string>      <string name="summary_generic" msgid="1761976003668044801">"سيتمكّن هذا التطبيق من مزامنة المعلومات، مثل اسم المتصل، بين هاتفك والجهاز المحدّد."</string> diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml index 4fb9ceed1c6c..2316baadf480 100644 --- a/packages/CompanionDeviceManager/res/values-bg/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml @@ -30,7 +30,7 @@      <string name="summary_app_streaming" msgid="295548145144086753">"%1$s ще има достъп до всичко, което се показва или възпроизвежда на телефона, включително аудиосъдържание, снимки, пароли и съобщения.<br/><br/>%1$s ще може да предава поточно приложения, докато не премахнете това разрешение."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуги за различни устройства"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> да предава поточно приложения между устройствата ви"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> да показва и да предава поточно приложения между устройствата ви"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ иска разрешение от името на <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> да показва и да предава поточно приложения между устройствата ви"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"Разрешете на <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> да осъществява достъп до тази информация от телефона ви"</string> diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml index 231d395e2a8e..247d017f4b16 100644 --- a/packages/CompanionDeviceManager/res/values-bs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml @@ -26,7 +26,7 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string>      <string name="summary_glasses" msgid="2872254734959842579">"Aplikaciji će biti dozvoljen pristup ovim odobrenjima na uređaju <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pristupa ovim informacijama s telefona"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Dozvoliti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da prenosi aplikacije telefona?"</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Dozvoliti uređaju <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da prenosi aplikacije telefona?"</string>      <string name="summary_app_streaming" msgid="295548145144086753">"%1$s će imati pristup svemu što je vidljivo ili se reproducira na telefonu, uključujući zvuk, fotografije, lozinke i poruke.<br/><br/>%1$s će moći prenositi aplikacije dok ne uklonite pristup ovom odobrenju."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluga na više uređaja"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> zahtijeva odobrenje da prenosi aplikacije između vaših uređaja"</string> @@ -59,7 +59,7 @@      <string name="permission_microphone" msgid="2152206421428732949">"Mikrofon"</string>      <string name="permission_call_logs" msgid="5546761417694586041">"Zapisnici poziva"</string>      <string name="permission_nearby_devices" msgid="7530973297737123481">"Uređaji u blizini"</string> -    <string name="permission_media_routing_control" msgid="5498639511586715253">"Promijeni izlaz med. sadržaja"</string> +    <string name="permission_media_routing_control" msgid="5498639511586715253">"Promjena medijskog izlaza"</string>      <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string>      <string name="permission_notifications" msgid="4099418516590632909">"Obavještenja"</string>      <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacije"</string> diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml index 94510e3d4ca7..3acd1798f990 100644 --- a/packages/CompanionDeviceManager/res/values-cs/strings.xml +++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml @@ -27,7 +27,7 @@      <string name="summary_glasses" msgid="2872254734959842579">"Tato aplikace bude mít ve vašem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> povolený přístup k těmto oprávněním"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"Povolte aplikaci <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> přístup k těmto informacím z vašeho telefonu"</string>      <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Povolit zařízení <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamovat aplikace telefonu?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"Aplikace %1$s bude mít přístup ke všemu, co zobrazíte nebo přehrajete na telefonu, včetně zvuku, fotek, hesel a zpráv.<br/><br/>%1$s bude moci streamovat aplikace, dokud přístup k tomuto oprávnění neodeberete."</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s bude mít přístup ke všemu, co na telefonu zobrazíte nebo přehrajete, včetně zvuku, fotek, hesel a zpráv.<br/><br/>%1$s bude moci streamovat aplikace, dokud přístup k tomuto oprávnění neodeberete."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pro více zařízení"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> oprávnění ke streamování aplikací mezi zařízeními"</string>      <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> oprávnění k zobrazení a streamování obsahu mezi zařízeními"</string> @@ -39,7 +39,7 @@      <string name="helper_summary_computer" msgid="8774832742608187072">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> oprávnění k přístupu k fotkám, médiím a oznámením v telefonu"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Povolit zařízení <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> podniknout tuto akci?"</string>      <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Povolit zařízení <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> streamovat aplikace a systémové funkce telefonu?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"Aplikace %1$s bude mít přístup ke všemu, co zobrazíte nebo přehrajete na telefonu, včetně zvuku, fotek, platebních údajů, hesel a zpráv.<br/><br/>%1$s bude moci streamovat aplikace a systémové funkce, dokud přístup k tomuto oprávnění neodeberete."</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s bude mít přístup ke všemu, co na telefonu zobrazíte nebo přehrajete, včetně zvuku, fotek, platebních údajů, hesel a zpráv.<br/><br/>%1$s bude moci streamovat aplikace a systémové funkce, dokud přístup k tomuto oprávnění neodeberete."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> žádá jménem vašeho zařízení <xliff:g id="DEVICE_NAME">%2$s</xliff:g> o oprávnění streamovat aplikace a další systémové funkce do zařízení v okolí"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string>      <string name="summary_generic" msgid="1761976003668044801">"Tato aplikace bude moci synchronizovat údaje, jako je jméno volajícího, mezi vaším telefonem a vybraným zařízením"</string> diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml index 6b38bff17b4c..9d0846c554c0 100644 --- a/packages/CompanionDeviceManager/res/values-da/strings.xml +++ b/packages/CompanionDeviceManager/res/values-da/strings.xml @@ -28,7 +28,7 @@      <string name="title_app_streaming" msgid="2270331024626446950">"Giv <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adgang til disse oplysninger fra din telefon"</string>      <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Vil du give <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilladelse til at streame din telefons apps?"</string>      <string name="summary_app_streaming" msgid="295548145144086753">"%1$s har adgang til alt, der er synligt eller afspilles på telefonen, herunder lyd, billeder, adgangskoder og beskeder.<br/><br/>%1$s kan streame apps, indtil du fjerner adgangen til denne tilladelse."</string> -    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester, som kan tilsluttes en anden enhed"</string> +    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester til flere enheder"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> til at streame apps mellem dine enheder"</string>      <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> til at vise og streame apps mellem dine enheder"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string> diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml index 65e923c67857..3f730fc82b30 100644 --- a/packages/CompanionDeviceManager/res/values-de/strings.xml +++ b/packages/CompanionDeviceManager/res/values-de/strings.xml @@ -26,11 +26,11 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"Gerät"</string>      <string name="summary_glasses" msgid="2872254734959842579">"Diese App darf dann auf diese Berechtigungen auf deinem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> zugreifen:"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Zugriff auf diese Informationen von deinem Smartphone gewähren"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> erlauben, die Apps auf deinem Smartphone zu streamen?"</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Zulassen, dass <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> die Apps auf deinem Smartphone streamt?"</string>      <string name="summary_app_streaming" msgid="295548145144086753">"%1$s hat dann Zugriff auf alle Inhalte, die auf deinem Smartphone sichtbar sind oder abgespielt werden, einschließlich Audio, Fotos, Passwörter und Nachrichten.<br/><br/>%1$s kann so lange Apps streamen, bis du diese Berechtigung entfernst."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Geräteübergreifende Dienste"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> um die Berechtigung zum Streamen von Apps zwischen deinen Geräten"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> um die Berechtigung zum Anzeigen und Streamen von Apps zwischen deinen Geräten"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> um die Berechtigung, gegenseitig das Anzeigen und Streamen von Apps zu erlauben"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> Zugriff auf diese Informationen von deinem Smartphone gewähren"</string> @@ -38,8 +38,8 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-Dienste"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen deines <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> um die Berechtigung zum Zugriff auf die Fotos, Medien und Benachrichtigungen deines Smartphones"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Darf das Gerät <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> diese Aktion ausführen?"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> erlauben, die Apps und Systemfunktionen auf deinem Smartphone zu streamen?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s hat dann Zugriff auf alle Inhalte, die auf deinem Smartphone sichtbar sind oder abgespielt werden, einschließlich Audio, Fotos, Zahlungsinformationen, Passwörter und Nachrichten.<br/><br/>%1$s kann so lange Apps und Systemfunktionen streamen, bis du diese Berechtigung entfernst."</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Zulassen, dass <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> die Apps und Systemfunktionen auf deinem Smartphone streamt?"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s hat dann Zugriff auf alle Inhalte, die auf deinem Smartphone sichtbar sind oder abgespielt werden, einschließlich Audio, Fotos, Zahlungsinformationen, Passwörter und Nachrichten.<br/><br/>%1$s kann so lange Apps und Systemfunktionen streamen, bis du diese Berechtigung entfernst."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein Gerät (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) um die Berechtigung, Apps und andere Systemfunktionen auf Geräte in der Nähe zu streamen"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>      <string name="summary_generic" msgid="1761976003668044801">"Diese App kann dann Daten wie den Namen eines Anrufers zwischen deinem Smartphone und dem ausgewählten Gerät synchronisieren"</string> diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml index c0d1888791e4..15d97af5ce0d 100644 --- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml +++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml @@ -59,7 +59,7 @@      <string name="permission_microphone" msgid="2152206421428732949">"Micrófono"</string>      <string name="permission_call_logs" msgid="5546761417694586041">"Registros de llamadas"</string>      <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos cercanos"</string> -    <string name="permission_media_routing_control" msgid="5498639511586715253">"Cambia la salida multimedia"</string> +    <string name="permission_media_routing_control" msgid="5498639511586715253">"Cambiar la salida multimedia"</string>      <string name="permission_storage" msgid="6831099350839392343">"Fotos y contenido multimedia"</string>      <string name="permission_notifications" msgid="4099418516590632909">"Notificaciones"</string>      <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string> diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml index b7a9ff632fba..e02cb04a6489 100644 --- a/packages/CompanionDeviceManager/res/values-et/strings.xml +++ b/packages/CompanionDeviceManager/res/values-et/strings.xml @@ -26,21 +26,21 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"seade"</string>      <string name="summary_glasses" msgid="2872254734959842579">"Sellele rakendusele antakse need load teie seadmes <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pääseda teie telefonis juurde sellele teabele"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Kas lubate rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> oma telefoni rakendusi voogesitada?"</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Kas lubate seadmel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> oma telefoni rakendusi voogesitada?"</string>      <string name="summary_app_streaming" msgid="295548145144086753">"%1$s saab juurdepääsu kõigele, mis on telefonis nähtaval või esitatav, sh helile, fotodele, paroolidele ja sõnumitele.<br/><br/>%1$s saab rakendusi voogesitada kuni eemaldate juurdepääsu sellele loale."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Seadmeülesed teenused"</string> -    <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nimel luba teie seadmete vahel rakendusi voogesitada"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nimel luba teie seadmete vahel rakendusi kuvada ja voogesitada"</string> +    <string name="helper_summary_app_streaming" msgid="2396773196949578425">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nimel luba teie seadmete vahel rakendusi voogesitada"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nimel luba teie seadmete vahel rakendusi kuvada ja voogesitada"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"Lubage rakendusel <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> pääseda teie telefonis juurde sellele teabele"</string>      <string name="summary_computer" msgid="3798467601598297062"></string>      <string name="helper_title_computer" msgid="4671071173916176037">"Google Play teenused"</string> -    <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nimel luba pääseda juurde telefoni fotodele, meediale ja märguannetele"</string> +    <string name="helper_summary_computer" msgid="8774832742608187072">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> nimel luba pääseda juurde telefoni fotodele, meediale ja märguannetele"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Kas lubada seadmel <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> teha seda toimingut?"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Kas lubate rakendusel <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> oma telefoni rakenduste ja süsteemifunktsioonidel voogesitada?"</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Kas lubate seadmel <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> oma telefoni rakendusi ja süsteemifunktsioone voogesitada?"</string>      <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s saab juurdepääsu kõigele, mis on teie telefonis nähtav või esitatav, sh heli, fotod, makseteave, paroolid ja sõnumid.<br/><br/>%1$s saab voogesitada rakendusi ja süsteemifunktsioone, kuni eemaldate juurdepääsu sellele loale."</string> -    <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba voogesitada rakendusi ja muid süsteemi funktsioone läheduses olevatesse seadmetesse"</string> +    <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_NAME">%2$s</xliff:g> nimel luba voogesitada rakendusi ja muid süsteemi funktsioone läheduses olevatesse seadmetesse"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>      <string name="summary_generic" msgid="1761976003668044801">"See rakendus saab sünkroonida teavet, näiteks helistaja nime, teie telefoni ja valitud seadme vahel"</string>      <string name="consent_yes" msgid="8344487259618762872">"Luba"</string> @@ -59,7 +59,7 @@      <string name="permission_microphone" msgid="2152206421428732949">"Mikrofon"</string>      <string name="permission_call_logs" msgid="5546761417694586041">"Kõnelogid"</string>      <string name="permission_nearby_devices" msgid="7530973297737123481">"Läheduses olevad seadmed"</string> -    <string name="permission_media_routing_control" msgid="5498639511586715253">"Muutke meediaväljundit"</string> +    <string name="permission_media_routing_control" msgid="5498639511586715253">"Meediaväljundi muutmine"</string>      <string name="permission_storage" msgid="6831099350839392343">"Fotod ja meedia"</string>      <string name="permission_notifications" msgid="4099418516590632909">"Märguanded"</string>      <string name="permission_app_streaming" msgid="6009695219091526422">"Rakendused"</string> diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml index d0dee9ba9021..ca8497077f6a 100644 --- a/packages/CompanionDeviceManager/res/values-eu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml @@ -26,8 +26,8 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"gailua"</string>      <string name="summary_glasses" msgid="2872254734959842579">"Baimen hauek erabili ahalko ditu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>n aplikazioak:"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"Eman informazioa telefonotik hartzeko baimena <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aplikazioari zure telefonoko aplikazioak zuzenean igortzeko baimena eman nahi diozu?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s aplikazioak telefonoan ikusgai dagoen edo erreproduzitzen den eduki guztia atzitu ahal izango du, audioa, argazkiak, pasahitzak eta mezuak barne.<br/><br/>%1$s aplikazioak zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> gailuari zure telefonoko aplikazioak zuzenean igortzeko baimena eman nahi diozu?"</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s gailuak telefonoan ikusgai dagoen edo erreproduzitzen den eduki guztia atzitu ahal izango du, audioa, argazkiak, pasahitzak eta mezuak barne.<br/><br/>%1$s aplikazioak zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Gailuarteko zerbitzuak"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"Gailu batetik bestera aplikazioak igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> gailuaren izenean"</string>      <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Aplikazioak gailuen artean bistaratzeko eta zuzenean igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> gailuaren izenean"</string> @@ -38,8 +38,8 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"Telefonoko argazkiak, multimedia-edukia eta jakinarazpenak erabiltzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> gailuaren izenean"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Ekintza hau gauzatzeko baimena eman nahi diozu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> aplikazioari?"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> aplikazioari zure telefonoko aplikazioak eta sistemaren eginbideak zuzenean igortzeko baimena eman nahi diozu?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s aplikazioak telefonoan ikusgai dagoen edo erreproduzitzen den eduki guztia atzitu ahal izango du, audioa, argazkiak, ordainketa-informazioa, pasahitzak eta mezuak barne.<br/><br/>%1$s aplikazioak eta sistemaren eginbideak zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> gailuari zure telefonoko aplikazioak eta sistemaren eginbideak zuzenean igortzeko baimena eman nahi diozu?"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s gailuak telefonoan ikusgai dagoen edo erreproduzitzen den eduki guztia atzitu ahal izango du, audioa, argazkiak, ordainketa-informazioa, pasahitzak eta mezuak barne.<br/><br/>%1$s aplikazioak eta sistemaren eginbideak zuzenean igortzeko gai izango da, baimen hori kentzen diozun arte."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Aplikazioak eta sistemaren beste eginbide batzuk inguruko gailuetara igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_NAME">%2$s</xliff:g> gailuaren izenean"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>      <string name="summary_generic" msgid="1761976003668044801">"Telefonoaren eta hautatutako gailuaren artean informazioa sinkronizatzeko gai izango da aplikazioa (esate baterako, deitzaileen izenak)"</string> diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml index 9b556698c0a8..2363886c3484 100644 --- a/packages/CompanionDeviceManager/res/values-hi/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml @@ -27,10 +27,10 @@      <string name="summary_glasses" msgid="2872254734959842579">"यह ऐप्लिकेशन, आपके <xliff:g id="DEVICE_NAME">%1$s</xliff:g> पर इन अनुमतियों को ऐक्सेस कर पाएगा"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>      <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को आपके फ़ोन के ऐप्लिकेशन स्ट्रीम करने की अनुमति देनी है?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s के पास ऐसे कॉन्टेंट का ऐक्सेस होगा जो फ़ोन पर दिख रहा हो या चलाया गया हो. जैसे, ऑडियो, फ़ोटो, पासवर्ड, और मैसेज.<br/><br/>%1$s तब तक ऐप्लिकेशन स्ट्रीम करेगा, जब तक आप इस अनुमति को हटा न दें."</string> -    <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिवाइस से जुड़ी सेवाएं"</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s के पास ऐसे कॉन्टेंट का ऐक्सेस होगा जो फ़ोन पर दिख रहा हो या चल रहा हो. जैसे, ऑडियो, फ़ोटो, पासवर्ड, और मैसेज.<br/><br/>%1$s तब तक ऐप्लिकेशन स्ट्रीम करेगा, जब तक आप इस अनुमति को हटा न दें."</string> +    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> की ओर से, आपके डिवाइसों के बीच ऐप्लिकेशन स्ट्रीम करने की अनुमति मांग रहा है"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> की ओर से, आपके डिवाइसों के बीच ऐप्लिकेशन दिखाने और स्ट्रीम करने की अनुमति मांग रहा है"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> की ओर से, एक डिवाइस के ऐप्लिकेशन, दूसरे डिवाइस पर दिखाने और स्ट्रीम करने की अनुमति मांग रहा है"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string> @@ -39,7 +39,7 @@      <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> की ओर से, आपने फ़ोन में मौजूद फ़ोटो, मीडिया, और सूचनाओं को ऐक्सेस करने की अनुमति मांग रहा है"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"क्या <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> को यह कार्रवाई करने की अनुमति देनी है?"</string>      <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> को आपके फ़ोन के ऐप्लिकेशन और सिस्टम की सुविधाएं स्ट्रीम करने की अनुमति देनी है?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s के पास ऐसे कॉन्टेंट का ऐक्सेस होगा जो फ़ोन पर दिख रहा हो या चलाया गया हो. जैसे, ऑडियो, फ़ोटो, पेमेंट से जुड़ी जानकारी, पासवर्ड, और मैसेज.<br/><br/>%1$s तब तक ऐप्लिकेशन और सिस्टम की सुविधाओं को स्ट्रीम करेगा, जब तक आप इस अनुमति को हटा न दें."</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s के पास ऐसे कॉन्टेंट का ऐक्सेस होगा जो फ़ोन पर दिख रहा हो या चल रहा हो. जैसे, ऑडियो, फ़ोटो, पेमेंट की जानकारी, पासवर्ड, और मैसेज.<br/><br/>%1$s तब तक ऐप्लिकेशन और सिस्टम की सुविधाओं को स्ट्रीम करेगा, जब तक आप इस अनुमति को हटा न दें."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_NAME">%2$s</xliff:g> की ओर से, ऐप्लिकेशन और दूसरे सिस्टम की सुविधाओं को आस-पास मौजूद डिवाइसों पर स्ट्रीम करने की अनुमति मांग रहा है"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>      <string name="summary_generic" msgid="1761976003668044801">"यह ऐप्लिकेशन, आपके फ़ोन और चुने हुए डिवाइस के बीच जानकारी सिंक करेगा. जैसे, कॉल करने वाले व्यक्ति का नाम"</string> diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml index 1c9c218e34a4..4985ae3cde34 100644 --- a/packages/CompanionDeviceManager/res/values-hu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml @@ -59,7 +59,7 @@      <string name="permission_microphone" msgid="2152206421428732949">"Mikrofon"</string>      <string name="permission_call_logs" msgid="5546761417694586041">"Hívásnaplók"</string>      <string name="permission_nearby_devices" msgid="7530973297737123481">"Közeli eszközök"</string> -    <string name="permission_media_routing_control" msgid="5498639511586715253">"Médiakiment módosítása"</string> +    <string name="permission_media_routing_control" msgid="5498639511586715253">"Médiakimenet módosítása"</string>      <string name="permission_storage" msgid="6831099350839392343">"Fotók és médiatartalmak"</string>      <string name="permission_notifications" msgid="4099418516590632909">"Értesítések"</string>      <string name="permission_app_streaming" msgid="6009695219091526422">"Alkalmazások"</string> diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml index c4de3cd08ade..a655a3ec3705 100644 --- a/packages/CompanionDeviceManager/res/values-hy/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml @@ -26,8 +26,8 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"սարք"</string>      <string name="summary_glasses" msgid="2872254734959842579">"Այս հավելվածը կստանա հետևյալ թույլտվությունները ձեր <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ում"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"Թույլատրեք <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Թույլատրե՞լ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> հավելվածին հեռարձակել ձեր հեռախոսի հավելվածները"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s հավելվածին հասանելի կլինի հեռախոսում ցուցադրվող կամ նվագարկվող բովանդակությունը՝ ներառյալ աուդիոն, լուսանկարները, գաղտնաբառերը և հաղորդագրությունները։<br/><br/>%1$s հավելվածը կկարողանա հավելվածներ հեռարձակել, քանի դեռ չեք չեղարկել այս թույլտվությունը։"</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Թույլատրե՞լ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-ին հեռարձակել ձեր հեռախոսի հավելվածները"</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s-ին հասանելի կլինի հեռախոսում ցուցադրվող կամ նվագարկվող բովանդակությունը՝ ներառյալ աուդիոն, լուսանկարները, գաղտնաբառերը և հաղորդագրությունները։<br/><br/>%1$s-ը կկարողանա հավելվածներ հեռարձակել, քանի դեռ չեք չեղարկել այս թույլտվությունը։"</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Միջսարքային ծառայություններ"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր սարքերի միջև հավելվածներ հեռարձակելու համար"</string>      <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր սարքերի միջև հավելվածներ հեռարձակելու համար"</string> @@ -38,8 +38,8 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ծառայություններ"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր հեռախոսի լուսանկարները, մեդիաֆայլերն ու ծանուցումները տեսնելու համար"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Թույլատրե՞լ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> հավելվածին կատարել այս գործողությունը"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Թույլատրե՞լ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> սարքին հեռարձակել ձեր հեռախոսի հավելվածները և համակարգի գործառույթները"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s սարքին հասանելի կլինի ձեր հեռախոսում ցուցադրվող կամ նվագարկվող բովանդակությունը՝ ներառյալ աուդիոն, լուսանկարները, վճարային տեղեկությունները, գաղտնաբառերը և հաղորդագրությունները։<br/><br/>%1$s սարքը կկարողանա հավելվածներ և համակարգի գործառույթներ հեռարձակել, քանի դեռ չեք չեղարկել այս թույլտվությունը։"</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Թույլատրե՞լ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>-ին հեռարձակել ձեր հեռախոսի հավելվածները և համակարգի գործառույթները"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s-ին հասանելի կլինի ձեր հեռախոսում ցուցադրվող կամ նվագարկվող բովանդակությունը՝ ներառյալ աուդիոն, լուսանկարները, վճարային տեղեկությունները, գաղտնաբառերը և հաղորդագրությունները։<br/><br/>%1$s-ը կկարողանա հավելվածներ և համակարգի գործառույթներ հեռարձակել, քանի դեռ չեք չեղարկել այս թույլտվությունը։"</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_NAME">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ մոտակա սարքերին հավելվածներ և համակարգի այլ գործառույթներ հեռարձակելու համար"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string>      <string name="summary_generic" msgid="1761976003668044801">"Այս հավելվածը կկարողանա համաժամացնել ձեր հեռախոսի և ընտրված սարքի տվյալները, օր․՝ զանգողի անունը"</string> diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml index b1c4f5b01f50..1481ca136762 100644 --- a/packages/CompanionDeviceManager/res/values-in/strings.xml +++ b/packages/CompanionDeviceManager/res/values-in/strings.xml @@ -26,11 +26,11 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"perangkat"</string>      <string name="summary_glasses" msgid="2872254734959842579">"Aplikasi ini akan diizinkan mengakses izin ini di <xliff:g id="DEVICE_NAME">%1$s</xliff:g> Anda"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> untuk mengakses informasi ini dari ponsel Anda"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> melakukan streaming aplikasi di ponsel Anda?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s akan memiliki akses ke konten apa pun yang ditampilkan atau dimainkan di ponsel, termasuk audio, foto, sandi, dan pesan.<br/><br/>%1$s akan dapat melakukan streaming aplikasi hingga Anda menghapus izin ini."</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> menstreaming aplikasi di ponsel Anda?"</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s akan memiliki akses ke apa pun yang ditampilkan atau diputar di ponsel, termasuk audio, foto, sandi, dan pesan.<br/><br/>%1$s akan dapat menstreaming aplikasi hingga Anda menghapus izin ini."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Layanan lintas perangkat"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> untuk menstreaming aplikasi di antara perangkat Anda"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> menggantikan <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> meminta izin untuk menampilkan dan melakukan streaming aplikasi di antara perangkat Anda"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> untuk menampilkan dan menstreaming aplikasi di antara perangkat Anda"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"Izinkan <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> mengakses informasi ini dari ponsel Anda"</string> @@ -38,8 +38,8 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Layanan Google Play"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> untuk mengakses foto, media, dan notifikasi ponsel Anda"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Izinkan <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> melakukan tindakan ini?"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Izinkan <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> melakukan streaming aplikasi dan mengakses fitur sistem di ponsel Anda?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s akan memiliki akses ke konten apa pun yang ditampilkan atau dimainkan di ponsel Anda, termasuk audio, foto, info pembayaran, sandi, dan pesan.<br/><br/>%1$s akan dapat melakukan streaming aplikasi dan mengakses fitur sistem hingga Anda menghapus izin ini."</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Izinkan <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> menstreaming aplikasi dan fitur sistem di ponsel Anda?"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s akan memiliki akses ke apa pun yang ditampilkan atau diputar di ponsel Anda, termasuk audio, foto, info pembayaran, sandi, dan pesan.<br/><br/>%1$s akan dapat menstreaming aplikasi dan fitur sistem hingga Anda menghapus izin ini."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_NAME">%2$s</xliff:g> untuk menstreaming aplikasi dan fitur sistem lainnya ke perangkat di sekitar"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>      <string name="summary_generic" msgid="1761976003668044801">"Aplikasi ini akan dapat menyinkronkan info, seperti nama penelepon, antara ponsel dan perangkat yang dipilih"</string> diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml index f1eb53477960..ce8feb5e0f72 100644 --- a/packages/CompanionDeviceManager/res/values-iw/strings.xml +++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml @@ -30,7 +30,7 @@      <string name="summary_app_streaming" msgid="295548145144086753">"ל-%1$s תהיה גישה לכל מה שרואים או מפעילים בטלפון, כולל אודיו, תמונות, סיסמאות והודעות.<br/><br/>ל-%1$s תהיה אפשרות לשדר אפליקציות עד שהגישה להרשאה הזו תוסר."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"שירותים למספר מכשירים"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה עבור המכשיר <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> כדי לשדר אפליקציות בין המכשירים שלך"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה למכשיר <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> כדי להציג ולשדר אפליקציות בין המכשירים שלך"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"האפליקציה \'<xliff:g id="APP_NAME">%1$s</xliff:g>\' מבקשת הרשאה למכשיר <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> כדי להציג ולשדר אפליקציות בין המכשירים שלך"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"מתן אישור לאפליקציה <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> לגשת למידע הזה מהטלפון שלך"</string> diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml index 7aace8292792..7dbcef0675b5 100644 --- a/packages/CompanionDeviceManager/res/values-kn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml @@ -30,7 +30,7 @@      <string name="summary_app_streaming" msgid="295548145144086753">"ಆಡಿಯೋ, ಫೋಟೋಗಳು, ಪಾಸ್ವರ್ಡ್ಗಳು ಮತ್ತು ಸಂದೇಶಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿ ಗೋಚರಿಸುವ ಅಥವಾ ಪ್ಲೇ ಆಗುವ ಯಾವುದೇ ಕಂಟೆಂಟ್ಗೆ %1$s ಆ್ಯಕ್ಸೆಸ್ ಹೊಂದಿರುತ್ತದೆ.<br/><br/>ನೀವು ಈ ಅನುಮತಿಗೆ ಇರುವ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ತೆಗೆದುಹಾಕುವವರೆಗೆ %1$s ಗೆ ಆ್ಯಪ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"ಕ್ರಾಸ್-ಡಿವೈಸ್ ಸೇವೆಗಳು"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ನ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಿಕೊಳ್ಳುತ್ತಿದೆ"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್ಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲು ಮತ್ತು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್ಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲು ಮತ್ತು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸುತ್ತಿವೆ"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ಗೆ ಅನುಮತಿಸಿ"</string> diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml index 86679ac147f7..925f21b0028c 100644 --- a/packages/CompanionDeviceManager/res/values-ko/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml @@ -30,7 +30,7 @@      <string name="summary_app_streaming" msgid="295548145144086753">"%1$s에서 오디오, 사진, 비밀번호, 메시지 등 휴대전화에 표시되거나 휴대전화에서 재생되는 모든 항목에 액세스할 수 있습니다.<br/><br/>이 권한에 대한 액세스를 삭제할 때까지 %1$s에서 앱을 스트리밍할 수 있습니다."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"교차 기기 서비스"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> 대신 기기 간에 앱을 스트리밍할 수 있는 권한을 요청하고 있습니다."</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> 대신 기기 간 앱을 표시하고 스트리밍할 권한을 요청하고 있습니다."</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> 대신 연결된 기기의 앱을 표시하고 스트리밍할 권한을 요청하고 있습니다."</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>이 휴대전화에서 이 정보에 액세스하도록 허용"</string> diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml index 932b5c5339d5..1b72477f5e33 100644 --- a/packages/CompanionDeviceManager/res/values-ky/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml @@ -26,8 +26,8 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"түзмөк"</string>      <string name="summary_glasses" msgid="2872254734959842579">"Бул колдонмого <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүңүздө төмөнкүлөрдү аткарууга уруксат берилет"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна телефонуңуздагы колдонмолорду алып ойнотууга уруксат бересизби?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s телефондо көрүнгөн же ойнотулган бардык нерселерге, анын ичинде аудио, сүрөттөр, сырсөздөр жана билдирүүлөргө кире алат. Бул уруксатты алып салмайынча, <br/><br/>%1$s колдонмолорду алып ойното алат."</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> колдонмосуна телефонуңуздагы колдонмолорду өткөрүүгө уруксат бересизби?"</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s телефондо көрүнгөн же ойнотулган аудиофайлдар, сүрөттөр, сырсөздөр жана билдирүүлөр сыяктуу нерселерди көрө алат. Бул уруксатты алып салмайынча, <br/><br/>%1$s колдонмолорду өткөрө берет."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Түзмөктөр аралык кызматтар"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> түзмөгүңүздүн атынан түзмөктөрүңүздүн ортосунда колдонмолорду алып ойнотууга уруксат сурап жатат"</string>      <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> түзмөгүңүздүн атынан түзмөктөрдүн ортосунда колдонмолорду көрсөтүү жана алып ойнотуу үчүн уруксат сурап жатат"</string> @@ -38,8 +38,8 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Google Play кызматтары"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> түзмөгүңүздүн атынан телефондогу сүрөттөрдү, медиа файлдарды жана билдирмелерди колдонууга уруксат сурап жатат"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> түзмөгүнө бул аракетти аткарууга уруксат бересизби?"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> колдонмосуна телефонуңуздагы колдонмолорду жана тутумдун функцияларын алып ойнотууга уруксат бересизби?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s телефонуңузда көрүнгөн же ойнотулган бардык нерселерге, анын ичинде аудио, сүрөттөр, төлөм маалыматы, сырсөздөр жана билдирүүлөргө кире алат. Бул уруксатты алып салмайынча, <br/><br/>%1$s колдонмолорду жана тутум функцияларын алып ойното алат."</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> колдонмосуна телефонуңуздагы колдонмолорду жана системалык функцияларды өткөргөнгө уруксат бересизби?"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s телефонуңузда көрүнгөн же ойнотулган аудиофайлдар, сүрөттөр, төлөм маалыматы, сырсөздөр жана билдирүүлөр сыяктуу нерселерди көрө алат. Бул уруксатты алып салмайынча, <br/><br/>%1$s колдонмолорду жана системдик функцияларды өткөрө алат."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_NAME">%2$s</xliff:g> түзмөгүңүздүн атынан жакын жердеги түзмөктөрдө колдонмолорду жана системанын башка функцияларын алып ойнотууга уруксат сурап жатат"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string>      <string name="summary_generic" msgid="1761976003668044801">"Бул колдонмо маалыматты шайкештире алат, мисалы, чалып жаткан кишинин атын телефон жана тандалган түзмөк менен шайкештирет"</string> diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml index fe6e4cca4e07..0c4bfcbfd6ba 100644 --- a/packages/CompanionDeviceManager/res/values-mn/strings.xml +++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml @@ -27,7 +27,7 @@      <string name="summary_glasses" msgid="2872254734959842579">"Энэ апп таны <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-н эдгээр зөвшөөрөлд хандах эрхтэй байх болно"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string>      <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Таны утасны аппуудыг дамжуулахыг <strong><xliff:g id="APP_NAME">%1$s</xliff:g>-д</strong> зөвшөөрөх үү?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s аудио, зураг, нууц үг болон мессежүүдийг оруулаад утсан дээр харагдсан эсвэх тоглуулсан аливаа зүйлд хандах эрхтэй болно.<br/><br/>%1$s таныг энэ зөвшөөрлийг хасах хүртэл аппуудыг дамжуулах боломжтой байх болно."</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s аудио, зураг, нууц үг болон мессежүүдийг зэрэг утсан дээр харагдсан эсвэл тоглуулсан аливаа зүйлд хандах эрхтэй болно.<br/><br/>%1$s таныг энэ зөвшөөрлийг хасах хүртэл аппуудыг дамжуулах боломжтой байх болно."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Төхөөрөмж хоорондын үйлчилгээ"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"Таны төхөөрөмжүүд хооронд апп дамжуулахын тулд <xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-н өмнөөс зөвшөөрөл хүсэж байна"</string>      <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-н өмнөөс таны төхөөрөмжүүдийн хооронд аппууд үзүүлж, дамжуулах зөвшөөрлийг хүсэж байна"</string> @@ -39,7 +39,7 @@      <string name="helper_summary_computer" msgid="8774832742608187072">"Таны утасны зураг, медиа болон мэдэгдэлд хандахын тулд <xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>-н өмнөөс зөвшөөрөл хүсэж байна"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>-д энэ үйлдлийг хийхийг зөвшөөрөх үү?"</string>      <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Таны утасны апп болон системийн онцлогуудыг дамжуулахыг <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g>-д</strong> зөвшөөрөх үү?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s аудио, зураг, төлбөрийн мэдээлэл, нууц үг болон мессежүүдийг оруулаад утсан дээр харагдсан эсвэх тоглуулсан аливаа зүйлд хандах эрхтэй болно.<br/><br/>%1$s таныг энэ зөвшөөрлийг хасах хүртэл апп болон системийн онцлогуудыг дамжуулах боломжтой байх болно."</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s аудио, зураг, төлбөрийн мэдээлэл, нууц үг болон мессеж зэрэг утсан дээр харагдсан эсвэл тоглуулсан аливаа зүйлд хандах эрхтэй болно.<br/><br/>%1$s таныг энэ зөвшөөрлийг хасах хүртэл апп болон системийн онцлогуудыг дамжуулах боломжтой байх болно."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DEVICE_NAME">%2$s</xliff:g>-н өмнөөс аппууд болон системийн бусад онцлогийг ойролцоох төхөөрөмжүүд рүү дамжуулах зөвшөөрөл хүсэж байна"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string>      <string name="summary_generic" msgid="1761976003668044801">"Энэ апп залгаж буй хүний нэр зэрэг мэдээллийг таны утас болон сонгосон төхөөрөмжийн хооронд синк хийх боломжтой болно"</string> diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml index d817df2678f3..4605c18eec0e 100644 --- a/packages/CompanionDeviceManager/res/values-nb/strings.xml +++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml @@ -24,7 +24,7 @@      <string name="summary_watch" msgid="7962014927042971830">"Denne appen får tillatelse til å synkronisere informasjon som navnet til noen som ringer, og har disse tillatelsene på <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>      <string name="confirmation_title_glasses" msgid="8288346850537727333">"Vil du la <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> administrere <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string>      <string name="profile_name_glasses" msgid="3506504967216601277">"enheten"</string> -    <string name="summary_glasses" msgid="2872254734959842579">"Denne appen får disse tillatelsene på <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string> +    <string name="summary_glasses" msgid="2872254734959842579">"Denne appen får disse tillatelsene på enheten din (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>)"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"Gi <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tilgang til denne informasjonen fra telefonen din"</string>      <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Vil du tillate at <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> strømmer appene på telefonen?"</string>      <string name="summary_app_streaming" msgid="295548145144086753">"%1$s får tilgang til alt som er synlig eller spilles av på telefonen, inkludert lyd, bilder, passord og meldinger.<br/><br/>%1$s kan strømme apper til du fjerner denne tillatelsen."</string> diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml index 8394a82a963d..448362f619b0 100644 --- a/packages/CompanionDeviceManager/res/values-pa/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml @@ -27,7 +27,7 @@      <string name="summary_glasses" msgid="2872254734959842579">"ਇਸ ਐਪ ਨੂੰ ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> \'ਤੇ ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>      <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"ਕੀ <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s ਕੋਲ ਆਡੀਓ, ਫ਼ੋਟੋਆਂ, ਪਾਸਵਰਡਾਂ ਅਤੇ ਸੁਨੇਹਿਆਂ ਸਮੇਤ, ਫ਼ੋਨ \'ਤੇ ਦਿਖਾਈ ਦੇਣ ਵਾਲੀ ਜਾਂ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਕਿਸੇ ਵੀ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ।<br/><br/>%1$s ਐਪਾਂ ਨੂੰ ਉਦੋਂ ਤੱਕ ਸਟ੍ਰੀਮ ਕਰ ਸਕੇਗੀ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਇਸ ਇਜਾਜ਼ਤ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹਟਾ ਦਿੰਦੇ।"</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s ਕੋਲ ਆਡੀਓ, ਫ਼ੋਟੋਆਂ, ਪਾਸਵਰਡਾਂ ਅਤੇ ਸੁਨੇਹਿਆਂ ਸਮੇਤ, ਫ਼ੋਨ \'ਤੇ ਦਿਖਾਈ ਦੇਣ ਵਾਲੀ ਜਾਂ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਕਿਸੇ ਵੀ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ।<br/><br/>%1$s ਐਪਾਂ ਨੂੰ ਉਦੋਂ ਤੱਕ ਸਟ੍ਰੀਮ ਕਰ ਸਕੇਗਾ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਇਸ ਇਜਾਜ਼ਤ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹਟਾ ਦਿੰਦੇ।"</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"ਕ੍ਰਾਸ-ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>      <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਐਪਾਂ ਨੂੰ ਦਿਖਾਉਣ ਅਤੇ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string> @@ -39,7 +39,7 @@      <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਫ਼ੋਨ ਦੀਆਂ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਸੂਚਨਾਵਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"ਕੀ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ਨੂੰ ਇਹ ਕਾਰਵਾਈ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>      <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"ਕੀ <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਅਤੇ ਸਿਸਟਮ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s ਕੋਲ ਆਡੀਓ, ਫ਼ੋਟੋਆਂ, ਭੁਗਤਾਨ ਜਾਣਕਾਰੀ, ਪਾਸਵਰਡਾਂ ਅਤੇ ਸੁਨੇਹਿਆਂ ਸਮੇਤ, ਫ਼ੋਨ \'ਤੇ ਦਿਖਾਈ ਦੇਣ ਵਾਲੀ ਜਾਂ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਕਿਸੇ ਵੀ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ।<br/><br/>%1$s ਐਪਾਂ ਨੂੰ ਉਦੋਂ ਤੱਕ ਸਟ੍ਰੀਮ ਅਤੇ ਸਿਸਟਮ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕੇਗੀ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਇਸ ਇਜਾਜ਼ਤ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹਟਾ ਦਿੰਦੇ।"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s ਕੋਲ ਆਡੀਓ, ਫ਼ੋਟੋਆਂ, ਭੁਗਤਾਨ ਜਾਣਕਾਰੀ, ਪਾਸਵਰਡਾਂ ਅਤੇ ਸੁਨੇਹਿਆਂ ਸਮੇਤ, ਫ਼ੋਨ \'ਤੇ ਦਿਖਾਈ ਦੇਣ ਵਾਲੀ ਜਾਂ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਕਿਸੇ ਵੀ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ।<br/><br/>%1$s ਐਪਾਂ ਨੂੰ ਉਦੋਂ ਤੱਕ ਸਟ੍ਰੀਮ ਅਤੇ ਸਿਸਟਮ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕੇਗਾ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਇਸ ਇਜਾਜ਼ਤ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹਟਾ ਦਿੰਦੇ।"</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ \'ਤੇ ਐਪਾਂ ਅਤੇ ਹੋਰ ਸਿਸਟਮ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string>      <string name="summary_generic" msgid="1761976003668044801">"ਇਹ ਐਪ ਤੁਹਾਡੇ ਫ਼ੋਨ ਅਤੇ ਚੁਣੇ ਗਏ ਡੀਵਾਈਸ ਵਿਚਕਾਰ ਕਾਲਰ ਦੇ ਨਾਮ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਸਿੰਕ ਕਰ ਸਕੇਗੀ"</string> diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml index 945f8491597f..757967858bea 100644 --- a/packages/CompanionDeviceManager/res/values-pl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml @@ -30,7 +30,7 @@      <string name="summary_app_streaming" msgid="295548145144086753">"%1$s będzie mieć dostęp do wszystkiego, co jest widoczne i odtwarzane na telefonie, w tym do dźwięku, zdjęć, haseł i wiadomości.<br/><br/>%1$s będzie w stanie strumieniować aplikacje, dopóki nie usuniesz dostępu do tego uprawnienia."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usługi na innym urządzeniu"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> o uprawnienia dotyczące strumieniowego odtwarzania treści z aplikacji na innym urządzeniu"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> o pozwolenie na wyświetlanie i strumieniowanie aplikacji między Twoimi urządzeniami"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> o pozwolenie na wyświetlanie i strumieniowanie aplikacji między Twoimi urządzeniami"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"Zezwól aplikacji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> na dostęp do tych informacji na Twoim telefonie"</string> diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml index 289d6e07f2e8..eb7b533abfc1 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml @@ -30,7 +30,7 @@      <string name="summary_app_streaming" msgid="295548145144086753">"O app %1$s terá acesso a tudo o que estiver visível ou for aberto no smartphone, incluindo áudios, fotos, senhas e mensagens. O app <br/><br/>%1$s poderá fazer o streaming de apps até que você remova o acesso a essa permissão."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para mostrar e fazer streaming de apps entre seus dispositivos"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para mostrar e fazer streaming de apps entre seus dispositivos"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string> @@ -38,8 +38,8 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realize esta ação?"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> faça streaming dos apps e recursos do sistema do smartphone?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"O app %1$s terá acesso a tudo o que estiver visível ou for aberto no smartphone, incluindo áudios, fotos, informações de pagamento, senhas e mensagens. O app <br/><br/>%1$s poderá fazer o streaming de apps e recursos do sistema até que você remova o acesso a essa permissão."</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Permitir que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> faça streaming de apps e recursos do sistema do smartphone?"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"O %1$s terá acesso a tudo o que estiver visível ou for aberto no smartphone, incluindo áudios, fotos, informações de pagamento, senhas e mensagens. <br/><br/>O %1$s poderá acessar e transferir informações de apps e recursos do sistema até que você remova essa permissão."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps e de outros recursos do sistema para dispositivos por perto"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>      <string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string> diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml index 9d94de7b66ce..c951334e68ff 100644 --- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml @@ -26,8 +26,8 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"dispositivo"</string>      <string name="summary_glasses" msgid="2872254734959842579">"Esta app vai poder aceder a estas autorizações no seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"Permita que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> aceda a estas informações do seu telemóvel"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Permitir que a app <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça stream das apps do telemóvel?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s vai ter acesso a tudo o que seja visível ou reproduzido no telemóvel, incluindo áudio, fotos, palavras-passe e mensagens.<br/><br/>%1$s vai poder fazer stream de apps até remover o acesso a esta autorização."</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Permitir que o dispositivo <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> faça stream das apps do telemóvel?"</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"O dispositivo %1$s vai ter acesso a tudo o que seja visível ou reproduzido no telemóvel, incluindo áudio, fotos, palavras-passe e mensagens.<br/><br/>O %1$s vai poder fazer stream de apps até remover o acesso a esta autorização."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para fazer stream de apps entre os seus dispositivos"</string>      <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para apresentar e fazer stream de apps entre os seus dispositivos"</string> @@ -39,7 +39,7 @@      <string name="helper_summary_computer" msgid="8774832742608187072">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para aceder às fotos, ao conteúdo multimédia e às notificações do seu telemóvel"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> faça esta ação?"</string>      <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> faça stream das apps e das funcionalidades do sistema do telemóvel?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s vai ter acesso a tudo o que seja visível ou reproduzido no telemóvel, incluindo áudio, fotos, informações de pagamento, palavras-passe e mensagens.<br/><br/>%1$s vai poder fazer stream de apps e funcionalidades do sistema até remover o acesso a esta autorização."</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"O dispositivo %1$s vai ter acesso a tudo o que seja visível ou reproduzido no telemóvel, incluindo áudio, fotos, informações de pagamento, palavras-passe e mensagens.<br/><br/>O %1$s vai poder fazer stream de apps e funcionalidades do sistema até remover o acesso a esta autorização."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer stream de apps e outras funcionalidades do sistema para dispositivos próximos"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>      <string name="summary_generic" msgid="1761976003668044801">"Esta app vai poder sincronizar informações, como o nome do autor de uma chamada, entre o telemóvel e o dispositivo escolhido"</string> diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml index 289d6e07f2e8..eb7b533abfc1 100644 --- a/packages/CompanionDeviceManager/res/values-pt/strings.xml +++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml @@ -30,7 +30,7 @@      <string name="summary_app_streaming" msgid="295548145144086753">"O app %1$s terá acesso a tudo o que estiver visível ou for aberto no smartphone, incluindo áudios, fotos, senhas e mensagens. O app <br/><br/>%1$s poderá fazer o streaming de apps até que você remova o acesso a essa permissão."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para mostrar e fazer streaming de apps entre seus dispositivos"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para mostrar e fazer streaming de apps entre seus dispositivos"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"Autorizar que <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> acesse estas informações do smartphone"</string> @@ -38,8 +38,8 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> realize esta ação?"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Permitir que o dispositivo <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> faça streaming dos apps e recursos do sistema do smartphone?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"O app %1$s terá acesso a tudo o que estiver visível ou for aberto no smartphone, incluindo áudios, fotos, informações de pagamento, senhas e mensagens. O app <br/><br/>%1$s poderá fazer o streaming de apps e recursos do sistema até que você remova o acesso a essa permissão."</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Permitir que <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> faça streaming de apps e recursos do sistema do smartphone?"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"O %1$s terá acesso a tudo o que estiver visível ou for aberto no smartphone, incluindo áudios, fotos, informações de pagamento, senhas e mensagens. <br/><br/>O %1$s poderá acessar e transferir informações de apps e recursos do sistema até que você remova essa permissão."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu dispositivo <xliff:g id="DEVICE_NAME">%2$s</xliff:g> para fazer streaming de apps e de outros recursos do sistema para dispositivos por perto"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>      <string name="summary_generic" msgid="1761976003668044801">"O app poderá sincronizar informações, como o nome de quem está ligando, entre seu smartphone e o dispositivo escolhido"</string> diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml index ce65c702aa8c..15456aaac3ea 100644 --- a/packages/CompanionDeviceManager/res/values-ru/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml @@ -26,11 +26,11 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"устройстве"</string>      <string name="summary_glasses" msgid="2872254734959842579">"Это приложение получит указанные разрешения на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>      <string name="title_app_streaming" msgid="2270331024626446950">"Разрешите приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> получать эту информацию с вашего телефона"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Разрешить приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> транслировать приложения с вашего телефона?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"Приложение \"%1$s\" получит доступ ко всему, что показывается или воспроизводится на телефоне, включая аудиофайлы, фотографии, пароли и сообщения.<br/><br/>Приложение \"%1$s\" сможет транслировать приложения, пока вы не отзовете это разрешение."</string> -    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервисы стриминга приложений"</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Разрешить устройству <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> транслировать приложения с вашего телефона?"</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"У устройства \"%1$s\" будет доступ ко всему, что показывается или воспроизводится на телефоне, включая аудиофайлы, фотографии, пароли и сообщения.<br/><br/><br/>Устройство \"%1$s\" сможет транслировать приложения, пока вы не отзовете это разрешение."</string> +    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервисы для нескольких устройств"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запрашивает разрешение от имени вашего устройства <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>, чтобы транслировать приложения между устройствами."</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запрашивает разрешение от имени вашего устройства <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>, чтобы транслировать приложения между устройствами."</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени вашего устройства \"<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>\" запрашивает разрешение на трансляцию приложений между устройствами."</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"Разрешите приложению <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> получать эту информацию с вашего телефона"</string> @@ -38,8 +38,8 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Сервисы Google Play"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запрашивает разрешение от имени вашего устройства <xliff:g id="DISPLAY_NAME">%2$s</xliff:g>, чтобы получить доступ к фотографиям, медиаконтенту и уведомлениям на телефоне."</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Разрешить приложению <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> выполнять это действие?"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Разрешить приложению <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> транслировать приложения и системные функции с вашего телефона?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"Приложение \"%1$s\" получит доступ ко всему, что показывается или воспроизводится на вашем телефоне, включая аудиофайлы, фотографии, платежные данные, пароли и сообщения.<br/><br/>Приложение \"%1$s\" сможет транслировать приложения и системные функции, пока вы не отзовете это разрешение."</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Разрешить устройству <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> транслировать приложения и системные функции с вашего телефона?"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"У устройства \"%1$s\" будет доступ ко всему, что показывается или воспроизводится на вашем телефоне, включая аудиофайлы, фотографии, платежные данные, пароли и сообщения.<br/><br/>Устройство \"%1$s\" сможет транслировать приложения и системные функции, пока вы не отзовете это разрешение."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" от имени вашего устройства \"<xliff:g id="DEVICE_NAME">%2$s</xliff:g>\" запрашивает разрешение транслировать приложения и системные функции на устройства поблизости."</string>      <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>      <string name="summary_generic" msgid="1761976003668044801">"Приложение сможет синхронизировать информацию между телефоном и выбранным устройством, например данные из журнала звонков."</string> diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml index bbee596d56f4..c0d27f1e32e1 100644 --- a/packages/CompanionDeviceManager/res/values-sk/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml @@ -26,11 +26,11 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"zariadenie"</string>      <string name="summary_glasses" msgid="2872254734959842579">"Táto aplikácia bude mať prístup k týmto povoleniam v zariadení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k týmto informáciám z vášho telefónu"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Chcete povoliť aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamovať aplikácie vo svojom telefóne?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s bude mať prístup k všetkému obsahu viditeľnému alebo prehrávanému v telefóne vrátane zvuku, fotiek, hesiel a správ.<br/><br/>%1$s bude môcť streamovať aplikácie, kým prístup k tomuto povoleniu neodstránite."</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Chcete povoliť zariadeniu <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> streamovať aplikácie telefónu?"</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s bude mať prístup k všetkému, čo v telefóne zobrazíte alebo prehrajete, vrátane zvuku, fotiek, hesiel a správ.<br/><br/>%1$s bude môcť streamovať aplikácie, kým toto povolenie neodstránite."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pre viacero zariadení"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje pre zariadenie <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> povolenie streamovať aplikácie medzi vašimi zariadeniami."</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje pre zariadenie <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> povolenie zobrazovať a streamovať aplikácie medzi zariadeniami"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje v mene zariadenia <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> povolenie zobrazovať a streamovať aplikácie medzi zariadeniami"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"Povoľte aplikácii <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> prístup k týmto informáciám z vášho telefónu"</string> @@ -38,8 +38,8 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje pre zariadenie <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> povolenie na prístup k fotkám, médiám a upozorneniam vášho telefónu"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Chcete povoliť zariadeniu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> vykonať túto akciu?"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Chcete povoliť aplikácii <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> streamovať aplikácie a systémové funkcie vo svojom telefóne?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s bude mať prístup k všetkému obsahu viditeľnému alebo prehrávanému v telefóne vrátane zvuku, fotiek, platobných údajov, hesiel a správ.<br/><br/>%1$s bude môcť streamovať aplikácie, kým prístup k tomuto povoleniu neodstránite."</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Chcete povoliť zariadeniu <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> streamovať aplikácie a systémové funkcie telefónu?"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s bude mať prístup k všetkému, čo v telefóne zobrazíte alebo prehrajete, vrátane zvuku, fotiek, platobných údajov, hesiel a správ.<br/><br/>%1$s bude môcť streamovať aplikácie a systémové funkcie, kým toto povolenie neodstránite."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje pre zariadenie <xliff:g id="DEVICE_NAME">%2$s</xliff:g> povolenie streamovať aplikácie a ďalšie systémové funkcie do zariadení v okolí"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>      <string name="summary_generic" msgid="1761976003668044801">"Táto aplikácia bude môcť synchronizovať informácie, napríklad meno volajúceho, medzi telefónom a vybraným zariadením"</string> diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml index 346fbaee9625..a895c25bf075 100644 --- a/packages/CompanionDeviceManager/res/values-sl/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml @@ -28,7 +28,7 @@      <string name="title_app_streaming" msgid="2270331024626446950">"Dovolite, da <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dostopa do teh podatkov v vašem telefonu"</string>      <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Ali aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> dovolite, da pretočno predvaja aplikacije telefona?"</string>      <string name="summary_app_streaming" msgid="295548145144086753">"Aplikacija %1$s bo imela dostop do vsega, kar je prikazano ali se predvaja v telefonu, vključno z zvokom, fotografijami, gesli in sporočili.<br/><br/>Aplikacija %1$s bo lahko pretočno predvajala aplikacije, dokler ne odstranite dostopa do tega dovoljenja."</string> -    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Storitve za zunanje naprave"</string> +    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Storitve v več napravah"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>« zahteva dovoljenje za pretočno predvajanje aplikacij v vaših napravah."</string>      <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>« zahteva dovoljenje za prikaz in pretočno predvajanje aplikacij v vaših napravah."</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string> diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml index 76f623a1d2f5..63e8cb6a4c32 100644 --- a/packages/CompanionDeviceManager/res/values-sq/strings.xml +++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml @@ -27,20 +27,20 @@      <string name="summary_glasses" msgid="2872254734959842579">"Këtij aplikacioni do t\'i lejohet qasja te këto leje në <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ketë qasje në këtë informacion nga telefoni yt"</string>      <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"Të lejohet që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të transmetojë aplikacionet e telefonit tënd?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s do të ketë qasje te çdo gjë që është e dukshme ose luhet në telefon, duke përfshirë audion, fotografitë, fjalëkalimet dhe mesazhet.<br/><br/>%1$s do të mund të transmetojë aplikacionet derisa ta heqësh qasjen për këtë leje."</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s do të ketë qasje te çdo gjë që është e dukshme ose që luhet në telefon, duke përfshirë audion, fotografitë, fjalëkalimet dhe mesazhet.<br/><br/>%1$s do të mund t\'i transmetojë aplikacionet derisa ta heqësh qasjen për këtë leje."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Shërbimet mes pajisjeve"</string> -    <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> për të transmetuar aplikacione ndërmjet pajisjeve të tua"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> për të shfaqur dhe transmetuar aplikacionet mes pajisjeve të tua"</string> +    <string name="helper_summary_app_streaming" msgid="2396773196949578425">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" po kërkon leje në emër të <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> për të transmetuar aplikacione ndërmjet pajisjeve të tua"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" po kërkon leje në emër të <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> për të shfaqur dhe transmetuar aplikacionet mes pajisjeve të tua"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"Lejo që <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> të ketë qasje në këtë informacion nga telefoni yt"</string>      <string name="summary_computer" msgid="3798467601598297062"></string>      <string name="helper_title_computer" msgid="4671071173916176037">"Shërbimet e Google Play"</string> -    <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> për të marrë qasje te fotografitë, media dhe njoftimet e telefonit tënd"</string> +    <string name="helper_summary_computer" msgid="8774832742608187072">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" po kërkon leje në emër të <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> për të marrë qasje te fotografitë, media dhe njoftimet e telefonit tënd"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Të lejohet që <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> të ndërmarrë këtë veprim?"</string>      <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Të lejohet që <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> të transmetojë aplikacionet dhe veçoritë e sistemit të telefonit tënd?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s do të ketë qasje te çdo gjë që është e dukshme ose luhet në telefon, duke përfshirë audion, fotografitë, informacionet për pagesën, fjalëkalimet dhe mesazhet.<br/><br/>%1$s do të mund të transmetojë aplikacionet dhe veçoritë e sistemit derisa ta heqësh qasjen për këtë leje."</string> -    <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) tënde për të transmetuar aplikacione dhe veçori të tjera të sistemit te pajisjet në afërsi"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s do të ketë qasje te çdo gjë që është e dukshme ose që luhet në telefon, duke përfshirë audion, fotografitë, informacionet për pagesën, fjalëkalimet dhe mesazhet.<br/><br/>%1$s do të mund t\'i transmetojë aplikacionet dhe veçoritë e sistemit derisa ta heqësh qasjen për këtë leje."</string> +    <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" po kërkon leje në emër të (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) tënde për të transmetuar aplikacione dhe veçori të tjera të sistemit te pajisjet në afërsi"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>      <string name="summary_generic" msgid="1761976003668044801">"Ky aplikacion do të mund të sinkronizojë informacione, si p.sh emrin e dikujt që po telefonon, mes telefonit tënd dhe pajisjes së zgjedhur."</string>      <string name="consent_yes" msgid="8344487259618762872">"Lejo"</string> diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml index ede266e23464..2643b2d4c19b 100644 --- a/packages/CompanionDeviceManager/res/values-te/strings.xml +++ b/packages/CompanionDeviceManager/res/values-te/strings.xml @@ -28,7 +28,7 @@      <string name="title_app_streaming" msgid="2270331024626446950">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> యాప్ను అనుమతించండి"</string>      <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"మీ ఫోన్ యాప్లను స్ట్రీమ్ చేయడానికి <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>ను అనుమతించాలా?"</string>      <string name="summary_app_streaming" msgid="295548145144086753">"ఆడియో, ఫోటోలు, పాస్వర్డ్లు, మెసేజ్లతో సహా ఫోన్లో కనిపించే లేదా ప్లే అయ్యే దేనికైనా %1$sకు యాక్సెస్ ఉంటుంది.<br/><br/>మీరు ఈ అనుమతికి యాక్సెస్ను తీసివేసే వరకు %1$s యాప్లను స్ట్రీమ్ చేయగలదు."</string> -    <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string> +    <string name="helper_title_app_streaming" msgid="4151687003439969765">"క్రాస్-డివైజ్ సర్వీసులు"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"మీ పరికరాల మధ్య యాప్లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> మీ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>      <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"మీ పరికరాలలో యాప్లను డిస్ప్లే చేయడానికి, స్ట్రీమ్ చేయడానికి <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> తరఫున <xliff:g id="APP_NAME">%1$s</xliff:g> అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string> diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml index 3efc29925a21..5852657a01b5 100644 --- a/packages/CompanionDeviceManager/res/values-tr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml @@ -26,7 +26,7 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"Cihaz"</string>      <string name="summary_glasses" msgid="2872254734959842579">"Bu uygulamanın <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızda şu izinlere erişmesine izin verilecek:"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adlı uygulamanın telefonunuzdaki uygulamaları aktarmasına izin verilsin mi?"</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> adlı cihazın telefonunuzdaki uygulamaları aktarmasına izin verilsin mi?"</string>      <string name="summary_app_streaming" msgid="295548145144086753">"%1$s; ses, fotoğraflar, şifreler ve mesajlar da dahil olmak üzere telefonda görünen veya oynatılan her şeye erişebilecek.<br/><br/>%1$s siz bu iznin erişimini kaldırana kadar uygulamaları aktarabilecek."</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlar arası hizmetler"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g>, cihazlarınız arasında uygulama akışı gerçekleştirmek için <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> cihazınız adına izin istiyor"</string> @@ -38,7 +38,7 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Hizmetleri"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g>, telefonunuzdaki fotoğraf, medya ve bildirimlere erişmek için <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> cihazınız adına izin istiyor"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> cihazının bu işlemi yapmasına izin verilsin mi?"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> adlı uygulamanın telefonunuzdaki uygulamaları ve sistem özelliklerini aktarmasına izin verilsin mi?"</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> adlı cihazın telefonunuzdaki uygulamaları ve sistem özelliklerini aktarmasına izin verilsin mi?"</string>      <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s; ses, fotoğraflar, ödeme bilgileri, şifreler ve mesajlar da dahil olmak üzere telefonunuzda görünen veya oynatılan her şeye erişebilecek.<br/><br/>%1$s siz bu iznin erişimini kaldırana kadar uygulamaları ve diğer sistem özelliklerini aktarabilecek."</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması <xliff:g id="DEVICE_NAME">%2$s</xliff:g> cihazınız adına uygulamaları ve diğer sistem özelliklerini yakındaki cihazlara aktarmak için izin istiyor"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string> diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml index 109a011bccd6..d92a2e088f25 100644 --- a/packages/CompanionDeviceManager/res/values-ur/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml @@ -27,7 +27,7 @@      <string name="summary_glasses" msgid="2872254734959842579">"اس ایپ کو آپ کے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> پر ان اجازتوں تک رسائی کی اجازت ہوگی"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"اپنے فون سے ان معلومات تک رسائی حاصل کرنے کی <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو اجازت دیں"</string>      <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"اجازت دیں<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> اپنے فون کی ایپس کو سلسلہ بندی کرنے کے لیے؟"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s کو فون پر دکھائی دینے والی یا چلائی جانے والی کسی بھی چیز تک رسائی حاصل ہوگی، بشمول آڈیو، تصاویر، پاس ورڈز اور پیغامات۔<br/><br/>%1$s اس وقت تک ایپس کو اسٹریم کر سکے گید جب تک آپ اس اجازت تک رسائی کو ہٹا دیتے ہیں۔"</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s کو فون پر دکھائی دینے والی یا چلائی جانے والی کسی بھی چیز تک رسائی حاصل ہوگی، بشمول آڈیو، تصاویر، پاس ورڈز اور پیغامات۔<br/><br/>اس وقت تک %1$s ایپس کو اسٹریم کر سکے گا جب تک آپ اس اجازت تک رسائی کو ہٹا نہیں دیتے۔"</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"کراس ڈیوائس سروسز"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> کی جانب سے آپ کے آلات کے درمیان ایپس کی سلسلہ بندی کرنے کی اجازت کی درخواست کر رہی ہے"</string>      <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"<xliff:g id="APP_NAME">%1$s</xliff:g> آپ کے <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> کی جانب سے آپ کے آلات کے درمیان ایپس کو ڈسپلے اور اسٹریم کرنے کے لیے اجازت کی درخواست کر رہی ہے"</string> @@ -38,7 +38,7 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Google Play سروسز"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> کی جانب سے آپ کے فون کی تصاویر، میڈیا اور اطلاعات تک رسائی کی اجازت کی درخواست کر رہی ہے"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> کو یہ کارروائی انجام دینے کی اجازت دیں؟"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"اجازت دیں <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> اپنے فون کی ایپس اور سسٹم کی خصوصیات کو سلسلہ بندی کرنے کے لیے؟"</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"آپ کے فون کی ایپس اور سسٹم کی خصوصیات کو سلسلہ بندی کرنے کی <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> کو اجازت دیں؟"</string>      <!-- String.format failed for translation -->      <!-- no translation found for summary_nearby_device_streaming (4039565463149145573) -->      <skip /> diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml index 750ff0d5ce4e..6daf4ff20b54 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml @@ -26,11 +26,11 @@      <string name="profile_name_glasses" msgid="3506504967216601277">"设备"</string>      <string name="summary_glasses" msgid="2872254734959842579">"该应用将可以获得您<xliff:g id="DEVICE_NAME">%1$s</xliff:g>上的以下权限"</string>      <string name="title_app_streaming" msgid="2270331024626446950">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”<strong></strong>访问您手机中的这项信息"</string> -    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 流式传输手机的应用?"</string> -    <string name="summary_app_streaming" msgid="295548145144086753">"“%1$s”将能够访问手机上可见或播放的任何内容,包括音频、照片、密码和消息。<br/><br/>“%1$s”将能够流式传输应用,除非您撤消此访问权限。"</string> +    <string name="title_app_streaming_with_mirroring" msgid="3364582597581570658">"要允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 流式传输手机的应用吗?"</string> +    <string name="summary_app_streaming" msgid="295548145144086753">"%1$s 将能够访问手机上可见或播放的任何内容,包括音频、照片、密码和消息。<br/><br/>%1$s 将能够流式传输应用,除非您撤消此访问权限。"</string>      <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨设备服务"</string>      <string name="helper_summary_app_streaming" msgid="2396773196949578425">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>请求在您的设备之间流式传输应用内容"</string> -    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>请求在设备之间显示和流式传输应用"</string> +    <string name="helper_summary_app_streaming_with_mirroring" msgid="6138581029144467467">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的 <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> 请求在设备之间显示和流式传输应用"</string>      <string name="title_automotive_projection" msgid="3296005598978412847"></string>      <string name="summary_automotive_projection" msgid="8683801274662496164"></string>      <string name="title_computer" msgid="4693714143506569253">"允许 <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 访问您手机中的这项信息"</string> @@ -38,8 +38,8 @@      <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服务"</string>      <string name="helper_summary_computer" msgid="8774832742608187072">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DISPLAY_NAME">%2$s</xliff:g>请求访问您手机上的照片、媒体内容和通知"</string>      <string name="title_nearby_device_streaming" msgid="7269956847378799794">"允许<strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong>进行此操作?"</string> -    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"允许 <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> 流式传输手机的应用和系统功能?"</string> -    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"“%1$s”将能够访问手机上可见或播放的任何内容,包括音频、照片、付款信息、密码和消息。<br/><br/>“%1$s”将能够流式传输应用和系统功能,除非您撤消此访问权限。"</string> +    <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"要允许 <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> 流式传输手机的应用和系统功能吗?"</string> +    <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s 将能够访问手机上可见或播放的任何内容,包括音频、照片、付款信息、密码和消息。<br/><br/>%1$s 将能够流式传输应用和系统功能,除非您撤消此访问权限。"</string>      <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DEVICE_NAME">%2$s</xliff:g>请求将应用和其他系统功能流式传输到附近的设备"</string>      <string name="profile_name_generic" msgid="6851028682723034988">"设备"</string>      <string name="summary_generic" msgid="1761976003668044801">"此应用将能在您的手机和所选设备之间同步信息,例如来电者的姓名"</string> diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml index 0af108052137..e8e24f492005 100644 --- a/packages/CompanionDeviceManager/res/values/styles.xml +++ b/packages/CompanionDeviceManager/res/values/styles.xml @@ -40,6 +40,7 @@          <item name="android:layout_width">match_parent</item>          <item name="android:layout_height">wrap_content</item>          <item name="android:gravity">center</item> +        <item name="android:textDirection">locale</item>          <item name="android:layout_marginLeft">14dp</item>          <item name="android:layout_marginRight">14dp</item>          <item name="android:textSize">20sp</item> @@ -53,6 +54,7 @@          <item name="android:layout_marginTop">18dp</item>          <item name="android:layout_marginLeft">18dp</item>          <item name="android:layout_marginRight">18dp</item> +        <item name="android:textDirection">locale</item>          <item name="android:textSize">14sp</item>          <item name="android:textColor">?android:attr/textColorSecondary</item>      </style> diff --git a/packages/CrashRecovery/aconfig/flags.aconfig b/packages/CrashRecovery/aconfig/flags.aconfig index 8627eac7beed..15fdc521f75a 100644 --- a/packages/CrashRecovery/aconfig/flags.aconfig +++ b/packages/CrashRecovery/aconfig/flags.aconfig @@ -2,7 +2,7 @@ package: "android.crashrecovery.flags"  flag {      name: "recoverability_detection" -    namespace: "package_watchdog" +    namespace: "package_manager_service"      description: "Feature flag for recoverability detection"      bug: "310236690"      is_fixed_read_only: true diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java index 8891b50352d1..75a8bdfe5416 100644 --- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java +++ b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java @@ -39,15 +39,15 @@ import android.text.TextUtils;  import android.util.ArrayMap;  import android.util.ArraySet;  import android.util.AtomicFile; -import android.util.BackgroundThread; -import android.util.LongArrayQueue;  import android.util.Slog;  import android.util.Xml; +import android.utils.BackgroundThread; +import android.utils.LongArrayQueue; +import android.utils.XmlUtils;  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.modules.utils.TypedXmlPullParser;  import com.android.modules.utils.TypedXmlSerializer; diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java index 271d552fc574..f86eb61c365f 100644 --- a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java +++ b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java @@ -31,7 +31,6 @@ import android.content.pm.VersionedPackage;  import android.crashrecovery.flags.Flags;  import android.os.Build;  import android.os.Environment; -import android.os.FileUtils;  import android.os.PowerManager;  import android.os.RecoverySystem;  import android.os.SystemClock; @@ -44,10 +43,11 @@ import android.text.TextUtils;  import android.util.ArraySet;  import android.util.Log;  import android.util.Slog; +import android.utils.ArrayUtils; +import android.utils.FileUtils;  import com.android.internal.annotations.GuardedBy;  import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils;  import com.android.server.PackageWatchdog.FailureReasons;  import com.android.server.PackageWatchdog.PackageHealthObserver;  import com.android.server.PackageWatchdog.PackageHealthObserverImpact; diff --git a/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java b/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java new file mode 100644 index 000000000000..fa4d6afc03d3 --- /dev/null +++ b/packages/CrashRecovery/services/java/com/android/utils/ArrayUtils.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.utils; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.io.File; +import java.util.List; +import java.util.Objects; + +/** + * Copied over from frameworks/base/core/java/com/android/internal/util/ArrayUtils.java + * + * @hide + */ +public class ArrayUtils { +    private ArrayUtils() { /* cannot be instantiated */ } +    public static final File[] EMPTY_FILE = new File[0]; + + +    /** +     * Return first index of {@code value} in {@code array}, or {@code -1} if +     * not found. +     */ +    public static <T> int indexOf(@Nullable T[] array, T value) { +        if (array == null) return -1; +        for (int i = 0; i < array.length; i++) { +            if (Objects.equals(array[i], value)) return i; +        } +        return -1; +    } + +    /** @hide */ +    public static @NonNull File[] defeatNullable(@Nullable File[] val) { +        return (val != null) ? val : EMPTY_FILE; +    } + +    /** +     * Checks if given array is null or has zero elements. +     */ +    public static boolean isEmpty(@Nullable int[] array) { +        return array == null || array.length == 0; +    } + +    /** +     * True if the byte array is null or has length 0. +     */ +    public static boolean isEmpty(@Nullable byte[] array) { +        return array == null || array.length == 0; +    } + +    /** +     * Converts from List of bytes to byte array +     * @param list +     * @return byte[] +     */ +    public static byte[] toPrimitive(List<byte[]> list) { +        if (list.size() == 0) { +            return new byte[0]; +        } +        int byteLen = list.get(0).length; +        byte[] array = new byte[list.size() * byteLen]; +        for (int i = 0; i < list.size(); i++) { +            for (int j = 0; j < list.get(i).length; j++) { +                array[i * byteLen + j] = list.get(i)[j]; +            } +        } +        return array; +    } + +    /** +     * Adds value to given array if not already present, providing set-like +     * behavior. +     */ +    public static @NonNull int[] appendInt(@Nullable int[] cur, int val) { +        return appendInt(cur, val, false); +    } + +    /** +     * Adds value to given array. +     */ +    public static @NonNull int[] appendInt(@Nullable int[] cur, int val, +            boolean allowDuplicates) { +        if (cur == null) { +            return new int[] { val }; +        } +        final int n = cur.length; +        if (!allowDuplicates) { +            for (int i = 0; i < n; i++) { +                if (cur[i] == val) { +                    return cur; +                } +            } +        } +        int[] ret = new int[n + 1]; +        System.arraycopy(cur, 0, ret, 0, n); +        ret[n] = val; +        return ret; +    } +} diff --git a/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java b/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java index a6ae68f62f10..afcf6895fd0d 100644 --- a/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java +++ b/packages/CrashRecovery/services/java/com/android/utils/BackgroundThread.java @@ -14,7 +14,7 @@   * limitations under the License.   */ -package android.util; +package android.utils;  import android.annotation.NonNull;  import android.os.Handler; diff --git a/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java b/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java new file mode 100644 index 000000000000..e4923bfc4ecb --- /dev/null +++ b/packages/CrashRecovery/services/java/com/android/utils/FileUtils.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.utils; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Bits and pieces copied from hidden API of android.os.FileUtils. + * + * @hide + */ +public class FileUtils { +    /** +     * Read a text file into a String, optionally limiting the length. +     * +     * @param file     to read (will not seek, so things like /proc files are OK) +     * @param max      length (positive for head, negative of tail, 0 for no limit) +     * @param ellipsis to add of the file was truncated (can be null) +     * @return the contents of the file, possibly truncated +     * @throws IOException if something goes wrong reading the file +     * @hide +     */ +    public static @Nullable String readTextFile(@Nullable File file, @Nullable int max, +            @Nullable String ellipsis) throws IOException { +        InputStream input = new FileInputStream(file); +        // wrapping a BufferedInputStream around it because when reading /proc with unbuffered +        // input stream, bytes read not equal to buffer size is not necessarily the correct +        // indication for EOF; but it is true for BufferedInputStream due to its implementation. +        BufferedInputStream bis = new BufferedInputStream(input); +        try { +            long size = file.length(); +            if (max > 0 || (size > 0 && max == 0)) {  // "head" mode: read the first N bytes +                if (size > 0 && (max == 0 || size < max)) max = (int) size; +                byte[] data = new byte[max + 1]; +                int length = bis.read(data); +                if (length <= 0) return ""; +                if (length <= max) return new String(data, 0, length); +                if (ellipsis == null) return new String(data, 0, max); +                return new String(data, 0, max) + ellipsis; +            } else if (max < 0) {  // "tail" mode: keep the last N +                int len; +                boolean rolled = false; +                byte[] last = null; +                byte[] data = null; +                do { +                    if (last != null) rolled = true; +                    byte[] tmp = last; +                    last = data; +                    data = tmp; +                    if (data == null) data = new byte[-max]; +                    len = bis.read(data); +                } while (len == data.length); + +                if (last == null && len <= 0) return ""; +                if (last == null) return new String(data, 0, len); +                if (len > 0) { +                    rolled = true; +                    System.arraycopy(last, len, last, 0, last.length - len); +                    System.arraycopy(data, 0, last, last.length - len, len); +                } +                if (ellipsis == null || !rolled) return new String(last); +                return ellipsis + new String(last); +            } else {  // "cat" mode: size unknown, read it all in streaming fashion +                ByteArrayOutputStream contents = new ByteArrayOutputStream(); +                int len; +                byte[] data = new byte[1024]; +                do { +                    len = bis.read(data); +                    if (len > 0) contents.write(data, 0, len); +                } while (len == data.length); +                return contents.toString(); +            } +        } finally { +            bis.close(); +            input.close(); +        } +    } + +    /** +     * Perform an fsync on the given FileOutputStream. The stream at this +     * point must be flushed but not yet closed. +     * +     * @hide +     */ +    public static boolean sync(FileOutputStream stream) { +        try { +            if (stream != null) { +                stream.getFD().sync(); +            } +            return true; +        } catch (IOException e) { +        } +        return false; +    } + +    /** +     * List the files in the directory or return empty file. +     * +     * @hide +     */ +    public static @NonNull File[] listFilesOrEmpty(@Nullable File dir) { +        return (dir != null) ? ArrayUtils.defeatNullable(dir.listFiles()) +            : ArrayUtils.EMPTY_FILE; +    } +} diff --git a/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java b/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java index 948ebcca0263..fdb15e2333d5 100644 --- a/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java +++ b/packages/CrashRecovery/services/java/com/android/utils/HandlerExecutor.java @@ -14,7 +14,7 @@   * limitations under the License.   */ -package android.util; +package android.utils;  import android.annotation.NonNull;  import android.os.Handler; diff --git a/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java b/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java new file mode 100644 index 000000000000..5cdc2536129a --- /dev/null +++ b/packages/CrashRecovery/services/java/com/android/utils/LongArrayQueue.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.utils; + +import libcore.util.EmptyArray; + +import java.util.NoSuchElementException; + +/** + * Copied from frameworks/base/core/java/android/util/LongArrayQueue.java + * + * @hide + */ +public class LongArrayQueue { + +    private long[] mValues; +    private int mSize; +    private int mHead; +    private int mTail; + +    private long[] newUnpaddedLongArray(int num) { +        return new long[num]; +    } +    /** +     * Initializes a queue with the given starting capacity. +     * +     * @param initialCapacity the capacity. +     */ +    public LongArrayQueue(int initialCapacity) { +        if (initialCapacity == 0) { +            mValues = EmptyArray.LONG; +        } else { +            mValues = newUnpaddedLongArray(initialCapacity); +        } +        mSize = 0; +        mHead = mTail = 0; +    } + +    /** +     * Initializes a queue with default starting capacity. +     */ +    public LongArrayQueue() { +        this(16); +    } + +    /** @hide */ +    public static int growSize(int currentSize) { +        return currentSize <= 4 ? 8 : currentSize * 2; +    } + +    private void grow() { +        if (mSize < mValues.length) { +            throw new IllegalStateException("Queue not full yet!"); +        } +        final int newSize = growSize(mSize); +        final long[] newArray = newUnpaddedLongArray(newSize); +        final int r = mValues.length - mHead; // Number of elements on and to the right of head. +        System.arraycopy(mValues, mHead, newArray, 0, r); +        System.arraycopy(mValues, 0, newArray, r, mHead); +        mValues = newArray; +        mHead = 0; +        mTail = mSize; +    } + +    /** +     * Returns the number of elements in the queue. +     */ +    public int size() { +        return mSize; +    } + +    /** +     * Removes all elements from this queue. +     */ +    public void clear() { +        mSize = 0; +        mHead = mTail = 0; +    } + +    /** +     * Adds a value to the tail of the queue. +     * +     * @param value the value to be added. +     */ +    public void addLast(long value) { +        if (mSize == mValues.length) { +            grow(); +        } +        mValues[mTail] = value; +        mTail = (mTail + 1) % mValues.length; +        mSize++; +    } + +    /** +     * Removes an element from the head of the queue. +     * +     * @return the element at the head of the queue. +     * @throws NoSuchElementException if the queue is empty. +     */ +    public long removeFirst() { +        if (mSize == 0) { +            throw new NoSuchElementException("Queue is empty!"); +        } +        final long ret = mValues[mHead]; +        mHead = (mHead + 1) % mValues.length; +        mSize--; +        return ret; +    } + +    /** +     * Returns the element at the given position from the head of the queue, where 0 represents the +     * head of the queue. +     * +     * @param position the position from the head of the queue. +     * @return the element found at the given position. +     * @throws IndexOutOfBoundsException if {@code position} < {@code 0} or +     *                                   {@code position} >= {@link #size()} +     */ +    public long get(int position) { +        if (position < 0 || position >= mSize) { +            throw new IndexOutOfBoundsException("Index " + position +                + " not valid for a queue of size " + mSize); +        } +        final int index = (mHead + position) % mValues.length; +        return mValues[index]; +    } + +    /** +     * Returns the element at the head of the queue, without removing it. +     * +     * @return the element at the head of the queue. +     * @throws NoSuchElementException if the queue is empty +     */ +    public long peekFirst() { +        if (mSize == 0) { +            throw new NoSuchElementException("Queue is empty!"); +        } +        return mValues[mHead]; +    } + +    /** +     * Returns the element at the tail of the queue. +     * +     * @return the element at the tail of the queue. +     * @throws NoSuchElementException if the queue is empty. +     */ +    public long peekLast() { +        if (mSize == 0) { +            throw new NoSuchElementException("Queue is empty!"); +        } +        final int index = (mTail == 0) ? mValues.length - 1 : mTail - 1; +        return mValues[index]; +    } + +    /** +     * {@inheritDoc} +     */ +    @Override +    public String toString() { +        if (mSize <= 0) { +            return "{}"; +        } + +        final StringBuilder buffer = new StringBuilder(mSize * 64); +        buffer.append('{'); +        buffer.append(get(0)); +        for (int i = 1; i < mSize; i++) { +            buffer.append(", "); +            buffer.append(get(i)); +        } +        buffer.append('}'); +        return buffer.toString(); +    } +} diff --git a/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java b/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java new file mode 100644 index 000000000000..dbbef61f6777 --- /dev/null +++ b/packages/CrashRecovery/services/java/com/android/utils/XmlUtils.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.utils; + +import android.annotation.NonNull; +import android.system.ErrnoException; +import android.system.Os; + +import com.android.modules.utils.TypedXmlPullParser; + +import libcore.util.XmlObjectFactory; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Copied over partly from frameworks/base/core/java/com/android/internal/util/XmlUtils.java + * + * @hide + */ +public class XmlUtils { + +    private static final String STRING_ARRAY_SEPARATOR = ":"; + +    /** @hide */ +    public static final void beginDocument(XmlPullParser parser, String firstElementName) +            throws XmlPullParserException, IOException { +        int type; +        while ((type = parser.next()) != parser.START_TAG +            && type != parser.END_DOCUMENT) { +            // Do nothing +        } + +        if (type != parser.START_TAG) { +            throw new XmlPullParserException("No start tag found"); +        } + +        if (!parser.getName().equals(firstElementName)) { +            throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +                + ", expected " + firstElementName); +        } +    } + +    /** @hide */ +    public static boolean nextElementWithin(XmlPullParser parser, int outerDepth) +            throws IOException, XmlPullParserException { +        for (;;) { +            int type = parser.next(); +            if (type == XmlPullParser.END_DOCUMENT +                    || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) { +                return false; +            } +            if (type == XmlPullParser.START_TAG +                    && parser.getDepth() == outerDepth + 1) { +                return true; +            } +        } +    } + +    private static XmlPullParser newPullParser() { +        try { +            XmlPullParser parser = XmlObjectFactory.newXmlPullParser(); +            parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true); +            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); +            return parser; +        } catch (XmlPullParserException e) { +            throw new AssertionError(); +        } +    } + +    /** @hide */ +    public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in) +            throws IOException { +        final byte[] magic = new byte[4]; +        if (in instanceof FileInputStream) { +            try { +                Os.pread(((FileInputStream) in).getFD(), magic, 0, magic.length, 0); +            } catch (ErrnoException e) { +                throw e.rethrowAsIOException(); +            } +        } else { +            if (!in.markSupported()) { +                in = new BufferedInputStream(in); +            } +            in.mark(8); +            in.read(magic); +            in.reset(); +        } + +        final TypedXmlPullParser xml; +        xml = (TypedXmlPullParser) newPullParser(); +        try { +            xml.setInput(in, "UTF_8"); +        } catch (XmlPullParserException e) { +            throw new IOException(e); +        } +        return xml; +    } +} diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml index a24134b3ff3f..b17293dbe4e2 100644 --- a/packages/CredentialManager/res/values-af/strings.xml +++ b/packages/CredentialManager/res/values-af/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Skep toegangsleutel om by <xliff:g id="APP_NAME">%1$s</xliff:g> aan te meld?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Stoor wagwoord om by <xliff:g id="APP_NAME">%1$s</xliff:g> aan te meld?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Stoor aanmeldinligting vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Gebruik jou skermslot om ’n toegangsleutel vir <xliff:g id="APP_NAME">%1$s</xliff:g> te skep?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Gebruik jou skermslot om ’n wagwoord vir <xliff:g id="APP_NAME">%1$s</xliff:g> te skep?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Gebruik jou skermslot om aanmeldinligting vir <xliff:g id="APP_NAME">%1$s</xliff:g> te stoor?"</string>      <string name="passkey" msgid="632353688396759522">"toegangsleutel"</string>      <string name="password" msgid="6738570945182936667">"wagwoord"</string>      <string name="passkeys" msgid="5733880786866559847">"toegangsleutels"</string> diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml index 0554d81c0d6b..4ee07883d23e 100644 --- a/packages/CredentialManager/res/values-am/strings.xml +++ b/packages/CredentialManager/res/values-am/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"ወደ <xliff:g id="APP_NAME">%1$s</xliff:g> ለመግባት የይለፍ ቁልፍ ይፈጠር?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"ወደ <xliff:g id="APP_NAME">%1$s</xliff:g> ለመግባት የይለፍ ቃል ይቀመጥ?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"የ<xliff:g id="APP_NAME">%1$s</xliff:g> የመግቢያ መረጃ ይቀመጥ?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"ለ<xliff:g id="APP_NAME">%1$s</xliff:g> የይለፍ ቁልፍ ለመፍጠር የማያ ገጽ መቆለፊያዎን መጠቀም ይፈልጋሉ?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"ለ<xliff:g id="APP_NAME">%1$s</xliff:g> የይለፍ ቃል ለመፍጠር የማያ ገጽ መቆለፊያዎን መጠቀም ይፈልጋሉ?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"የ<xliff:g id="APP_NAME">%1$s</xliff:g> መግቢያ መረጃን ለማስቀመጥ የማያ ገጽ መቆለፊያዎን መጠቀም ይፈልጋሉ?"</string>      <string name="passkey" msgid="632353688396759522">"የይለፍ ቁልፍ"</string>      <string name="password" msgid="6738570945182936667">"የይለፍ ቃል"</string>      <string name="passkeys" msgid="5733880786866559847">"የይለፍ ቁልፎች"</string> diff --git a/packages/CredentialManager/res/values-ar/strings.xml b/packages/CredentialManager/res/values-ar/strings.xml index 5e089fe5a301..7e141c244516 100644 --- a/packages/CredentialManager/res/values-ar/strings.xml +++ b/packages/CredentialManager/res/values-ar/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"هل تريد إنشاء مفتاح مرور لتسجيل الدخول إلى \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"هل تريد حفظ كلمة المرور لتسجيل الدخول إلى \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"هل تريد حفظ معلومات تسجيل الدخول إلى \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"هل تريد استخدام قفل الشاشة لإنشاء مفتاح مرور لتطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"هل تريد استخدام قفل الشاشة لإنشاء كلمة مرور لتطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"هل تريد استخدام قفل الشاشة لحفظ معلومات تسجيل الدخول لتطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string>      <string name="passkey" msgid="632353688396759522">"مفتاح المرور"</string>      <string name="password" msgid="6738570945182936667">"كلمة المرور"</string>      <string name="passkeys" msgid="5733880786866559847">"مفاتيح المرور"</string> diff --git a/packages/CredentialManager/res/values-as/strings.xml b/packages/CredentialManager/res/values-as/strings.xml index 95a0e1b6a36d..cde91123d08b 100644 --- a/packages/CredentialManager/res/values-as/strings.xml +++ b/packages/CredentialManager/res/values-as/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g>ত ছাইন ইন কৰিবলৈ পাছকী সৃষ্টি কৰিবনে?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g>ত ছাইন ইন কৰিবলৈ পাছৱৰ্ড ছেভ কৰিবনে?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে ছাইন ইনৰ তথ্য ছেভ কৰিবনে?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে পাছকী সৃষ্টি কৰিবলৈ আপোনাৰ স্ক্ৰীন লক ব্যৱহাৰ কৰিবনে?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে পাছৱৰ্ড সৃষ্টি কৰিবলৈ আপোনাৰ স্ক্ৰীন লক ব্যৱহাৰ কৰিবনে?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে ছাইন ইনৰ তথ্য ছেভ কৰিবলৈ আপোনাৰ স্ক্ৰীন লক ব্যৱহাৰ কৰিবনে?"</string>      <string name="passkey" msgid="632353688396759522">"পাছকী"</string>      <string name="password" msgid="6738570945182936667">"পাছৱৰ্ড"</string>      <string name="passkeys" msgid="5733880786866559847">"পাছকী"</string> diff --git a/packages/CredentialManager/res/values-az/strings.xml b/packages/CredentialManager/res/values-az/strings.xml index 00a671847a38..1623ec4b292b 100644 --- a/packages/CredentialManager/res/values-az/strings.xml +++ b/packages/CredentialManager/res/values-az/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqinə daxil olmaq üçün giriş açarı yaradılsın?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqinə daxil olmaq üçün parol yadda saxlansın?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün giriş məlumatları yadda saxlansın?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün giriş açarı yaratmaq məqsədilə ekran kilidi istifadə edilsin?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün parol yaratmaq məqsədilə ekran kilidi istifadə edilsin?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün giriş məlumatını yadda saxlamaq məqsədilə ekran kilidi istifadə edilsin?"</string>      <string name="passkey" msgid="632353688396759522">"açar"</string>      <string name="password" msgid="6738570945182936667">"parol"</string>      <string name="passkeys" msgid="5733880786866559847">"açarlar"</string> diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml index 390c7742cde6..23c021e2528d 100644 --- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml +++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Želite da napravite pristupni ključ da biste se prijavili u <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Želite da sačuvate lozinku da biste se prijavili u <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Želite da sačuvate podatke za prijavljivanje za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Želite da koristite otključavanje ekrana da biste napravili pristupni ključ za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Želite da koristite otključavanje ekrana da biste napravili lozinku za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Želite da koristite otključavanje ekrana da biste sačuvali podatke za prijavljivanje za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"pristupni kôd"</string>      <string name="password" msgid="6738570945182936667">"lozinka"</string>      <string name="passkeys" msgid="5733880786866559847">"pristupni kodovi"</string> diff --git a/packages/CredentialManager/res/values-be/strings.xml b/packages/CredentialManager/res/values-be/strings.xml index 6922e7052d91..d27f68bf56de 100644 --- a/packages/CredentialManager/res/values-be/strings.xml +++ b/packages/CredentialManager/res/values-be/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Стварыць ключ доступу для ўваходу ў праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Захаваць пароль для ўваходу ў праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Захаваць даныя для ўваходу ў праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"ключ доступу"</string>      <string name="password" msgid="6738570945182936667">"пароль"</string>      <string name="passkeys" msgid="5733880786866559847">"ключы доступу"</string> diff --git a/packages/CredentialManager/res/values-bg/strings.xml b/packages/CredentialManager/res/values-bg/strings.xml index 3d33c8fd91f4..780699b450f7 100644 --- a/packages/CredentialManager/res/values-bg/strings.xml +++ b/packages/CredentialManager/res/values-bg/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Искате ли да създадете ключ за достъп, с който да влизате в(ъв) <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Искате ли да запазите паролата за влизане в(ъв) <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Искате ли да запазите данните за вход за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"код за достъп"</string>      <string name="password" msgid="6738570945182936667">"парола"</string>      <string name="passkeys" msgid="5733880786866559847">"ключове за достъп"</string> diff --git a/packages/CredentialManager/res/values-bn/strings.xml b/packages/CredentialManager/res/values-bn/strings.xml index fe42ed6f2ad1..9d429d4746a2 100644 --- a/packages/CredentialManager/res/values-bn/strings.xml +++ b/packages/CredentialManager/res/values-bn/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপে সাইন-ইন করার জন্য পাসকী তৈরি করবেন?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপে সাইন-ইন করার জন্য পাসওয়ার্ড সেভ করবেন?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপের জন্য সাইন-ইন সংক্রান্ত তথ্য সেভ করবেন?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"পাসকী"</string>      <string name="password" msgid="6738570945182936667">"পাসওয়ার্ড"</string>      <string name="passkeys" msgid="5733880786866559847">"পাসকী"</string> diff --git a/packages/CredentialManager/res/values-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml index f6e6d811f2a6..00c211b48e01 100644 --- a/packages/CredentialManager/res/values-bs/strings.xml +++ b/packages/CredentialManager/res/values-bs/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Kreirati pristupni ključ da se prijavite u aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Sačuvati lozinku da se prijavite u aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Sačuvati podatke za prijavu u aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Želite li upotrijebiti zaključavanje zaslona za izradu pristupnog ključa za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Želite li upotrijebiti zaključavanje zaslona za izradu zaporke za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Želite li upotrijebiti zaključavanje zaslona za spremanje podataka za prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"pristupni ključ"</string>      <string name="password" msgid="6738570945182936667">"lozinka"</string>      <string name="passkeys" msgid="5733880786866559847">"pristupni ključevi"</string> diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml index 3809d9251f7c..cf08741ebc2f 100644 --- a/packages/CredentialManager/res/values-ca/strings.xml +++ b/packages/CredentialManager/res/values-ca/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Vols crear una clau d\'accés per iniciar la sessió a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Vols desar la contrasenya per iniciar la sessió a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Vols desar la informació d\'inici de sessió per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"clau d\'accés"</string>      <string name="password" msgid="6738570945182936667">"contrasenya"</string>      <string name="passkeys" msgid="5733880786866559847">"claus d\'accés"</string> diff --git a/packages/CredentialManager/res/values-cs/strings.xml b/packages/CredentialManager/res/values-cs/strings.xml index 6e6857c209d9..5e0d42e2d25f 100644 --- a/packages/CredentialManager/res/values-cs/strings.xml +++ b/packages/CredentialManager/res/values-cs/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Vytvořit přístupový klíč k přihlašování do aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Uložit heslo k přihlašování do aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Uložit přihlašovací údaje pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"přístupový klíč"</string>      <string name="password" msgid="6738570945182936667">"heslo"</string>      <string name="passkeys" msgid="5733880786866559847">"přístupové klíče"</string> diff --git a/packages/CredentialManager/res/values-da/strings.xml b/packages/CredentialManager/res/values-da/strings.xml index ae7c3cfaf96e..e978b8e86890 100644 --- a/packages/CredentialManager/res/values-da/strings.xml +++ b/packages/CredentialManager/res/values-da/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Vil du oprette en adgangsnøgle for at logge ind på <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Vil du gemme adgangskoden for at logge ind på <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Vil du gemme loginoplysningerne til <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"adgangsnøgle"</string>      <string name="password" msgid="6738570945182936667">"adgangskode"</string>      <string name="passkeys" msgid="5733880786866559847">"adgangsnøgler"</string> diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml index 4fa669baa9d9..b338b1d92e48 100644 --- a/packages/CredentialManager/res/values-de/strings.xml +++ b/packages/CredentialManager/res/values-de/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Passkey zur Anmeldung in <xliff:g id="APP_NAME">%1$s</xliff:g> erstellen?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Passwort zur Anmeldung in <xliff:g id="APP_NAME">%1$s</xliff:g> speichern?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Anmeldedaten für <xliff:g id="APP_NAME">%1$s</xliff:g> speichern?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"Passkey"</string>      <string name="password" msgid="6738570945182936667">"Passwort"</string>      <string name="passkeys" msgid="5733880786866559847">"Passkeys"</string> diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml index b6b2728b8961..29ad56951449 100644 --- a/packages/CredentialManager/res/values-el/strings.xml +++ b/packages/CredentialManager/res/values-el/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Δημιουργία κλειδιού πρόσβασης για σύνδεση στην εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Αποθήκευση κωδικού πρόσβασης για σύνδεση στην εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Αποθήκευση πληροφοριών σύνδεσης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"κλειδί πρόσβασης"</string>      <string name="password" msgid="6738570945182936667">"κωδικός πρόσβασης"</string>      <string name="passkeys" msgid="5733880786866559847">"κλειδιά πρόσβασης"</string> diff --git a/packages/CredentialManager/res/values-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml index f177cf981e8c..b8bef997a383 100644 --- a/packages/CredentialManager/res/values-en-rAU/strings.xml +++ b/packages/CredentialManager/res/values-en-rAU/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Create passkey to sign in to <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Save password to sign in to <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Save sign-in info for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"passkey"</string>      <string name="password" msgid="6738570945182936667">"password"</string>      <string name="passkeys" msgid="5733880786866559847">"passkeys"</string> diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml index df4cd86e6d20..3fb3d55e655d 100644 --- a/packages/CredentialManager/res/values-en-rCA/strings.xml +++ b/packages/CredentialManager/res/values-en-rCA/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Create passkey to sign in to <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Save password to sign in to <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Save sign-in info for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Use your screen lock to create a passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Use your screen lock to create a password for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Use your screen lock to save sign in info for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"passkey"</string>      <string name="password" msgid="6738570945182936667">"password"</string>      <string name="passkeys" msgid="5733880786866559847">"passkeys"</string> diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml index f177cf981e8c..b8bef997a383 100644 --- a/packages/CredentialManager/res/values-en-rGB/strings.xml +++ b/packages/CredentialManager/res/values-en-rGB/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Create passkey to sign in to <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Save password to sign in to <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Save sign-in info for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"passkey"</string>      <string name="password" msgid="6738570945182936667">"password"</string>      <string name="passkeys" msgid="5733880786866559847">"passkeys"</string> diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml index f177cf981e8c..b8bef997a383 100644 --- a/packages/CredentialManager/res/values-en-rIN/strings.xml +++ b/packages/CredentialManager/res/values-en-rIN/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Create passkey to sign in to <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Save password to sign in to <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Save sign-in info for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"passkey"</string>      <string name="password" msgid="6738570945182936667">"password"</string>      <string name="passkeys" msgid="5733880786866559847">"passkeys"</string> diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml index 77ae53afc700..b642c87bf28a 100644 --- a/packages/CredentialManager/res/values-en-rXC/strings.xml +++ b/packages/CredentialManager/res/values-en-rXC/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Create passkey to sign in to <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Save password to sign in to <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Save sign-in info for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Use your screen lock to create a passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Use your screen lock to create a password for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Use your screen lock to save sign in info for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"passkey"</string>      <string name="password" msgid="6738570945182936667">"password"</string>      <string name="passkeys" msgid="5733880786866559847">"passkeys"</string> diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml index 6ccfec3d8a15..3b4392d924e7 100644 --- a/packages/CredentialManager/res/values-es-rUS/strings.xml +++ b/packages/CredentialManager/res/values-es-rUS/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"¿Quieres crear una llave de acceso para acceder a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"¿Quieres guardar la contraseña para acceder a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"¿Quieres guardar la información de acceso para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"llave de acceso"</string>      <string name="password" msgid="6738570945182936667">"contraseña"</string>      <string name="passkeys" msgid="5733880786866559847">"llaves de acceso"</string> diff --git a/packages/CredentialManager/res/values-es/strings.xml b/packages/CredentialManager/res/values-es/strings.xml index b2c1c6fe4915..427ed1d69c25 100644 --- a/packages/CredentialManager/res/values-es/strings.xml +++ b/packages/CredentialManager/res/values-es/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"¿Crear llave de acceso para iniciar sesión en <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"¿Guardar contraseña para iniciar sesión en <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"¿Guardar la información de inicio de sesión de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"llave de acceso"</string>      <string name="password" msgid="6738570945182936667">"contraseña"</string>      <string name="passkeys" msgid="5733880786866559847">"llaves de acceso"</string> diff --git a/packages/CredentialManager/res/values-et/strings.xml b/packages/CredentialManager/res/values-et/strings.xml index 823a016e8d8f..44b907e4b08d 100644 --- a/packages/CredentialManager/res/values-et/strings.xml +++ b/packages/CredentialManager/res/values-et/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Kas luua rakendusse <xliff:g id="APP_NAME">%1$s</xliff:g> sisselogimiseks pääsuvõti?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Kas salvestada rakendusse <xliff:g id="APP_NAME">%1$s</xliff:g> sisselogimiseks parool?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Kas salvestada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks sisselogimisteave?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"pääsuvõti"</string>      <string name="password" msgid="6738570945182936667">"parool"</string>      <string name="passkeys" msgid="5733880786866559847">"pääsuvõtmed"</string> diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml index 8507b3f21997..afc91ea2cdb2 100644 --- a/packages/CredentialManager/res/values-eu/strings.xml +++ b/packages/CredentialManager/res/values-eu/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioan saioa hasteko sarbide-gako bat sortu nahi duzu?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioan saioa hasteko pasahitza gorde nahi duzu?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioan saioa hasteko informazioa gorde nahi duzu?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"sarbide-gakoa"</string>      <string name="password" msgid="6738570945182936667">"pasahitza"</string>      <string name="passkeys" msgid="5733880786866559847">"sarbide-gakoak"</string> @@ -75,7 +81,7 @@      <string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioan saioa hasteko aukerak desblokeatu nahi dituzu?"</string>      <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Aukeratu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gordetako sarbide-gakoa"</string>      <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"Aukeratu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gordetako pasahitza"</string> -    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Aukeratu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gordetako kredentzialak"</string> +    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Aukeratu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gordetako saioa hasteko moduak"</string>      <string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"Aukeratu <xliff:g id="APP_NAME">%1$s</xliff:g> zerbitzuan saioa hasteko kredentzialak"</string>      <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako aukera bat hautatu nahi duzu?"</string>      <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioan erabili nahi duzu informazio hori?"</string> @@ -89,10 +95,10 @@      <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Desblokeatzeko, sakatu hau"</string>      <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Ez dago saioa hasteko informaziorik"</string>      <string name="no_sign_in_info_in" msgid="2641118151920288356">"Ez dago saioa hasteko informaziorik <xliff:g id="SOURCE">%1$s</xliff:g> kontuan"</string> -    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Kudeatu kredentzialak"</string> +    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Kudeatu saioa hasteko moduak"</string>      <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Beste gailu batean gordetakoak"</string>      <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Erabili beste gailu bat"</string>      <string name="request_cancelled_by" msgid="3735222326886267820">"Utzi du bertan behera eskaera <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak"</string> -    <string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"Saioa hasteko aukerak"</string> +    <string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"Saioa hasteko moduak"</string>      <string name="more_options_content_description" msgid="1323427365788198808">"Gehiago"</string>  </resources> diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml index 656c789a72b8..095cb0614ca5 100644 --- a/packages/CredentialManager/res/values-fa/strings.xml +++ b/packages/CredentialManager/res/values-fa/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"برای ورود به سیستم <xliff:g id="APP_NAME">%1$s</xliff:g>، گذرکلید ایجاد شود؟"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"برای ورود به سیستم <xliff:g id="APP_NAME">%1$s</xliff:g>، گذرواژه ذخیره شود؟"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"اطلاعات ورود به سیستم <xliff:g id="APP_NAME">%1$s</xliff:g> ذخیره شود؟"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"گذرکلید"</string>      <string name="password" msgid="6738570945182936667">"گذرواژه"</string>      <string name="passkeys" msgid="5733880786866559847">"گذرکلیدها"</string> diff --git a/packages/CredentialManager/res/values-fi/strings.xml b/packages/CredentialManager/res/values-fi/strings.xml index f2f1bfbb4d1e..7de1151f2117 100644 --- a/packages/CredentialManager/res/values-fi/strings.xml +++ b/packages/CredentialManager/res/values-fi/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Luodaanko avainkoodi sisäänkirjautumista (<xliff:g id="APP_NAME">%1$s</xliff:g>) varten?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Tallennetaanko salasana sisäänkirjautumista (<xliff:g id="APP_NAME">%1$s</xliff:g>) varten?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Tallennetaanko kirjautumistiedot (<xliff:g id="APP_NAME">%1$s</xliff:g>)?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"avainkoodi"</string>      <string name="password" msgid="6738570945182936667">"salasana"</string>      <string name="passkeys" msgid="5733880786866559847">"avainkoodit"</string> diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml index 891e98791449..519b14ace029 100644 --- a/packages/CredentialManager/res/values-fr-rCA/strings.xml +++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Créer une clé d\'accès pour se connecter à <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Enregistrer un mot de passe pour se connecter à <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Enregistrer les renseignements de connexion pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>      <string name="password" msgid="6738570945182936667">"mot de passe"</string>      <string name="passkeys" msgid="5733880786866559847">"clés d\'accès"</string> diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml index f2ca1fc4028c..f63c7c2aee2b 100644 --- a/packages/CredentialManager/res/values-fr/strings.xml +++ b/packages/CredentialManager/res/values-fr/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Créer une clé d\'accès pour se connecter à <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Enregistrer un mot de passe pour se connecter à <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Enregistrer les informations de connexion pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>      <string name="password" msgid="6738570945182936667">"mot de passe"</string>      <string name="passkeys" msgid="5733880786866559847">"clés d\'accès"</string> @@ -75,7 +81,7 @@      <string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Déverrouiller les options de connexion pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>      <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Choisir une clé d\'accès enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"Choisir un mot de passe enregistré pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> -    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Choisir des informations de connexion enregistrées pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> +    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Choisissez les identifiants à utiliser pour la connexion à <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"Choisir des infos de connexion pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Choisir une option pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>      <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Utiliser ces informations dans <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string> diff --git a/packages/CredentialManager/res/values-gl/strings.xml b/packages/CredentialManager/res/values-gl/strings.xml index 7117e1c00794..d756200c11d4 100644 --- a/packages/CredentialManager/res/values-gl/strings.xml +++ b/packages/CredentialManager/res/values-gl/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Queres crear unha clave de acceso para iniciar sesión en <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Queres gardar o contrasinal para iniciar sesión en <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Queres gardar a información de inicio de sesión de <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"clave de acceso"</string>      <string name="password" msgid="6738570945182936667">"contrasinal"</string>      <string name="passkeys" msgid="5733880786866559847">"claves de acceso"</string> @@ -75,7 +81,7 @@      <string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Queres desbloquear as opcións de inicio de sesión para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Escolle unha clave de acceso gardada para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"Escolle un contrasinal gardado para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> -    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Escolle un método de inicio de sesión gardado para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> +    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Escolle un inicio de sesión gardado para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"Escolle un inicio de sesión para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Queres escoller unha opción para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Queres usar esta información en <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> diff --git a/packages/CredentialManager/res/values-gu/strings.xml b/packages/CredentialManager/res/values-gu/strings.xml index 98b4686716ec..ed081288bffb 100644 --- a/packages/CredentialManager/res/values-gu/strings.xml +++ b/packages/CredentialManager/res/values-gu/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g>માં સાઇન ઇન કરવા માટે પાસકી બનાવીએ?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g>માં સાઇન ઇન કરવા માટે પાસવર્ડ સાચવીએ?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે સાઇન-ઇન કરવાની માહિતી સાચવીએ?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે કોઈ પાસકી બનાવવા માટે, શું તમારા સ્ક્રીન લૉકનો ઉપયોગ કરીએ?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે કોઈ પાસવર્ડ બનાવવા માટે, શું તમારા સ્ક્રીન લૉકનો ઉપયોગ કરીએ?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે સાઇન ઇનની માહિતી સાચવવા માટે, શું તમારા સ્ક્રીન લૉકનો ઉપયોગ કરીએ?"</string>      <string name="passkey" msgid="632353688396759522">"પાસકી"</string>      <string name="password" msgid="6738570945182936667">"પાસવર્ડ"</string>      <string name="passkeys" msgid="5733880786866559847">"પાસકી"</string> diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml index 9bc5feb6e9e9..16f04c5432b2 100644 --- a/packages/CredentialManager/res/values-hi/strings.xml +++ b/packages/CredentialManager/res/values-hi/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"क्या आपको <xliff:g id="APP_NAME">%1$s</xliff:g> में साइन इन करने के लिए पासकी बनानी है?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"क्या आपको <xliff:g id="APP_NAME">%1$s</xliff:g> में साइन इन करने के लिए पासवर्ड सेव करना है?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"क्या आपको <xliff:g id="APP_NAME">%1$s</xliff:g> के लिए साइन-इन की जानकारी सेव करनी है?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"क्या स्क्रीन लॉक का इस्तेमाल करके, <xliff:g id="APP_NAME">%1$s</xliff:g> के लिए पासकी बनानी है?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"क्या स्क्रीन लॉक का इस्तेमाल करके, <xliff:g id="APP_NAME">%1$s</xliff:g> के लिए पासवर्ड बनाना है?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"क्या स्क्रीन लॉक का इस्तेमाल करके, <xliff:g id="APP_NAME">%1$s</xliff:g> में साइन इन करने की जानकारी सेव करनी है?"</string>      <string name="passkey" msgid="632353688396759522">"पासकी"</string>      <string name="password" msgid="6738570945182936667">"पासवर्ड"</string>      <string name="passkeys" msgid="5733880786866559847">"पासकी"</string> @@ -75,24 +78,24 @@      <string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"क्या आपको <xliff:g id="APP_NAME">%1$s</xliff:g> में साइन इन करने के विकल्पों को अनलॉक करना है?"</string>      <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> के लिए सेव की गई पासकी चुनें"</string>      <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"<xliff:g id="APP_NAME">%1$s</xliff:g> के लिए सेव किया गया पासवर्ड चुनें"</string> -    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"<xliff:g id="APP_NAME">%1$s</xliff:g> के लिए सेव किया गया साइन इन क्रेडेंशियल चुनें"</string> +    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"<xliff:g id="APP_NAME">%1$s</xliff:g> के लिए सेव किया गया क्रेडेंशियल चुनें"</string>      <string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"<xliff:g id="APP_NAME">%1$s</xliff:g> के लिए साइन-इन क्रेडेंशियल चुनें"</string>      <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> में साइन इन करने के लिए सेव किए गए विकल्पों में से किसी को चुनना है?"</string>      <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"<xliff:g id="APP_NAME">%1$s</xliff:g> के लिए, क्या इस जानकारी का इस्तेमाल करना है?"</string>      <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"किसी दूसरे तरीके से साइन इन करें"</string>      <string name="snackbar_action" msgid="37373514216505085">"विकल्प देखें"</string>      <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"जारी रखें"</string> -    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"साइन इन करने के विकल्प"</string> +    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"साइन-इन करने के लिए विकल्प"</string>      <string name="button_label_view_more" msgid="3429098227286495651">"ज़्यादा देखें"</string>      <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> के लिए"</string>      <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"लॉक किए गए पासवर्ड मैनेजर"</string>      <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"अनलॉक करने के लिए टैप करें"</string>      <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"साइन-इन करने से जुड़ी कोई जानकारी उपलब्ध नहीं है"</string>      <string name="no_sign_in_info_in" msgid="2641118151920288356">"<xliff:g id="SOURCE">%1$s</xliff:g> में साइन-इन की जानकारी नहीं है"</string> -    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन इन करने की सुविधा को मैनेज करें"</string> +    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन-इन किए गए खाते मैनेज करें"</string>      <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"किसी दूसरे डिवाइस से"</string>      <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"दूसरे डिवाइस का इस्तेमाल करें"</string>      <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> की ओर से अनुरोध रद्द किया गया"</string> -    <string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"साइन-इन करने के विकल्प"</string> +    <string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"साइन-इन करने के लिए विकल्प"</string>      <string name="more_options_content_description" msgid="1323427365788198808">"ज़्यादा"</string>  </resources> diff --git a/packages/CredentialManager/res/values-hr/strings.xml b/packages/CredentialManager/res/values-hr/strings.xml index 968a7472d58e..2c10c2122ce3 100644 --- a/packages/CredentialManager/res/values-hr/strings.xml +++ b/packages/CredentialManager/res/values-hr/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Želite li izraditi pristupni ključ za prijavu u aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Želite li spremiti zaporku za prijavu u aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Želite li spremiti informacije o prijavi za <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Želite li upotrijebiti zaključavanje zaslona za izradu pristupnog ključa za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Želite li upotrijebiti zaključavanje zaslona za izradu zaporke za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Želite li upotrijebiti zaključavanje zaslona za spremanje podataka za prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"pristupni ključ"</string>      <string name="password" msgid="6738570945182936667">"zaporka"</string>      <string name="passkeys" msgid="5733880786866559847">"pristupni ključevi"</string> diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml index e601da676a2f..fe749f6129a8 100644 --- a/packages/CredentialManager/res/values-hu/strings.xml +++ b/packages/CredentialManager/res/values-hu/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Létrehoz azonosítókulcsot a következőbe való bejelentkezéshez: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Menti a jelszót a következőbe való bejelentkezéshez: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Menti a bejelentkezési adatokat a következőhöz: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"azonosítókulcs"</string>      <string name="password" msgid="6738570945182936667">"jelszó"</string>      <string name="passkeys" msgid="5733880786866559847">"azonosítókulcsait"</string> @@ -75,7 +81,7 @@      <string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Feloldja a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> bejelentkezési lehetőségeit?"</string>      <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Mentett azonosítókulcs kiválasztása a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz"</string>      <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"Mentett jelszó kiválasztása a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz"</string> -    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Mentett bejelentkezési adatok kiválasztása a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz"</string> +    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Mentett bejelentkezési adatok kiválasztása – <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"Válasszon bejelentkezési adatokat – <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"Kiválaszt egy lehetőséget a következőbe való bejelentkezéshez: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Használni szeretná ezt az információt a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazásban?"</string> diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml index 79a2624e980f..452acb7a18b2 100644 --- a/packages/CredentialManager/res/values-hy/strings.xml +++ b/packages/CredentialManager/res/values-hy/strings.xml @@ -27,7 +27,7 @@      <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Անցաբառերի հետ ավելի ապահով է"</string>      <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Անցաբառերի շնորհիվ դուք բարդ գաղտնաբառեր ստեղծելու կամ հիշելու անհրաժեշտություն չեք ունենա"</string>      <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Անցաբառերը գաղտնագրված թվային բանալիներ են, որոնք ստեղծվում են մատնահետքի, դեմքով ապակողպման կամ էկրանի կողպման օգտագործմամբ"</string> -    <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Դուք կարող եք մուտք գործել այլ սարքերում, քանի որ անցաբառերը պահվում են գաղտնաբառերի կառավարիչում"</string> +    <string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Դուք կարող եք մուտք գործել այլ սարքերում, քանի որ մուտքի բանալիները պահվում են գաղտնաբառերի կառավարիչում"</string>      <string name="more_about_passkeys_title" msgid="7797903098728837795">"Ավելին՝ անցաբառերի մասին"</string>      <string name="passwordless_technology_title" msgid="2497513482056606668">"Գաղտնաբառեր չպահանջող տեխնոլոգիա"</string>      <string name="passwordless_technology_detail" msgid="6853928846532955882">"Անցաբառերը ձեզ թույլ են տալիս մուտք գործել առանց գաղտնաբառերի։ Ձեզ պարզապես հարկավոր է օգտագործել ձեր մատնահետքը, դիմաճանաչումը, PIN կոդը կամ նախշը՝ ձեր ինքնությունը հաստատելու և անցաբառ ստեղծելու համար։"</string> @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Ստեղծե՞լ անցաբառ՝ <xliff:g id="APP_NAME">%1$s</xliff:g> հավելված մուտք գործելու համար"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Պահե՞լ գաղտնաբառը՝ <xliff:g id="APP_NAME">%1$s</xliff:g> հավելված մուտք գործելու համար"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Պահե՞լ «<xliff:g id="APP_NAME">%1$s</xliff:g>» հավելվածի մուտքի տվյալները"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"անցաբառ"</string>      <string name="password" msgid="6738570945182936667">"գաղտնաբառ"</string>      <string name="passkeys" msgid="5733880786866559847">"անցաբառեր"</string> @@ -53,7 +59,7 @@      <string name="save_password_on_other_device_title" msgid="5829084591948321207">"Պահե՞լ գաղտնաբառն այլ սարքում"</string>      <string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Պահե՞լ մուտքի տվյալներն այլ սարքում"</string>      <string name="use_provider_for_all_title" msgid="4201020195058980757">"Միշտ մուտք գործե՞լ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> հավելվածի միջոցով"</string> -    <string name="use_provider_for_all_description" msgid="1998772715863958997">"Այս գաղտնաբառերի կառավարչում <xliff:g id="USERNAME">%1$s</xliff:g> օգտատերը կկարողանա պահել իր գաղտնաբառերն ու անցաբառերը, որպեսզի հետագայում ավելի արագ մուտք գործի հաշիվ"</string> +    <string name="use_provider_for_all_description" msgid="1998772715863958997">"Այս գաղտնաբառերի կառավարչում <xliff:g id="USERNAME">%1$s</xliff:g> օգտատերը կկարողանա պահել իր գաղտնաբառերն ու մուտքի բանալիները, որպեսզի հետագայում ավելի արագ մուտք գործի հաշիվ"</string>      <string name="set_as_default" msgid="4415328591568654603">"Նշել որպես կանխադրված"</string>      <string name="settings" msgid="6536394145760913145">"Կարգավորումներ"</string>      <string name="use_once" msgid="9027366575315399714">"Օգտագործել մեկ անգամ"</string> diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml index e7556b01d730..3eac6e97f986 100644 --- a/packages/CredentialManager/res/values-in/strings.xml +++ b/packages/CredentialManager/res/values-in/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Buat kunci sandi untuk login ke <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Simpan sandi untuk login ke <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Simpan info login untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Gunakan kunci layar Anda untuk membuat kunci sandi untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Gunakan kunci layar Anda untuk membuat sandi untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Gunakan kunci layar Anda untuk menyimpan info login untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"kunci sandi"</string>      <string name="password" msgid="6738570945182936667">"sandi"</string>      <string name="passkeys" msgid="5733880786866559847">"kunci sandi"</string> diff --git a/packages/CredentialManager/res/values-is/strings.xml b/packages/CredentialManager/res/values-is/strings.xml index 970a2e647c8a..9fd552b11568 100644 --- a/packages/CredentialManager/res/values-is/strings.xml +++ b/packages/CredentialManager/res/values-is/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Búa til aðgangslykil til að skrá þig inn á <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Vista aðgangsorð til að skrá þig inn á <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Viltu vista innskráningarupplýsingar fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Nota skjálásinn til að búa til aðgangslykil fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Nota skjálásinn til að búa til aðgangsorð fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Nota skjálásinn til að vista innskráningarupplýsingar fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"aðgangslykill"</string>      <string name="password" msgid="6738570945182936667">"aðgangsorð"</string>      <string name="passkeys" msgid="5733880786866559847">"aðgangslykla"</string> diff --git a/packages/CredentialManager/res/values-it/strings.xml b/packages/CredentialManager/res/values-it/strings.xml index a04a840b5148..ce04dbc556b5 100644 --- a/packages/CredentialManager/res/values-it/strings.xml +++ b/packages/CredentialManager/res/values-it/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Creare passkey per accedere all\'app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Salvare password per accedere all\'app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Vuoi salvare i dati di accesso di <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"passkey"</string>      <string name="password" msgid="6738570945182936667">"password"</string>      <string name="passkeys" msgid="5733880786866559847">"passkey"</string> diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml index 87dee5fa8d5f..07b26b7d9c59 100644 --- a/packages/CredentialManager/res/values-iw/strings.xml +++ b/packages/CredentialManager/res/values-iw/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"ליצור מפתח גישה כדי להיכנס לחשבון ב-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"לשמור את הסיסמה כדי להיכנס לחשבון ב-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"לשמור את פרטי הכניסה של <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"מפתח גישה"</string>      <string name="password" msgid="6738570945182936667">"סיסמה"</string>      <string name="passkeys" msgid="5733880786866559847">"מפתחות גישה"</string> diff --git a/packages/CredentialManager/res/values-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml index 71746dc63994..f12bb5e50937 100644 --- a/packages/CredentialManager/res/values-ja/strings.xml +++ b/packages/CredentialManager/res/values-ja/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> にログインするためにパスキーを作成しますか?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> にログインするためにパスワードを保存しますか?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> のログイン情報を保存しますか?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"パスキー"</string>      <string name="password" msgid="6738570945182936667">"パスワード"</string>      <string name="passkeys" msgid="5733880786866559847">"パスキー"</string> diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml index 51f1332eba1d..4c6154040a7d 100644 --- a/packages/CredentialManager/res/values-ka/strings.xml +++ b/packages/CredentialManager/res/values-ka/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"შესასვლელად წვდომის გასაღების შექმნა: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"შესასვლელი პაროლის შენახვა: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"აპში შესვლის ინფორმაციის შენახვა: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"წვდომის გასაღები"</string>      <string name="password" msgid="6738570945182936667">"პაროლი"</string>      <string name="passkeys" msgid="5733880786866559847">"წვდომის გასაღები"</string> diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml index 7393ca08c1bc..5b76ac89f47e 100644 --- a/packages/CredentialManager/res/values-kk/strings.xml +++ b/packages/CredentialManager/res/values-kk/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасына кіру үшін кіру кілті жасалсын ба?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасына кіру үшін құпия сөз сақталсын ба?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін кіру мәліметін сақтау керек пе?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"Кіру кілті"</string>      <string name="password" msgid="6738570945182936667">"құпия сөз"</string>      <string name="passkeys" msgid="5733880786866559847">"кіру кілттері"</string> @@ -75,7 +81,7 @@      <string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін кіру опциялары ашылсын ба?"</string>      <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған кіру кілтін таңдаңыз"</string>      <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған құпия сөзді таңдаңыз"</string> -    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған тіркелу деректерін таңдаңыз"</string> +    <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған кіру деректерін таңдаңыз"</string>      <string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасына кіру деректерін таңдаңыз"</string>      <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін опция таңдайсыз ба?"</string>      <string name="get_dialog_title_use_info_on" msgid="8863708099535435146">"Бұл ақпарат <xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында сақталсын ба?"</string> diff --git a/packages/CredentialManager/res/values-km/strings.xml b/packages/CredentialManager/res/values-km/strings.xml index ac0d42704389..279474f96cb1 100644 --- a/packages/CredentialManager/res/values-km/strings.xml +++ b/packages/CredentialManager/res/values-km/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"បង្កើតកូដសម្ងាត់ ដើម្បីចូលគណនី <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"រក្សាទុកពាក្យសម្ងាត់ ដើម្បីចូលគណនី <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"រក្សាទុកព័ត៌មានចូលគណនីសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"ប្រើមុខងារចាក់សោអេក្រង់របស់អ្នក ដើម្បីបង្កើតកូដសម្ងាត់សម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"ប្រើមុខងារចាក់សោអេក្រង់របស់អ្នក ដើម្បីបង្កើតពាក្យសម្ងាត់សម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"ប្រើមុខងារចាក់សោអេក្រង់របស់អ្នក ដើម្បីរក្សាទុកព័ត៌មានចូលគណនីសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string>      <string name="passkey" msgid="632353688396759522">"កូដសម្ងាត់"</string>      <string name="password" msgid="6738570945182936667">"ពាក្យសម្ងាត់"</string>      <string name="passkeys" msgid="5733880786866559847">"កូដសម្ងាត់"</string> diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml index 031fa65114bf..01d0f59fe985 100644 --- a/packages/CredentialManager/res/values-kn/strings.xml +++ b/packages/CredentialManager/res/values-kn/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಲು ಪಾಸ್ಕೀ ಯನ್ನು ರಚಿಸಬೇಕೇ?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಲು ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ಸೇವ್ ಮಾಡಬೇಕೇ?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗಾಗಿ ಸೈನ್-ಇನ್ ಮಾಹಿತಿಯನ್ನು ಸೇವ್ ಮಾಡಬೇಕೇ?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"ಪಾಸ್ಕೀ"</string>      <string name="password" msgid="6738570945182936667">"ಪಾಸ್ವರ್ಡ್"</string>      <string name="passkeys" msgid="5733880786866559847">"ಪಾಸ್ಕೀಗಳು"</string> diff --git a/packages/CredentialManager/res/values-ko/strings.xml b/packages/CredentialManager/res/values-ko/strings.xml index e29ae68f7dc9..1f1fa2990d87 100644 --- a/packages/CredentialManager/res/values-ko/strings.xml +++ b/packages/CredentialManager/res/values-ko/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"패스키를 생성하여 <xliff:g id="APP_NAME">%1$s</xliff:g>에 로그인하시겠습니까?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"비밀번호를 저장하여 <xliff:g id="APP_NAME">%1$s</xliff:g>에 로그인하시겠습니까?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g>의 로그인 정보를 저장하시겠습니까?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"패스키"</string>      <string name="password" msgid="6738570945182936667">"비밀번호"</string>      <string name="passkeys" msgid="5733880786866559847">"패스키"</string> diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml index 5e48ae5b2b2e..4e3fed1e1874 100644 --- a/packages/CredentialManager/res/values-ky/strings.xml +++ b/packages/CredentialManager/res/values-ky/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосуна кирүү үчүн киргизүүчү ачкычты түзөсүзбү?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосуна кирүү үчүн сырсөздү сактайсызбы?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн кирүү маалыматы сакталсынбы?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу үчүн киргизүүчү ачкыч катары экрандын кулпусун колдоносузбу?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу үчүн сырсөз катары экрандын кулпусун колдоносузбу?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу үчүн кирүү маалыматы катары экрандын кулпусун колдоносузбу?"</string>      <string name="passkey" msgid="632353688396759522">"киргизүүчү ачкыч"</string>      <string name="password" msgid="6738570945182936667">"сырсөз"</string>      <string name="passkeys" msgid="5733880786866559847">"киргизүүчү ачкычтар"</string> diff --git a/packages/CredentialManager/res/values-lo/strings.xml b/packages/CredentialManager/res/values-lo/strings.xml index c3733a3ef1c3..e0f8839f1465 100644 --- a/packages/CredentialManager/res/values-lo/strings.xml +++ b/packages/CredentialManager/res/values-lo/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"ສ້າງກະແຈຜ່ານເພື່ອເຂົ້າສູ່ລະບົບ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"ບັນທຶກລະຫັດຜ່ານເພື່ອເຂົ້າສູ່ລະບົບ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"ບັນທຶກຂໍ້ມູນການເຂົ້າສູ່ລະບົບສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"ໃຊ້ລັອກໜ້າຈໍຂອງທ່ານເພື່ອສ້າງກະແຈຜ່ານສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"ໃຊ້ລັອກໜ້າຈໍຂອງທ່ານເພື່ອສ້າງລະຫັດຜ່ານສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"ໃຊ້ລັອກໜ້າຈໍຂອງທ່ານເພື່ອບັນທຶກຂໍ້ມູນການເຂົ້າສູ່ລະບົບສຳລັບ<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string>      <string name="passkey" msgid="632353688396759522">"ກະແຈຜ່ານ"</string>      <string name="password" msgid="6738570945182936667">"ລະຫັດຜ່ານ"</string>      <string name="passkeys" msgid="5733880786866559847">"ກະແຈຜ່ານ"</string> diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml index 453a0e0236eb..3b0124cf2249 100644 --- a/packages/CredentialManager/res/values-lt/strings.xml +++ b/packages/CredentialManager/res/values-lt/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Sukurti prieigos raktą, skirtą prisijungti prie „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Sukurti slaptažodį, skirtą prisijungti prie „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Išsaugoti prisijungimo prie „<xliff:g id="APP_NAME">%1$s</xliff:g>“ informaciją?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"„passkey“"</string>      <string name="password" msgid="6738570945182936667">"slaptažodis"</string>      <string name="passkeys" msgid="5733880786866559847">"prieigos raktas"</string> diff --git a/packages/CredentialManager/res/values-lv/strings.xml b/packages/CredentialManager/res/values-lv/strings.xml index 4da1051fe8fd..095fbeeea072 100644 --- a/packages/CredentialManager/res/values-lv/strings.xml +++ b/packages/CredentialManager/res/values-lv/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Vai izveidot piekļuves atslēgu, lai pierakstītos lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Vai saglabāt paroli, lai pierakstītos lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Vai saglabāt pierakstīšanās informāciju lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"piekļuves atslēga"</string>      <string name="password" msgid="6738570945182936667">"parole"</string>      <string name="passkeys" msgid="5733880786866559847">"piekļuves atslēgas"</string> @@ -93,6 +99,6 @@      <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"No citas ierīces"</string>      <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Izmantot citu ierīci"</string>      <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> atcēla pieprasījumu"</string> -    <string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"Pierakstīšanās iespējas"</string> +    <string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"Pierakstīšanās opcijas"</string>      <string name="more_options_content_description" msgid="1323427365788198808">"Vairāk"</string>  </resources> diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml index 95554a2330fb..0f22f6fc81fa 100644 --- a/packages/CredentialManager/res/values-mk/strings.xml +++ b/packages/CredentialManager/res/values-mk/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Да се создаде криптографски клуч за најавување на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Да се зачува лозинката за најавување на <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Да се зачуваат податоците за најавување за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"криптографски клуч"</string>      <string name="password" msgid="6738570945182936667">"лозинка"</string>      <string name="passkeys" msgid="5733880786866559847">"криптографски клучеви"</string> diff --git a/packages/CredentialManager/res/values-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml index eccfb511b16c..f7d74fe2b05a 100644 --- a/packages/CredentialManager/res/values-ml/strings.xml +++ b/packages/CredentialManager/res/values-ml/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിലേക്ക് സൈൻ ഇൻ ചെയ്യാൻ പാസ്കീ സൃഷ്ടിക്കണോ?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിലേക്ക് സൈൻ ഇൻ ചെയ്യാൻ പാസ്വേഡ് സംരക്ഷിക്കണോ?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി സൈൻ ഇൻ വിവരങ്ങൾ സംരക്ഷിക്കണോ?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി പാസ്കീ സൃഷ്ടിക്കാൻ നിങ്ങളുടെ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കണോ?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി പാസ്വേഡ് സൃഷ്ടിക്കാൻ നിങ്ങളുടെ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കണോ?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി സൈൻ ഇൻ വിവരങ്ങൾ സംരക്ഷിക്കാൻ നിങ്ങളുടെ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കണോ?"</string>      <string name="passkey" msgid="632353688396759522">"പാസ്കീ"</string>      <string name="password" msgid="6738570945182936667">"പാസ്വേഡ്"</string>      <string name="passkeys" msgid="5733880786866559847">"പാസ്കീകൾ"</string> diff --git a/packages/CredentialManager/res/values-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml index 5b1cbe90c63a..5554670b4d2d 100644 --- a/packages/CredentialManager/res/values-mn/strings.xml +++ b/packages/CredentialManager/res/values-mn/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д нэвтрэхийн тулд нэвтрэх түлхүүр үүсгэх үү?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д нэвтрэхийн тулд нууц үгийг хадгалах уу?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н нэвтрэх мэдээллийг хадгалах уу?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"passkey"</string>      <string name="password" msgid="6738570945182936667">"нууц үг"</string>      <string name="passkeys" msgid="5733880786866559847">"нэвтрэх түлхүүрүүд"</string> diff --git a/packages/CredentialManager/res/values-mr/strings.xml b/packages/CredentialManager/res/values-mr/strings.xml index a0a4a7de1146..ce415f5efd41 100644 --- a/packages/CredentialManager/res/values-mr/strings.xml +++ b/packages/CredentialManager/res/values-mr/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> मध्ये साइन इन करण्यासाठी पासकी तयार करायची आहे का?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> मध्ये साइन इन करण्यासाठी पासवर्ड सेव्ह करायचा आहे का?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> साठी साइन-इनसंबंधित माहिती सेव्ह करायची का?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"पासकी"</string>      <string name="password" msgid="6738570945182936667">"पासवर्ड"</string>      <string name="passkeys" msgid="5733880786866559847">"पासकी"</string> @@ -82,7 +88,7 @@      <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"दुसऱ्या मार्गाने साइन इन करा"</string>      <string name="snackbar_action" msgid="37373514216505085">"पर्याय पहा"</string>      <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"पुढे सुरू ठेवा"</string> -    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"साइन इन पर्याय"</string> +    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"साइन-इन पर्याय"</string>      <string name="button_label_view_more" msgid="3429098227286495651">"आणखी पहा"</string>      <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> साठी"</string>      <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"लॉक केलेले पासवर्ड व्यवस्थापक"</string> @@ -93,6 +99,6 @@      <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"दुसऱ्या डिव्हाइस वरून"</string>      <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"वेगळे डिव्हाइस वापरा"</string>      <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ने विनंती रद्द केली आहे"</string> -    <string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"साइन इन करण्याचे पर्याय"</string> +    <string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"साइन-इन पर्याय"</string>      <string name="more_options_content_description" msgid="1323427365788198808">"आणखी"</string>  </resources> diff --git a/packages/CredentialManager/res/values-ms/strings.xml b/packages/CredentialManager/res/values-ms/strings.xml index c866013d9478..62a7deb2f553 100644 --- a/packages/CredentialManager/res/values-ms/strings.xml +++ b/packages/CredentialManager/res/values-ms/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Buat kunci laluan untuk log masuk ke <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Simpan kata laluan untuk log masuk ke <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Simpan maklumat log masuk untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Gunakan kunci skrin anda untuk membuat kunci laluan bagi <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Gunakan kunci skrin anda untuk membuat kata laluan bagi <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Gunakan kunci skrin anda untuk menyimpan maklumat log masuk bagi <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"kunci laluan"</string>      <string name="password" msgid="6738570945182936667">"kata laluan"</string>      <string name="passkeys" msgid="5733880786866559847">"kunci laluan"</string> diff --git a/packages/CredentialManager/res/values-my/strings.xml b/packages/CredentialManager/res/values-my/strings.xml index a66e7b67c85e..5af7b72a48a6 100644 --- a/packages/CredentialManager/res/values-my/strings.xml +++ b/packages/CredentialManager/res/values-my/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> သို့ လက်မှတ်ထိုးဝင်ရန် လျှို့ဝှက်ကီး ပြုလုပ်မလား။"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> သို့ လက်မှတ်ထိုးဝင်ရန် စကားဝှက်ကို သိမ်းမလား။"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် လက်မှတ်ထိုးဝင်ရန် အချက်အလက်ကို သိမ်းမလား။"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"လျှို့ဝှက်ကီး"</string>      <string name="password" msgid="6738570945182936667">"စကားဝှက်"</string>      <string name="passkeys" msgid="5733880786866559847">"လျှို့ဝှက်ကီးများ"</string> diff --git a/packages/CredentialManager/res/values-nb/strings.xml b/packages/CredentialManager/res/values-nb/strings.xml index 7f4fa6ba8dfb..b6a679a49be6 100644 --- a/packages/CredentialManager/res/values-nb/strings.xml +++ b/packages/CredentialManager/res/values-nb/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Vil du opprette en passnøkkel for å logge på <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Vil du lagre passordet for å logge på <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Vil du lagre påloggingsinformasjon for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"passnøkkel"</string>      <string name="password" msgid="6738570945182936667">"passord"</string>      <string name="passkeys" msgid="5733880786866559847">"passnøkler"</string> diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml index 6e6947626ff0..161a16d6dbc5 100644 --- a/packages/CredentialManager/res/values-ne/strings.xml +++ b/packages/CredentialManager/res/values-ne/strings.xml @@ -22,8 +22,8 @@      <string name="string_continue" msgid="1346732695941131882">"जारी राख्नुहोस्"</string>      <string name="string_more_options" msgid="2763852250269945472">"अर्को तरिकाले सेभ गर्नुहोस्"</string>      <string name="string_learn_more" msgid="4541600451688392447">"थप जान्नुहोस्"</string> -    <string name="content_description_show_password" msgid="3283502010388521607">"पासवर्ड देखाइयोस्"</string> -    <string name="content_description_hide_password" msgid="6841375971631767996">"पासवर्ड लुकाइयोस्"</string> +    <string name="content_description_show_password" msgid="3283502010388521607">"पासवर्ड देखाउनुहोस्"</string> +    <string name="content_description_hide_password" msgid="6841375971631767996">"पासवर्ड लुकाउनुहोस्"</string>      <string name="passkey_creation_intro_title" msgid="4251037543787718844">"पासकीका सहायताले सुरक्षित रहनुहोस्"</string>      <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"तपाईंले पासकी बनाउनुभयो भने तपाईंले जटिल पासवर्ड बनाउनु वा तिनलाई याद गरिराख्नु पर्दैन"</string>      <string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"पासकी भनेको तपाईंले आफ्नो फिंगरप्रिन्ट, अनुहार वा स्क्रिन लक प्रयोग गरेर बनाएको इन्क्रिप्ट गरिएको डिजिटल की हो"</string> @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन इन गर्न पासकी बनाउने हो?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन इन गर्न पासवर्ड सेभ गर्ने हो?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन गर्न प्रयोग गरिने जानकारी सेभ गर्ने हो?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा पासकी बनाउन आफ्नो स्क्रिन लक प्रयोग गर्ने हो?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा पासवर्ड राख्न आफ्नो स्क्रिन लक प्रयोग गर्ने हो?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन इनसम्बन्धी जानकारी सेभ गर्न आफ्नो स्क्रिन लक प्रयोग गर्ने हो?"</string>      <string name="passkey" msgid="632353688396759522">"पासकी"</string>      <string name="password" msgid="6738570945182936667">"पासवर्ड"</string>      <string name="passkeys" msgid="5733880786866559847">"पासकीहरू"</string> diff --git a/packages/CredentialManager/res/values-nl/strings.xml b/packages/CredentialManager/res/values-nl/strings.xml index 50eefc7e5e9b..06ebc08d9725 100644 --- a/packages/CredentialManager/res/values-nl/strings.xml +++ b/packages/CredentialManager/res/values-nl/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Toegangssleutel maken om in te loggen bij <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Wachtwoord opslaan om in te loggen bij <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Inloggegevens opslaan voor <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"Toegangssleutel"</string>      <string name="password" msgid="6738570945182936667">"wachtwoord"</string>      <string name="passkeys" msgid="5733880786866559847">"toegangssleutels"</string> @@ -82,7 +88,7 @@      <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Op een andere manier inloggen"</string>      <string name="snackbar_action" msgid="37373514216505085">"Opties bekijken"</string>      <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Doorgaan"</string> -    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opties voor inloggen"</string> +    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Inlogopties"</string>      <string name="button_label_view_more" msgid="3429098227286495651">"Meer bekijken"</string>      <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Voor <xliff:g id="USERNAME">%1$s</xliff:g>"</string>      <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Vergrendelde wachtwoordmanagers"</string> @@ -93,6 +99,6 @@      <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Via een ander apparaat"</string>      <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Een ander apparaat gebruiken"</string>      <string name="request_cancelled_by" msgid="3735222326886267820">"Verzoek geannuleerd door <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> -    <string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"Opties voor inloggen"</string> +    <string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"Inlogopties"</string>      <string name="more_options_content_description" msgid="1323427365788198808">"Meer"</string>  </resources> diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml index 56e585d015bd..9781c49d945c 100644 --- a/packages/CredentialManager/res/values-or/strings.xml +++ b/packages/CredentialManager/res/values-or/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g>ରେ ସାଇନ ଇନ କରିବାକୁ ପାସକୀ ତିଆରି କରିବେ?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g>ରେ ସାଇନ ଇନ କରିବାକୁ ପାସୱାର୍ଡ ସେଭ କରିବେ?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ସାଇନ-ଇନର ସୂଚନା ସେଭ କରିବେ?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ଏକ ପାସକୀ ତିଆରି କରିବାକୁ ଆପଣଙ୍କ ସ୍କ୍ରିନ ଲକ ବ୍ୟବହାର କରିବେ?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ଏକ ପାସୱାର୍ଡ ତିଆରି କରିବାକୁ ଆପଣଙ୍କ ସ୍କ୍ରିନ ଲକ ବ୍ୟବହାର କରିବେ?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ସାଇନ ଇନ ସୂଚନା ସେଭ କରିବାକୁ ଆପଣଙ୍କ ସ୍କ୍ରିନ ଲକ ବ୍ୟବହାର କରିବେ?"</string>      <string name="passkey" msgid="632353688396759522">"ପାସକୀ"</string>      <string name="password" msgid="6738570945182936667">"ପାସୱାର୍ଡ"</string>      <string name="passkeys" msgid="5733880786866559847">"ପାସକୀଗୁଡ଼ିକ"</string> diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml index d23d20956b11..4cf8e17172c0 100644 --- a/packages/CredentialManager/res/values-pa/strings.xml +++ b/packages/CredentialManager/res/values-pa/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਵਿੱਚ ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਪਾਸਕੀ ਬਣਾਉਣੀ ਹੈ?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਵਿੱਚ ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਪਾਸਵਰਡ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਰੱਖਿਅਤ ਕਰਨੀ ਹੈ?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"ਪਾਸਕੀ"</string>      <string name="password" msgid="6738570945182936667">"ਪਾਸਵਰਡ"</string>      <string name="passkeys" msgid="5733880786866559847">"ਪਾਸਕੀਆਂ"</string> diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml index 5fa26b49a9e6..eca8699d0a55 100644 --- a/packages/CredentialManager/res/values-pl/strings.xml +++ b/packages/CredentialManager/res/values-pl/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Utworzyć klucz dostępu do logowania w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Zapisać hasło do logowania w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Zapisać dane używane do logowania w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Użyć metody odblokowania ekranu do utworzenia klucza dostępu do aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Użyć metody odblokowania ekranu do utworzenia hasła do aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Użyć metody odblokowania ekranu do zapisania danych logowania do aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"klucz"</string>      <string name="password" msgid="6738570945182936667">"hasło"</string>      <string name="passkeys" msgid="5733880786866559847">"klucze dostępu"</string> diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml index 994bc553102d..e49387143fef 100644 --- a/packages/CredentialManager/res/values-pt-rBR/strings.xml +++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Criar chave de acesso para fazer login no app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Salvar senha para fazer login no app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Salvar informações de login do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"chave de acesso"</string>      <string name="password" msgid="6738570945182936667">"senha"</string>      <string name="passkeys" msgid="5733880786866559847">"chaves de acesso"</string> diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml index 26c6491ad591..8b6b2b2e6450 100644 --- a/packages/CredentialManager/res/values-pt-rPT/strings.xml +++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Criar a chave de acesso para iniciar sessão na app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Guardar a palavra-passe para iniciar sessão na app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Guardar as informações de início de sessão da app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Usar o bloqueio de ecrã para criar uma chave de acesso para a app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Usar o bloqueio de ecrã para criar uma palavra-passe para a app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Usar o bloqueio de ecrã para guardar as informações de início de sessão para a app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"chave de acesso"</string>      <string name="password" msgid="6738570945182936667">"palavra-passe"</string>      <string name="passkeys" msgid="5733880786866559847">"chaves de acesso"</string> diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml index 994bc553102d..e49387143fef 100644 --- a/packages/CredentialManager/res/values-pt/strings.xml +++ b/packages/CredentialManager/res/values-pt/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Criar chave de acesso para fazer login no app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Salvar senha para fazer login no app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Salvar informações de login do app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"chave de acesso"</string>      <string name="password" msgid="6738570945182936667">"senha"</string>      <string name="passkeys" msgid="5733880786866559847">"chaves de acesso"</string> diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml index 342b6ab77e8b..87b551b62f22 100644 --- a/packages/CredentialManager/res/values-ro/strings.xml +++ b/packages/CredentialManager/res/values-ro/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Creezi o cheie de acces pentru a te conecta la <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Salvezi parola pentru a te conecta la <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Salvezi informațiile de conectare pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"cheia de acces"</string>      <string name="password" msgid="6738570945182936667">"parolă"</string>      <string name="passkeys" msgid="5733880786866559847">"cheile de acces"</string> @@ -89,7 +95,7 @@      <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Atinge pentru a debloca"</string>      <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Fără informații de conectare"</string>      <string name="no_sign_in_info_in" msgid="2641118151920288356">"Nu există informații de conectare în contul <xliff:g id="SOURCE">%1$s</xliff:g>"</string> -    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestionează acreditările"</string> +    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestionează conectările"</string>      <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De pe alt dispozitiv"</string>      <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Folosește alt dispozitiv"</string>      <string name="request_cancelled_by" msgid="3735222326886267820">"Solicitare anulată de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-ru/strings.xml b/packages/CredentialManager/res/values-ru/strings.xml index e4726957d650..c9c8dcccfbf0 100644 --- a/packages/CredentialManager/res/values-ru/strings.xml +++ b/packages/CredentialManager/res/values-ru/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Создать ключ доступа для входа в приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Сохранить пароль для входа в приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Сохранить данные для входа в приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Использовать способ разблокировки экрана, чтобы создать ключ доступа для приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Использовать способ разблокировки экрана, чтобы создать пароль для приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Использовать способ разблокировки экрана, чтобы сохранить данные для входа в приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>      <string name="passkey" msgid="632353688396759522">"ключ доступа"</string>      <string name="password" msgid="6738570945182936667">"пароль"</string>      <string name="passkeys" msgid="5733880786866559847">"ключи доступа"</string> diff --git a/packages/CredentialManager/res/values-si/strings.xml b/packages/CredentialManager/res/values-si/strings.xml index ce0b9cd048eb..ab78c062bba1 100644 --- a/packages/CredentialManager/res/values-si/strings.xml +++ b/packages/CredentialManager/res/values-si/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> වෙත පුරනය වීමට මුරයතුරක් තනන්න ද?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> වෙත පුරනය වීමට මුරපදය සුරකින්න ද?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා පුරනය වීමේ තතු සුරකින්න ද?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"මුරයතුර"</string>      <string name="password" msgid="6738570945182936667">"මුරපදය"</string>      <string name="passkeys" msgid="5733880786866559847">"මුරයතුරු"</string> diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml index 62a2e690edae..c2626eaebeca 100644 --- a/packages/CredentialManager/res/values-sk/strings.xml +++ b/packages/CredentialManager/res/values-sk/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Chcete vytvoriť prístupový kľúč na prihlasovanie do aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Chcete uložiť heslo na prihlasovanie do aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Chcete uložiť prihlasovacie údaje pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Chcete pomocou zámky obrazovky vytvoriť prístupový kľúč pre <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Chcete pomocou zámky obrazovky vytvoriť heslo pre <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Chcete pomocou zámky obrazovky uložiť prihlasovacie údaje pre <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"prístupový kľúč"</string>      <string name="password" msgid="6738570945182936667">"heslo"</string>      <string name="passkeys" msgid="5733880786866559847">"prístupové kľúče"</string> diff --git a/packages/CredentialManager/res/values-sl/strings.xml b/packages/CredentialManager/res/values-sl/strings.xml index d2aaf685032a..79c8c72d2f94 100644 --- a/packages/CredentialManager/res/values-sl/strings.xml +++ b/packages/CredentialManager/res/values-sl/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Želite ustvariti ključ za dostop za prijavo v aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Želite shraniti geslo za prijavo v aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Želite shraniti podatke za prijavo za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Želite uporabiti zaklepanje zaslona za ustvarjanje ključa za dostop za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Želite uporabiti zaklepanje zaslona za ustvarjanje gesla za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Želite uporabiti zaklepanje zaslona za shranjevanje podatkov za prijavo za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"ključ za dostop"</string>      <string name="password" msgid="6738570945182936667">"geslo"</string>      <string name="passkeys" msgid="5733880786866559847">"ključi za dostop"</string> diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml index f31d16aabe1e..8038cea71aed 100644 --- a/packages/CredentialManager/res/values-sq/strings.xml +++ b/packages/CredentialManager/res/values-sq/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Të krijohet një çelës kalimi për t\'u identifikuar në <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Të ruhet fjalëkalimi për t\'u identifikuar në <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Të ruhen informacionet e identifikimit për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"çelësin e kalimit"</string>      <string name="password" msgid="6738570945182936667">"fjalëkalimi"</string>      <string name="passkeys" msgid="5733880786866559847">"çelësat e kalimit"</string> @@ -89,7 +95,7 @@      <string name="locked_credential_entry_label_subtext_tap_to_unlock" msgid="6390367581393605009">"Trokit për të shkyçur"</string>      <string name="locked_credential_entry_label_subtext_no_sign_in" msgid="8131725029983174901">"Nuk ka informacione për identifikimin"</string>      <string name="no_sign_in_info_in" msgid="2641118151920288356">"Nuk ka informacione regjistrimi në <xliff:g id="SOURCE">%1$s</xliff:g>"</string> -    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Identifikimet e menaxhimit"</string> +    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Menaxho identifikimet"</string>      <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Nga një pajisje tjetër"</string>      <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Përdor një pajisje tjetër"</string>      <string name="request_cancelled_by" msgid="3735222326886267820">"Kërkesa u anulua nga <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml index e68a20cc4f3b..58110aacdc36 100644 --- a/packages/CredentialManager/res/values-sr/strings.xml +++ b/packages/CredentialManager/res/values-sr/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Желите да направите приступни кључ да бисте се пријавили у <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Желите да сачувате лозинку да бисте се пријавили у <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Желите да сачувате податке за пријављивање за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Желите да користите откључавање екрана да бисте направили приступни кључ за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Желите да користите откључавање екрана да бисте направили лозинку за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Желите да користите откључавање екрана да бисте сачували податке за пријављивање за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"приступни кôд"</string>      <string name="password" msgid="6738570945182936667">"лозинка"</string>      <string name="passkeys" msgid="5733880786866559847">"приступни кодови"</string> diff --git a/packages/CredentialManager/res/values-sv/strings.xml b/packages/CredentialManager/res/values-sv/strings.xml index e18fea1049ea..6379df248b8d 100644 --- a/packages/CredentialManager/res/values-sv/strings.xml +++ b/packages/CredentialManager/res/values-sv/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Vill du skapa en nyckel för att logga in i <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Vill du spara lösenordet för att logga in i <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Vill du spara inloggningsuppgifterna för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"nyckel"</string>      <string name="password" msgid="6738570945182936667">"lösenord"</string>      <string name="passkeys" msgid="5733880786866559847">"nycklar"</string> diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml index 65672d5696ef..888b01c7550c 100644 --- a/packages/CredentialManager/res/values-sw/strings.xml +++ b/packages/CredentialManager/res/values-sw/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Ungependa kubuni ufunguo wa siri wa kuingia katika akaunti ya <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Ungependa kuhifadhi nenosiri la kuingia katika akaunti ya <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Ungependa kuhifadhi maelezo ya kuingia katika akaunti ya <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Ungependa kutumia mbinu yako ya kufunga skrini kubuni ufunguo wa siri wa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Ungependa kutumia mbinu yako ya kufunga skrini kubuni nenosiri la <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Ungependa kutumia mbinu yako ya kufunga skrini kuhifadhi maelezo ya kuingia katika akaunti ya <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"ufunguo wa siri"</string>      <string name="password" msgid="6738570945182936667">"nenosiri"</string>      <string name="passkeys" msgid="5733880786866559847">"funguo za siri"</string> diff --git a/packages/CredentialManager/res/values-ta/strings.xml b/packages/CredentialManager/res/values-ta/strings.xml index 49d17101abb2..008baaba0ec9 100644 --- a/packages/CredentialManager/res/values-ta/strings.xml +++ b/packages/CredentialManager/res/values-ta/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸில் உள்நுழைய கடவுச்சாவியை உருவாக்கவா?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸில் உள்நுழைய கடவுச்சொல்லைச் சேமிக்கவா?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கான உள்நுழைவுத் தகவலைச் சேமிக்கவா?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"கடவுச்சாவி"</string>      <string name="password" msgid="6738570945182936667">"கடவுச்சொல்"</string>      <string name="passkeys" msgid="5733880786866559847">"கடவுச்சாவிகள்"</string> diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml index 742a42279169..e2e362bb37aa 100644 --- a/packages/CredentialManager/res/values-te/strings.xml +++ b/packages/CredentialManager/res/values-te/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g>కు సైన్ ఇన్ చేయడానికి పాస్-కీని క్రియేట్ చేయాలా?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g>కు సైన్ ఇన్ చేయడానికి పాస్వర్డ్ను సేవ్ చేయాలా?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం సైన్ ఇన్ సమాచారాన్ని సేవ్ చేయాలా?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"మీ స్క్రీన్ లాక్ను ఉపయోగించి <xliff:g id="APP_NAME">%1$s</xliff:g>కు పాస్-కీని క్రియేట్ చేయాలా?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"మీ స్క్రీన్ లాక్ను ఉపయోగించి <xliff:g id="APP_NAME">%1$s</xliff:g>కు పాస్వర్డ్ను క్రియేట్ చేయాలా?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"మీ స్క్రీన్ లాక్ను ఉపయోగించి <xliff:g id="APP_NAME">%1$s</xliff:g>కు సంబంధించిన సైన్-ఇన్ సమాచారాన్ని సేవ్ చేయాలా?"</string>      <string name="passkey" msgid="632353688396759522">"పాస్-కీ"</string>      <string name="password" msgid="6738570945182936667">"పాస్వర్డ్"</string>      <string name="passkeys" msgid="5733880786866559847">"పాస్-కీలు"</string> diff --git a/packages/CredentialManager/res/values-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml index 3f9de268ecf4..876371a9c7f5 100644 --- a/packages/CredentialManager/res/values-th/strings.xml +++ b/packages/CredentialManager/res/values-th/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"สร้างพาสคีย์เพื่อลงชื่อเข้าใช้ <xliff:g id="APP_NAME">%1$s</xliff:g> ไหม"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"บันทึกรหัสผ่านเพื่อลงชื่อเข้าใช้ <xliff:g id="APP_NAME">%1$s</xliff:g> ไหม"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"บันทึกข้อมูลการลงชื่อเข้าใช้สำหรับ <xliff:g id="APP_NAME">%1$s</xliff:g> ไหม"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"ต้องการใช้ฟีเจอร์ล็อกหน้าจอเพื่อสร้างพาสคีย์สำหรับ <xliff:g id="APP_NAME">%1$s</xliff:g> ใช่ไหม"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"ต้องการใช้ฟีเจอร์ล็อกหน้าจอเพื่อสร้างรหัสผ่านสำหรับ <xliff:g id="APP_NAME">%1$s</xliff:g> ใช่ไหม"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"ต้องการใช้ฟีเจอร์ล็อกหน้าจอเพื่อบันทึกข้อมูลการลงชื่อเข้าใช้สำหรับ <xliff:g id="APP_NAME">%1$s</xliff:g> ใช่ไหม"</string>      <string name="passkey" msgid="632353688396759522">"พาสคีย์"</string>      <string name="password" msgid="6738570945182936667">"รหัสผ่าน"</string>      <string name="passkeys" msgid="5733880786866559847">"พาสคีย์"</string> diff --git a/packages/CredentialManager/res/values-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml index 659c1ec031b0..163e93aaf4f9 100644 --- a/packages/CredentialManager/res/values-tl/strings.xml +++ b/packages/CredentialManager/res/values-tl/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Gumawa ng passkey para mag-sign in sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"I-save ang password para mag-sign in sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"I-save ang impormasyon sa pag-sign in para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"Gamitin ang iyong lock ng screen para gumawa ng passkey para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"Gamitin ang iyong lock ng screen para gumawa ng password para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"Gamitin ang iyong lock ng screen para mag-save ng impormasyon sa pag-sign in para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="passkey" msgid="632353688396759522">"passkey"</string>      <string name="password" msgid="6738570945182936667">"password"</string>      <string name="passkeys" msgid="5733880786866559847">"mga passkey"</string> diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml index 5139a6789f7a..96a1c0083fa5 100644 --- a/packages/CredentialManager/res/values-tr/strings.xml +++ b/packages/CredentialManager/res/values-tr/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasında oturum açmak için geçiş anahtarı oluşturulsun mu?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasında oturum açmak için şifre kaydedilsin mi?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> için oturum açma bilgileri kaydedilsin mi?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"Geçiş anahtarı"</string>      <string name="password" msgid="6738570945182936667">"Şifre"</string>      <string name="passkeys" msgid="5733880786866559847">"Geçiş anahtarlarınızın"</string> diff --git a/packages/CredentialManager/res/values-uk/strings.xml b/packages/CredentialManager/res/values-uk/strings.xml index 62eac9afc737..b867903855a5 100644 --- a/packages/CredentialManager/res/values-uk/strings.xml +++ b/packages/CredentialManager/res/values-uk/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Створити ключ доступу для входу в додаток <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Зберегти пароль для входу в додаток <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Зберегти дані для входу для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"ключ доступу"</string>      <string name="password" msgid="6738570945182936667">"пароль"</string>      <string name="passkeys" msgid="5733880786866559847">"ключі доступу"</string> diff --git a/packages/CredentialManager/res/values-ur/strings.xml b/packages/CredentialManager/res/values-ur/strings.xml index 9fad27318f80..67cf20ae7ae2 100644 --- a/packages/CredentialManager/res/values-ur/strings.xml +++ b/packages/CredentialManager/res/values-ur/strings.xml @@ -42,6 +42,9 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> میں سائن ان کرنے کیلئے پاس کی تخلیق کریں؟"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> میں سائن ان کرنے کیلئے پاس ورڈ محفوظ کریں؟"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے سائن ان کی معلومات محفوظ کریں؟"</string> +    <string name="choose_create_single_tap_passkey_title" msgid="3872793514041774218">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے پاس کی بنانے کے لیے اپنا اسکرین لاک استعمال کریں؟"</string> +    <string name="choose_create_single_tap_password_title" msgid="5231871886818921622">"<xliff:g id="APP_NAME">%1$s</xliff:g> کا پاس ورڈ بنانے کے لیے اپنا اسکرین لاک استعمال کریں؟"</string> +    <string name="choose_create_single_tap_sign_in_title" msgid="256498714574099587">"<xliff:g id="APP_NAME">%1$s</xliff:g> کی سائن ان کی معلومات محفوظ کرنے کے لیے اپنا اسکرین لاک استعمال کریں؟"</string>      <string name="passkey" msgid="632353688396759522">"پاس کی"</string>      <string name="password" msgid="6738570945182936667">"پاس ورڈ"</string>      <string name="passkeys" msgid="5733880786866559847">"پاس کیز"</string> diff --git a/packages/CredentialManager/res/values-uz/strings.xml b/packages/CredentialManager/res/values-uz/strings.xml index a3d20250a249..796bd87e76e6 100644 --- a/packages/CredentialManager/res/values-uz/strings.xml +++ b/packages/CredentialManager/res/values-uz/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga kirish uchun kirish kaliti yaratilsinmi?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasiga kirish uchun parol saqlansinmi?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun kirish maʼlumoti saqlansinmi?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"kalit"</string>      <string name="password" msgid="6738570945182936667">"parol"</string>      <string name="passkeys" msgid="5733880786866559847">"kalitlar"</string> diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml index da04efd82896..59bd541061b4 100644 --- a/packages/CredentialManager/res/values-vi/strings.xml +++ b/packages/CredentialManager/res/values-vi/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Tạo khoá truy cập để đăng nhập vào <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Lưu mật khẩu để đăng nhập vào <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Lưu thông tin đăng nhập cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"khoá đăng nhập"</string>      <string name="password" msgid="6738570945182936667">"mật khẩu"</string>      <string name="passkeys" msgid="5733880786866559847">"khoá truy cập"</string> @@ -82,7 +88,7 @@      <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Đăng nhập bằng cách khác"</string>      <string name="snackbar_action" msgid="37373514216505085">"Xem các lựa chọn"</string>      <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Tiếp tục"</string> -    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Tuỳ chọn đăng nhập"</string> +    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Lựa chọn đăng nhập"</string>      <string name="button_label_view_more" msgid="3429098227286495651">"Xem thêm"</string>      <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Cho <xliff:g id="USERNAME">%1$s</xliff:g>"</string>      <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Trình quản lý mật khẩu đã khoá"</string> diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml index 968e978801d4..e9ac45a73088 100644 --- a/packages/CredentialManager/res/values-zh-rCN/strings.xml +++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"要创建通行密钥以便登录“<xliff:g id="APP_NAME">%1$s</xliff:g>”吗?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"要保存密码以便登录“<xliff:g id="APP_NAME">%1$s</xliff:g>”吗?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"要保存“<xliff:g id="APP_NAME">%1$s</xliff:g>”的登录信息吗?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"通行密钥"</string>      <string name="password" msgid="6738570945182936667">"密码"</string>      <string name="passkeys" msgid="5733880786866559847">"通行密钥"</string> diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml index 7a375c9c7aea..77855b51c7c4 100644 --- a/packages/CredentialManager/res/values-zh-rHK/strings.xml +++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"要建立密鑰以登入 <xliff:g id="APP_NAME">%1$s</xliff:g> 嗎?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"要儲存密碼以登入 <xliff:g id="APP_NAME">%1$s</xliff:g> 嗎?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"要儲存 <xliff:g id="APP_NAME">%1$s</xliff:g> 的登入資料嗎?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"密鑰"</string>      <string name="password" msgid="6738570945182936667">"密碼"</string>      <string name="passkeys" msgid="5733880786866559847">"密鑰"</string> diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml index 029908872a71..520d9a8049e7 100644 --- a/packages/CredentialManager/res/values-zh-rTW/strings.xml +++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"要建立用於登入「<xliff:g id="APP_NAME">%1$s</xliff:g>」的密碼金鑰嗎?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"要儲存用於登入「<xliff:g id="APP_NAME">%1$s</xliff:g>」的密碼嗎?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"要儲存「<xliff:g id="APP_NAME">%1$s</xliff:g>」的登入資訊嗎?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"密碼金鑰"</string>      <string name="password" msgid="6738570945182936667">"密碼"</string>      <string name="passkeys" msgid="5733880786866559847">"密碼金鑰"</string> diff --git a/packages/CredentialManager/res/values-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml index 4f888f42b686..8cb25cb2ce9c 100644 --- a/packages/CredentialManager/res/values-zu/strings.xml +++ b/packages/CredentialManager/res/values-zu/strings.xml @@ -42,6 +42,12 @@      <string name="choose_create_option_passkey_title" msgid="8762295821604276511">"Sungula ukhiye wokudlula ukuze ungene ngemvume ku-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_password_title" msgid="4481366993598649224">"Londoloza iphasiwedi ukuze ungene ngemvume ku-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="choose_create_option_sign_in_title" msgid="7092914088455358079">"Londoloza ulwazi lokungena lwe-<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string> +    <!-- no translation found for choose_create_single_tap_passkey_title (3872793514041774218) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_password_title (5231871886818921622) --> +    <skip /> +    <!-- no translation found for choose_create_single_tap_sign_in_title (256498714574099587) --> +    <skip />      <string name="passkey" msgid="632353688396759522">"ukhiye wokudlula"</string>      <string name="password" msgid="6738570945182936667">"iphasiwedi"</string>      <string name="passkeys" msgid="5733880786866559847">"okhiye bokudlula"</string> diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt index b408c1553d94..9c8ec3b56813 100644 --- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt +++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt @@ -142,7 +142,7 @@ private fun getCredentialOptionInfoList(                      isDefaultIconPreferredAsSingleProvider =                              credentialEntry.isDefaultIconPreferredAsSingleProvider,                      affiliatedDomain = credentialEntry.affiliatedDomain?.toString(), -                    biometricRequest = predetermineAndValidateBiometricFlow(it, +                    biometricRequest = retrieveEntryBiometricRequest(it,                          CREDENTIAL_ENTRY_PREFIX),                  )                  ) @@ -172,7 +172,7 @@ private fun getCredentialOptionInfoList(                      isDefaultIconPreferredAsSingleProvider =                              credentialEntry.isDefaultIconPreferredAsSingleProvider,                      affiliatedDomain = credentialEntry.affiliatedDomain?.toString(), -                    biometricRequest = predetermineAndValidateBiometricFlow(it, +                    biometricRequest = retrieveEntryBiometricRequest(it,                          CREDENTIAL_ENTRY_PREFIX),                  )                  ) @@ -201,7 +201,7 @@ private fun getCredentialOptionInfoList(                      isDefaultIconPreferredAsSingleProvider =                              credentialEntry.isDefaultIconPreferredAsSingleProvider,                      affiliatedDomain = credentialEntry.affiliatedDomain?.toString(), -                    biometricRequest = predetermineAndValidateBiometricFlow(it, +                    biometricRequest = retrieveEntryBiometricRequest(it,                          CREDENTIAL_ENTRY_PREFIX),                  )                  ) @@ -216,7 +216,7 @@ private fun getCredentialOptionInfoList(  }  /** - * This validates if this is a biometric flow or not, and if it is, this returns the expected + * This validates if the entry calling this method contains biometric info, and if so, returns a   * [BiometricRequestInfo]. Namely, the biometric flow must have at least the   * ALLOWED_AUTHENTICATORS bit passed from Jetpack.   * Note that the required values, such as the provider info's icon or display name, or the entries @@ -230,7 +230,7 @@ private fun getCredentialOptionInfoList(   * // TODO(b/326243754) : Presently, due to dependencies, the opId bit is parsed but is never   * // expected to be used. When it is added, it should be lightly validated.   */ -fun predetermineAndValidateBiometricFlow( +fun retrieveEntryBiometricRequest(      entry: Entry,      hintPrefix: String,  ): BiometricRequestInfo? { diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt index a03975375e8a..888777e81d65 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt @@ -30,6 +30,8 @@ import androidx.compose.runtime.getValue  import androidx.compose.runtime.mutableStateOf  import androidx.compose.runtime.setValue  import androidx.lifecycle.ViewModel +import com.android.credentialmanager.common.BiometricFlowType +import com.android.credentialmanager.common.BiometricPromptState  import com.android.credentialmanager.common.BiometricResult  import com.android.credentialmanager.common.BiometricState  import com.android.credentialmanager.model.EntryInfo @@ -40,7 +42,7 @@ import com.android.credentialmanager.common.ProviderActivityState  import com.android.credentialmanager.createflow.ActiveEntry  import com.android.credentialmanager.createflow.CreateCredentialUiState  import com.android.credentialmanager.createflow.CreateScreenState -import com.android.credentialmanager.createflow.findBiometricFlowEntry +import com.android.credentialmanager.createflow.isBiometricFlow  import com.android.credentialmanager.getflow.GetCredentialUiState  import com.android.credentialmanager.getflow.GetScreenState  import com.android.credentialmanager.logging.LifecycleEvent @@ -303,13 +305,23 @@ class CredentialSelectorViewModel(      }      fun createFlowOnEntrySelectedFromMoreOptionScreen(activeEntry: ActiveEntry) { +        val isBiometricFlow = isBiometricFlow(activeEntry = activeEntry, isAutoSelectFlow = false) +        if (isBiometricFlow) { +            // This atomically ensures that the only edge case that *restarts* the biometric flow +            // doesn't risk a configuration change bug on the more options page during create. +            // Namely, it's atomic in that it happens only on a tap, and it is not possible to +            // reproduce a tap and a rotation at the same time. However, even if it were, it would +            // just be an alternate way to jump back into the biometric selection flow after this +            // reset, and thus, the state machine is maintained. +            onBiometricPromptStateChange(BiometricPromptState.INACTIVE) +        }          uiState = uiState.copy(              createCredentialUiState = uiState.createCredentialUiState?.copy(                  currentScreenState =                  // An autoselect flow never makes it to the more options screen -                if (findBiometricFlowEntry(activeEntry = activeEntry, -                        isAutoSelectFlow = false) != null) CreateScreenState.BIOMETRIC_SELECTION -                else if ( +                if (isBiometricFlow) { +                    CreateScreenState.BIOMETRIC_SELECTION +                } else if (                      uiState.createCredentialUiState?.requestDisplayInfo?.userSetDefaultProviderIds                          ?.contains(activeEntry.activeProvider.id) ?: true ||                      !(uiState.createCredentialUiState?.foundCandidateFromUserDefaultProvider @@ -375,6 +387,46 @@ class CredentialSelectorViewModel(          }      } +    /**************************************************************************/ +    /*****                     Biometric Flow Callbacks                   *****/ +    /**************************************************************************/ + +    /** +     * This allows falling back from the biometric prompt screen to the normal get flow by applying +     * a reset to all necessary states involved in the fallback. +     */ +    fun fallbackFromBiometricToNormalFlow(biometricFlowType: BiometricFlowType) { +        onBiometricPromptStateChange(BiometricPromptState.INACTIVE) +        when (biometricFlowType) { +            BiometricFlowType.GET -> getFlowOnBackToPrimarySelectionScreen() +            BiometricFlowType.CREATE -> createFlowOnUseOnceSelected() +        } +    } + +    /** +     * This method can be used to change the [BiometricPromptState] according to the necessity. +     * For example, if resetting, one might use [BiometricPromptState.INACTIVE], but if the flow +     * has just launched, to avoid configuration errors, one can use +     * [BiometricPromptState.PENDING]. +     */ +    fun onBiometricPromptStateChange(biometricPromptState: BiometricPromptState) { +        uiState = uiState.copy( +            biometricState = uiState.biometricState.copy( +                biometricStatus = biometricPromptState +            ) +        ) +    } + +    /** +     * This returns the present biometric state. +     */ +    fun getBiometricPromptState(): BiometricPromptState = +        uiState.biometricState.biometricStatus + +    /**************************************************************************/ +    /*****                     Misc. Callbacks/Logs                       *****/ +    /**************************************************************************/ +      @Composable      fun logUiEvent(uiEventEnum: UiEventEnum) {          this.uiMetrics.log(uiEventEnum, credManRepo.requestInfo?.packageName) diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt index 358ebfa1ec90..c477f30a1d2f 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt @@ -53,8 +53,9 @@ import androidx.credentials.provider.RemoteEntry  import org.json.JSONObject  import android.credentials.flags.Flags  import com.android.credentialmanager.createflow.isBiometricFlow +import com.android.credentialmanager.createflow.isFlowAutoSelectable  import com.android.credentialmanager.getflow.TopBrandingContent -import com.android.credentialmanager.ktx.predetermineAndValidateBiometricFlow +import com.android.credentialmanager.ktx.retrieveEntryBiometricRequest  import java.time.Instant  fun getAppLabel( @@ -431,7 +432,12 @@ class CreateFlowUtils {                  remoteEntryProvider = remoteEntryProvider,              )              val isBiometricFlow = if (activeEntry == null) false else isBiometricFlow(activeEntry, -                sortedCreateOptionsPairs, requestDisplayInfo) +                isFlowAutoSelectable( +                    requestDisplayInfo = requestDisplayInfo, +                    activeEntry = activeEntry, +                    sortedCreateOptionsPairs = sortedCreateOptionsPairs +                ) +            )              val initialScreenState = toCreateScreenState(                  createOptionSize = createOptionsPairs.size,                  remoteEntry = remoteEntry, @@ -514,7 +520,7 @@ class CreateFlowUtils {                          it.hasHint("androidx.credentials.provider.createEntry.SLICE_HINT_AUTO_" +                              "SELECT_ALLOWED")                      }?.text == "true", -                    biometricRequest = predetermineAndValidateBiometricFlow(it, +                    biometricRequest = retrieveEntryBiometricRequest(it,                          CREATE_ENTRY_PREFIX),                  )                  ) diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricFlowType.kt index f6140f51b7b5..263cfd574d73 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/FlowType.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricFlowType.kt @@ -16,7 +16,7 @@  package com.android.credentialmanager.common -enum class FlowType { +enum class BiometricFlowType {      GET,      CREATE  }
\ No newline at end of file diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt index fa177351be30..be3e0437a83e 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt @@ -59,7 +59,7 @@ import java.lang.Exception   * ).   *   * The above are examples; the credential type can change depending on scenario. - * // TODO(b/326243891) : Finalize once all the strings and create flow is iterated to completion + * // TODO(b/333445112) : Finalize once all the strings and create flow is iterated to completion   */  data class BiometricDisplayInfo(      val providerIcon: Bitmap, @@ -75,7 +75,8 @@ data class BiometricDisplayInfo(   * additional states that may improve the flow.   */  data class BiometricState( -    val biometricResult: BiometricResult? = null +    val biometricResult: BiometricResult? = null, +    val biometricStatus: BiometricPromptState = BiometricPromptState.INACTIVE  )  /** @@ -104,58 +105,115 @@ data class BiometricHelp(  )  /** - * This will handle the logic for integrating credential manager with the biometric prompt for the - * single account biometric experience. This simultaneously handles both the get and create flows, - * by retrieving all the data from credential manager, and properly parsing that data into the - * biometric prompt. + * This is the entry point to start the integrated biometric prompt for 'get' flows. It captures + * information specific to the get flow, along with required shared callbacks and more general + * info across both flows, such as the tapped [EntryInfo] or [sendDataToProvider].   */ -fun runBiometricFlow( +fun runBiometricFlowForGet(      biometricEntry: EntryInfo,      context: Context,      openMoreOptionsPage: () -> Unit,      sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit,      onCancelFlowAndFinish: () -> Unit,      onIllegalStateAndFinish: (String) -> Unit, +    getBiometricPromptState: () -> BiometricPromptState, +    onBiometricPromptStateChange: (BiometricPromptState) -> Unit, +    onBiometricFailureFallback: (BiometricFlowType) -> Unit,      getRequestDisplayInfo: RequestDisplayInfo? = null,      getProviderInfoList: List<ProviderInfo>? = null,      getProviderDisplayInfo: ProviderDisplayInfo? = null, -    onBiometricFailureFallback: () -> Unit, +) { +    if (getBiometricPromptState() != BiometricPromptState.INACTIVE) { +        // Screen is already up, do not re-launch +        return +    } +    onBiometricPromptStateChange(BiometricPromptState.PENDING) +    val biometricDisplayInfo = validateAndRetrieveBiometricGetDisplayInfo( +        getRequestDisplayInfo, +        getProviderInfoList, +        getProviderDisplayInfo, +        context, biometricEntry +    ) + +    if (biometricDisplayInfo == null) { +        onBiometricFailureFallback(BiometricFlowType.GET) +        return +    } + +    val callback: BiometricPrompt.AuthenticationCallback = +        setupBiometricAuthenticationCallback(sendDataToProvider, biometricEntry, +            onCancelFlowAndFinish, onIllegalStateAndFinish, onBiometricPromptStateChange) + +    Log.d(TAG, "The BiometricPrompt API call begins.") +    runBiometricFlow(context, biometricDisplayInfo, callback, openMoreOptionsPage, +        onBiometricFailureFallback, BiometricFlowType.GET) +} + +/** + * This is the entry point to start the integrated biometric prompt for 'create' flows. It captures + * information specific to the create flow, along with required shared callbacks and more general + * info across both flows, such as the tapped [EntryInfo] or [sendDataToProvider]. + */ +fun runBiometricFlowForCreate( +    biometricEntry: EntryInfo, +    context: Context, +    openMoreOptionsPage: () -> Unit, +    sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit, +    onCancelFlowAndFinish: () -> Unit, +    onIllegalStateAndFinish: (String) -> Unit, +    getBiometricPromptState: () -> BiometricPromptState, +    onBiometricPromptStateChange: (BiometricPromptState) -> Unit, +    onBiometricFailureFallback: (BiometricFlowType) -> Unit,      createRequestDisplayInfo: com.android.credentialmanager.createflow      .RequestDisplayInfo? = null,      createProviderInfo: EnabledProviderInfo? = null,  ) { -    // TODO(b/330396089) : Add rotation configuration fix with state machine -    var biometricDisplayInfo: BiometricDisplayInfo? = null -    var flowType = FlowType.GET -    if (getRequestDisplayInfo != null) { -        biometricDisplayInfo = validateAndRetrieveBiometricGetDisplayInfo(getRequestDisplayInfo, -            getProviderInfoList, -            getProviderDisplayInfo, -            context, biometricEntry) -    } else if (createRequestDisplayInfo != null) { -        flowType = FlowType.CREATE -        biometricDisplayInfo = validateAndRetrieveBiometricCreateDisplayInfo( -            createRequestDisplayInfo, -            createProviderInfo, -            context, biometricEntry) +    if (getBiometricPromptState() != BiometricPromptState.INACTIVE) { +        // Screen is already up, do not re-launch +        return      } +    onBiometricPromptStateChange(BiometricPromptState.PENDING) +    val biometricDisplayInfo = validateAndRetrieveBiometricCreateDisplayInfo( +        createRequestDisplayInfo, +        createProviderInfo, +        context, biometricEntry +    )      if (biometricDisplayInfo == null) { -        onBiometricFailureFallback() +        onBiometricFailureFallback(BiometricFlowType.CREATE)          return      } -    val biometricPrompt = setupBiometricPrompt(context, biometricDisplayInfo, openMoreOptionsPage, -        biometricDisplayInfo.biometricRequestInfo.allowedAuthenticators, flowType) -      val callback: BiometricPrompt.AuthenticationCallback =          setupBiometricAuthenticationCallback(sendDataToProvider, biometricEntry, -            onCancelFlowAndFinish, onIllegalStateAndFinish) +            onCancelFlowAndFinish, onIllegalStateAndFinish, onBiometricPromptStateChange) + +    Log.d(TAG, "The BiometricPrompt API call begins.") +    runBiometricFlow(context, biometricDisplayInfo, callback, openMoreOptionsPage, +        onBiometricFailureFallback, BiometricFlowType.CREATE) +} + +/** + * This will handle the logic for integrating credential manager with the biometric prompt for the + * single account biometric experience. This simultaneously handles both the get and create flows, + * by retrieving all the data from credential manager, and properly parsing that data into the + * biometric prompt. + */ +private fun runBiometricFlow( +    context: Context, +    biometricDisplayInfo: BiometricDisplayInfo, +    callback: BiometricPrompt.AuthenticationCallback, +    openMoreOptionsPage: () -> Unit, +    onBiometricFailureFallback: (BiometricFlowType) -> Unit, +    biometricFlowType: BiometricFlowType +) { +    val biometricPrompt = setupBiometricPrompt(context, biometricDisplayInfo, openMoreOptionsPage, +        biometricDisplayInfo.biometricRequestInfo, biometricFlowType)      val cancellationSignal = CancellationSignal()      cancellationSignal.setOnCancelListener {          Log.d(TAG, "Your cancellation signal was called.") -        // TODO(b/326243754) : Migrate towards passing along the developer cancellation signal +        // TODO(b/333445112) : Migrate towards passing along the developer cancellation signal          // or validate the necessity for this      } @@ -165,27 +223,28 @@ fun runBiometricFlow(          biometricPrompt.authenticate(cancellationSignal, executor, callback)      } catch (e: IllegalArgumentException) {          Log.w(TAG, "Calling the biometric prompt API failed with: /n${e.localizedMessage}\n") -        onBiometricFailureFallback() +        onBiometricFailureFallback(biometricFlowType)      }  }  /**   * Sets up the biometric prompt with the UI specific bits. - * // TODO(b/326243754) : Pass in opId once dependency is confirmed via CryptoObject + * // TODO(b/333445112) : Pass in opId once dependency is confirmed via CryptoObject   */  private fun setupBiometricPrompt(      context: Context,      biometricDisplayInfo: BiometricDisplayInfo,      openMoreOptionsPage: () -> Unit, -    requestAllowedAuthenticators: Int, -    flowType: FlowType, +    biometricRequestInfo: BiometricRequestInfo, +    biometricFlowType: BiometricFlowType,  ): BiometricPrompt { -    val finalAuthenticators = removeDeviceCredential(requestAllowedAuthenticators) +    val finalAuthenticators = removeDeviceCredential(biometricRequestInfo.allowedAuthenticators)      val biometricPrompt = BiometricPrompt.Builder(context)          .setTitle(biometricDisplayInfo.displayTitleText) -        // TODO(b/326243754) : Migrate to using new methods recently aligned upon -        .setNegativeButton(context.getString(if (flowType == FlowType.GET) R.string +        // TODO(b/333445112) : Migrate to using new methods and strings recently aligned upon +        .setNegativeButton(context.getString(if (biometricFlowType == BiometricFlowType.GET) +            R.string                  .dropdown_presentation_more_sign_in_options_text else R.string.string_more_options),              getMainExecutor(context)) { _, _ ->              openMoreOptionsPage() @@ -200,7 +259,7 @@ private fun setupBiometricPrompt(      return biometricPrompt  } -// TODO(b/326243754) : Remove after larger level alignments made on fallback negative button +// TODO(b/333445112) : Remove after larger level alignments made on fallback negative button  // For the time being, we do not support the pin fallback until UX is decided.  private fun removeDeviceCredential(requestAllowedAuthenticators: Int): Int {      var finalAuthenticators = requestAllowedAuthenticators @@ -230,16 +289,18 @@ private fun setupBiometricAuthenticationCallback(      selectedEntry: EntryInfo,      onCancelFlowAndFinish: () -> Unit,      onIllegalStateAndFinish: (String) -> Unit, +    onBiometricPromptStateChange: (BiometricPromptState) -> Unit  ): BiometricPrompt.AuthenticationCallback {      val callback: BiometricPrompt.AuthenticationCallback =          object : BiometricPrompt.AuthenticationCallback() { -            // TODO(b/326243754) : Validate remaining callbacks +            // TODO(b/333445772) : Validate remaining callbacks              override fun onAuthenticationSucceeded(                  authResult: BiometricPrompt.AuthenticationResult?              ) {                  super.onAuthenticationSucceeded(authResult)                  try {                      if (authResult != null) { +                        onBiometricPromptStateChange(BiometricPromptState.COMPLETE)                          sendDataToProvider(selectedEntry, authResult)                      } else {                          onIllegalStateAndFinish("The biometric flow succeeded but unexpectedly " + @@ -254,26 +315,24 @@ private fun setupBiometricAuthenticationCallback(              override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence?) {                  super.onAuthenticationHelp(helpCode, helpString)                  Log.d(TAG, "Authentication help discovered: $helpCode and $helpString") -                // TODO(b/326243754) : Decide on strategy with provider (a simple log probably -                // suffices here)              }              override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {                  super.onAuthenticationError(errorCode, errString)                  Log.d(TAG, "Authentication error-ed out: $errorCode and $errString") +                onBiometricPromptStateChange(BiometricPromptState.COMPLETE)                  if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED) {                      // Note that because the biometric prompt is imbued directly                      // into the selector, parity applies to the selector's cancellation instead                      // of the provider's biometric prompt cancellation.                      onCancelFlowAndFinish()                  } -                // TODO(b/326243754) : Propagate to provider +                // TODO(b/333445772) : Propagate to provider              }              override fun onAuthenticationFailed() {                  super.onAuthenticationFailed()                  Log.d(TAG, "Authentication failed.") -                // TODO(b/326243754) : Propagate to provider              }          }      return callback @@ -299,7 +358,7 @@ private fun validateAndRetrieveBiometricGetDisplayInfo(      if (getRequestDisplayInfo != null && getProviderInfoList != null &&          getProviderDisplayInfo != null) {          if (selectedEntry !is CredentialEntryInfo) { return null } -        return getBiometricDisplayValues(getProviderInfoList, +        return retrieveBiometricGetDisplayValues(getProviderInfoList,              context, getRequestDisplayInfo, selectedEntry)      }      return null @@ -308,7 +367,8 @@ private fun validateAndRetrieveBiometricGetDisplayInfo(  /**   * Creates the [BiometricDisplayInfo] for create flows, and early handles conditional   * checking between the two. The reason for this method matches the logic for the - * [validateBiometricGetFlow] with the only difference being that this is for the create flow. + * [validateAndRetrieveBiometricGetDisplayInfo] with the only difference being that this is for + * the create flow.   */  private fun validateAndRetrieveBiometricCreateDisplayInfo(      createRequestDisplayInfo: com.android.credentialmanager.createflow.RequestDisplayInfo?, @@ -318,8 +378,8 @@ private fun validateAndRetrieveBiometricCreateDisplayInfo(  ): BiometricDisplayInfo? {      if (createRequestDisplayInfo != null && createProviderInfo != null) {          if (selectedEntry !is CreateOptionInfo) { return null } -        return createBiometricDisplayValues(createRequestDisplayInfo, createProviderInfo, context, -            selectedEntry) +        return retrieveBiometricCreateDisplayValues(createRequestDisplayInfo, createProviderInfo, +            context, selectedEntry)      }      return null  } @@ -330,16 +390,16 @@ private fun validateAndRetrieveBiometricCreateDisplayInfo(   * to the original selector. Note that these redundant checks are just failsafe; the original   * flow should never reach here with invalid params.   */ -private fun getBiometricDisplayValues( +private fun retrieveBiometricGetDisplayValues(      getProviderInfoList: List<ProviderInfo>,      context: Context,      getRequestDisplayInfo: RequestDisplayInfo,      selectedEntry: CredentialEntryInfo,  ): BiometricDisplayInfo? { -    var icon: Bitmap? = null -    var providerName: String? = null -    var displayTitleText: String? = null -    var descriptionText: String? = null +    val icon: Bitmap? +    val providerName: String? +    val displayTitleText: String? +    val descriptionText: String?      val primaryAccountsProviderInfo = retrievePrimaryAccountProviderInfo(selectedEntry.providerId,          getProviderInfoList)      icon = primaryAccountsProviderInfo?.icon?.toBitmap() @@ -373,7 +433,7 @@ private fun getBiometricDisplayValues(   * if this is called, a result is guaranteed. Specifically, this is guaranteed to return a non-null   * value unlike the get counterpart.   */ -private fun createBiometricDisplayValues( +private fun retrieveBiometricCreateDisplayValues(      createRequestDisplayInfo: com.android.credentialmanager.createflow.RequestDisplayInfo,      createProviderInfo: EnabledProviderInfo,      context: Context, @@ -401,7 +461,7 @@ private fun createBiometricDisplayValues(          },          createRequestDisplayInfo.appName,      ) -    // TODO(b/327620327) : Add a subtitle and any other recently aligned ideas +    // TODO(b/333445112) : Add a subtitle and any other recently aligned ideas      return BiometricDisplayInfo(providerIcon = icon, providerName = providerName,          displayTitleText = displayTitleText, descriptionForCredential = descriptionText,          biometricRequestInfo = selectedEntry.biometricRequest as BiometricRequestInfo) diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricPromptState.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricPromptState.kt new file mode 100644 index 000000000000..e1aa0418e7a0 --- /dev/null +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricPromptState.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.credentialmanager.common + +enum class BiometricPromptState { +    /** The biometric prompt hasn't been activated. */ +    INACTIVE, +    /** The biometric prompt is active but data hasn't been returned yet. */ +    PENDING, +    /** The biometric prompt has closed and returned data we then send to the provider activity. */ +    COMPLETE +}
\ No newline at end of file diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt index 25fb477cbf38..122b8964dc96 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt @@ -46,11 +46,13 @@ import androidx.core.graphics.drawable.toBitmap  import com.android.compose.theme.LocalAndroidColorScheme  import com.android.credentialmanager.CredentialSelectorViewModel  import com.android.credentialmanager.R +import com.android.credentialmanager.common.BiometricFlowType +import com.android.credentialmanager.common.BiometricPromptState  import com.android.credentialmanager.model.EntryInfo  import com.android.credentialmanager.model.CredentialType  import com.android.credentialmanager.common.ProviderActivityState  import com.android.credentialmanager.common.material.ModalBottomSheetDefaults -import com.android.credentialmanager.common.runBiometricFlow +import com.android.credentialmanager.common.runBiometricFlowForCreate  import com.android.credentialmanager.common.ui.ActionButton  import com.android.credentialmanager.common.ui.BodyMediumText  import com.android.credentialmanager.common.ui.BodySmallText @@ -111,7 +113,11 @@ fun CreateCredentialScreen(                                  onBiometricEntrySelected =                                  viewModel::createFlowOnEntrySelected,                                  fallbackToOriginalFlow = -                                viewModel::getFlowOnBackToPrimarySelectionScreen, +                                viewModel::fallbackFromBiometricToNormalFlow, +                                getBiometricPromptState = +                                viewModel::getBiometricPromptState, +                                onBiometricPromptStateChange = +                                viewModel::onBiometricPromptStateChange                              )                          CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(                                  requestDisplayInfo = createCredentialUiState.requestDisplayInfo, @@ -578,18 +584,22 @@ internal fun BiometricSelectionPage(      onBiometricEntrySelected: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit,      onCancelFlowAndFinish: () -> Unit,      onIllegalScreenStateAndFinish: (String) -> Unit, -    fallbackToOriginalFlow: () -> Unit, +    fallbackToOriginalFlow: (BiometricFlowType) -> Unit, +    getBiometricPromptState: () -> BiometricPromptState, +    onBiometricPromptStateChange: (BiometricPromptState) -> Unit,  ) {      if (biometricEntry == null) { -        fallbackToOriginalFlow() +        fallbackToOriginalFlow(BiometricFlowType.CREATE)          return      } -    runBiometricFlow( +    runBiometricFlowForCreate(          biometricEntry = biometricEntry,          context = LocalContext.current,          openMoreOptionsPage = onMoreOptionSelected,          sendDataToProvider = onBiometricEntrySelected,          onCancelFlowAndFinish = onCancelFlowAndFinish, +        getBiometricPromptState = getBiometricPromptState, +        onBiometricPromptStateChange = onBiometricPromptStateChange,          createRequestDisplayInfo = requestDisplayInfo,          createProviderInfo = enabledProviderInfo,          onBiometricFailureFallback = fallbackToOriginalFlow, diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt index 1d262ba5261a..ddd4139b65b6 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt @@ -78,13 +78,8 @@ internal fun getCreateEntry(  */  internal fun isBiometricFlow(      activeEntry: ActiveEntry, -    sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>, -    requestDisplayInfo: RequestDisplayInfo, -) = findBiometricFlowEntry(activeEntry, isFlowAutoSelectable( -    requestDisplayInfo = requestDisplayInfo, -    activeEntry = activeEntry, -    sortedCreateOptionsPairs = sortedCreateOptionsPairs -)) != null +    isAutoSelectFlow: Boolean, +) = findBiometricFlowEntry(activeEntry, isAutoSelectFlow) != null  /**   * This utility presents the correct resource string for the create flows title conditionally. diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt index 6d1a3dd98210..72b7814a791a 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt @@ -52,9 +52,11 @@ import androidx.compose.ui.unit.dp  import androidx.core.graphics.drawable.toBitmap  import com.android.credentialmanager.CredentialSelectorViewModel  import com.android.credentialmanager.R +import com.android.credentialmanager.common.BiometricFlowType +import com.android.credentialmanager.common.BiometricPromptState  import com.android.credentialmanager.common.ProviderActivityState  import com.android.credentialmanager.common.material.ModalBottomSheetDefaults -import com.android.credentialmanager.common.runBiometricFlow +import com.android.credentialmanager.common.runBiometricFlowForGet  import com.android.credentialmanager.common.ui.ActionButton  import com.android.credentialmanager.common.ui.ActionEntry  import com.android.credentialmanager.common.ui.ConfirmButton @@ -154,7 +156,11 @@ fun GetCredentialScreen(                                  onBiometricEntrySelected =                                  viewModel::getFlowOnEntrySelected,                                  fallbackToOriginalFlow = -                                viewModel::getFlowOnBackToPrimarySelectionScreen, +                                viewModel::fallbackFromBiometricToNormalFlow, +                                getBiometricPromptState = +                                viewModel::getBiometricPromptState, +                                onBiometricPromptStateChange = +                                viewModel::onBiometricPromptStateChange                              )                          } else {                              AllSignInOptionCard( @@ -218,19 +224,23 @@ internal fun BiometricSelectionPage(      providerInfoList: List<ProviderInfo>,      providerDisplayInfo: ProviderDisplayInfo,      onBiometricEntrySelected: (EntryInfo, BiometricPrompt.AuthenticationResult?) -> Unit, -    fallbackToOriginalFlow: () -> Unit, +    fallbackToOriginalFlow: (BiometricFlowType) -> Unit, +    getBiometricPromptState: () -> BiometricPromptState, +    onBiometricPromptStateChange: (BiometricPromptState) -> Unit,  ) {      if (biometricEntry == null) { -        fallbackToOriginalFlow() +        fallbackToOriginalFlow(BiometricFlowType.GET)          return      } -    runBiometricFlow( +    runBiometricFlowForGet(          biometricEntry = biometricEntry,          context = LocalContext.current,          openMoreOptionsPage = onMoreOptionSelected,          sendDataToProvider = onBiometricEntrySelected,          onCancelFlowAndFinish = onCancelFlowAndFinish,          onIllegalStateAndFinish = onIllegalStateAndFinish, +        getBiometricPromptState = getBiometricPromptState, +        onBiometricPromptStateChange = onBiometricPromptStateChange,          getRequestDisplayInfo = requestDisplayInfo,          getProviderInfoList = providerInfoList,          getProviderDisplayInfo = providerDisplayInfo, diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt index ac776af4f627..b03407b9ebea 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt @@ -286,7 +286,7 @@ private fun toGetScreenState(          GetScreenState.REMOTE_ONLY      else if (isRequestForAllOptions)          GetScreenState.ALL_SIGN_IN_OPTIONS -    else if (isBiometricFlow(providerDisplayInfo)) +    else if (isBiometricFlow(providerDisplayInfo, isFlowAutoSelectable(providerDisplayInfo)))          GetScreenState.BIOMETRIC_SELECTION      else GetScreenState.PRIMARY_SELECTION  } @@ -294,9 +294,14 @@ private fun toGetScreenState(  /**   * Determines if the flow is a biometric flow by taking into account autoselect criteria.   */ -internal fun isBiometricFlow(providerDisplayInfo: ProviderDisplayInfo) = -    findBiometricFlowEntry(providerDisplayInfo, -        findAutoSelectEntry(providerDisplayInfo) != null) != null +internal fun isBiometricFlow(providerDisplayInfo: ProviderDisplayInfo, isAutoSelectFlow: Boolean) = +    findBiometricFlowEntry(providerDisplayInfo, isAutoSelectFlow) != null + +/** + * Determines if the flow is an autoselect flow. + */ +internal fun isFlowAutoSelectable(providerDisplayInfo: ProviderDisplayInfo) = +    findAutoSelectEntry(providerDisplayInfo) != null  internal class CredentialEntryInfoComparatorByTypeThenTimestamp(          val typePriorityMap: Map<String, Int>, diff --git a/packages/CredentialManager/wear/res/drawable/passkey_icon.xml b/packages/CredentialManager/wear/res/drawable/passkey_icon.xml deleted file mode 100644 index be366bf2a255..000000000000 --- a/packages/CredentialManager/wear/res/drawable/passkey_icon.xml +++ /dev/null @@ -1,21 +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:pathData="M23,10.5H17V13.5H23V10.5Z" -        android:fillColor="#188038"/> -    <path -        android:pathData="M6.5,17.5C3.5,17.5 1,15 1,12C1,9 3.5,6.5 6.5,6.5C9.5,6.5 12,9 12,12C12,15 9.5,17.5 6.5,17.5ZM6.5,9.5C5.1,9.5 4,10.6 4,12C4,13.4 5.1,14.5 6.5,14.5C7.9,14.5 9,13.4 9,12C9,10.6 7.9,9.5 6.5,9.5Z" -        android:fillColor="#4285F4"/> -    <path -        android:pathData="M21,13.5H19H17V16.5H19V15.5C19,14.9 19.4,14.5 20,14.5C20.6,14.5 21,14.9 21,15.5V16.5H23V13.5H21Z" -        android:fillColor="#34A853"/> -    <path -        android:pathData="M11.8,10.5H8.5C8.8,10.9 9,11.4 9,12C9,12.6 8.8,13.1 8.5,13.5H11.8C11.9,13 12,12.5 12,12C12,11.5 11.9,11 11.8,10.5Z" -        android:fillColor="#EA4335"/> -    <path -        android:pathData="M17,10.5H11.8C11.9,11 12,11.5 12,12C12,12.5 11.9,13 11.8,13.5H17V10.5Z" -        android:fillColor="#FBBC04"/> -</vector> diff --git a/packages/CredentialManager/wear/res/values-watch/donottranslate.xml b/packages/CredentialManager/wear/res/values-watch/donottranslate.xml new file mode 100644 index 000000000000..c3ab3cbb1f27 --- /dev/null +++ b/packages/CredentialManager/wear/res/values-watch/donottranslate.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + +     Licensed under the Apache License, Version 2.0 (the "License"); +     you may not use this file except in compliance with the License. +     You may obtain a copy of the License at + +          http://www.apache.org/licenses/LICENSE-2.0 + +     Unless required by applicable law or agreed to in writing, software +     distributed under the License is distributed on an "AS IS" BASIS, +     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +     See the License for the specific language governing permissions and +     limitations under the License. +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +    <!-- font-family-device-default is expected to be preloaded in the font_customization.xml(/vendor/<OEM>/products/<PRODUCT>/fonts/fonts_customization.xml)--> +    <!-- Falls back to system default when font-family-device-default doesn't exist    --> +    <string name="wear_material_compose_display_1_font_family">font-family-device-default</string> +    <string name="wear_material_compose_display_2_font_family">font-family-device-default</string> +    <string name="wear_material_compose_display_3_font_family">font-family-device-default</string> +    <string name="wear_material_compose_title_1_font_family">font-family-medium-device-default</string> +    <string name="wear_material_compose_title_2_font_family">font-family-medium-device-default</string> +    <string name="wear_material_compose_title_3_font_family">font-family-device-default</string> +    <string name="wear_material_compose_body_1_font_family">font-family-text-device-default</string> +    <string name="wear_material_compose_body_2_font_family">font-family-text-device-default</string> +    <string name="wear_material_compose_button_font_family">font-family-text-medium-device-default</string> +    <string name="wear_material_compose_caption_1_font_family">font-family-text-medium-device-default</string> +    <string name="wear_material_compose_caption_2_font_family">font-family-text-medium-device-default</string> +    <string name="wear_material_compose_caption_3_font_family">font-family-text-medium-device-default</string> +</resources> diff --git a/packages/CredentialManager/wear/res/values/overlayable.xml b/packages/CredentialManager/wear/res/values/overlayable.xml new file mode 100644 index 000000000000..5b9d37259b98 --- /dev/null +++ b/packages/CredentialManager/wear/res/values/overlayable.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> +    <overlayable name="CredentialSelectorStyles"> +        <policy type="product|system|vendor|odm|oem"> +            <!--START WEAR SPECIFIC FONT STRINGS --> +            <item type="string" name="wear_material_compose_display_1_font_family" /> +            <item type="string" name="wear_material_compose_display_2_font_family" /> +            <item type="string" name="wear_material_compose_display_3_font_family" /> +            <item type="string" name="wear_material_compose_title_1_font_family" /> +            <item type="string" name="wear_material_compose_title_2_font_family" /> +            <item type="string" name="wear_material_compose_title_3_font_family" /> +            <item type="string" name="wear_material_compose_body_1_font_family" /> +            <item type="string" name="wear_material_compose_body_2_font_family" /> +            <item type="string" name="wear_material_compose_button_font_family" /> +            <item type="string" name="wear_material_compose_caption_1_font_family" /> +            <item type="string" name="wear_material_compose_caption_2_font_family" /> +            <item type="string" name="wear_material_compose_caption_3_font_family" /> +            <!--END WEAR SPECIFIC FONT STRINGS --> + +        </policy> + +    </overlayable> + +</resources> diff --git a/packages/CredentialManager/wear/robotests/src/com/android/credentialmanager/CredentialSelectorUiStateGetMapperTest.kt b/packages/CredentialManager/wear/robotests/src/com/android/credentialmanager/CredentialSelectorUiStateGetMapperTest.kt index 3422d3dc4d94..6c145631a39e 100644 --- a/packages/CredentialManager/wear/robotests/src/com/android/credentialmanager/CredentialSelectorUiStateGetMapperTest.kt +++ b/packages/CredentialManager/wear/robotests/src/com/android/credentialmanager/CredentialSelectorUiStateGetMapperTest.kt @@ -65,29 +65,29 @@ class CredentialSelectorUiStateGetMapperTest {              isLastUnlocked = true          ) -    val passkeyCredentialEntryInfo = +    private val passkeyCredentialEntryInfo =          createCredentialEntryInfo(credentialType = CredentialType.PASSKEY, userName = "userName") -    val unknownCredentialEntryInfo = +    private val unknownCredentialEntryInfo =          createCredentialEntryInfo(credentialType = CredentialType.UNKNOWN, userName = "userName2") -    val passwordCredentialEntryInfo = +    private val passwordCredentialEntryInfo =          createCredentialEntryInfo(credentialType = CredentialType.PASSWORD, userName = "userName") -    val recentlyUsedPasskeyCredential = +    private val recentlyUsedPasskeyCredential =          createCredentialEntryInfo(credentialType =      CredentialType.PASSKEY, lastUsedTimeMillis = 2L, userName = "userName") -    val recentlyUsedPasswordCredential = +    private val recentlyUsedPasswordCredential =          createCredentialEntryInfo(credentialType =      CredentialType.PASSWORD, lastUsedTimeMillis = 2L, userName = "userName") -    val credentialList1 = listOf( +    private val credentialList1 = listOf(          passkeyCredentialEntryInfo,          passwordCredentialEntryInfo      ) -    val credentialList2 = listOf( +    private val credentialList2 = listOf(          passkeyCredentialEntryInfo,          passwordCredentialEntryInfo,          recentlyUsedPasskeyCredential, @@ -118,11 +118,12 @@ class CredentialSelectorUiStateGetMapperTest {                  unknownCredentialEntryInfo)))).toGet(isPrimary = true)          assertThat(getCredentialUiState).isEqualTo( -            CredentialSelectorUiState.Get.SingleEntryPerAccount( +            CredentialSelectorUiState.Get.MultipleEntryPrimaryScreen(                  sortedEntries = listOf(                      passkeyCredentialEntryInfo, // userName                      unknownCredentialEntryInfo // userName2                  ), +                icon = mDrawable,                  authenticationEntryList = listOf(authenticationEntryInfo)              )) // prefer passkey from account 1, then unknown from account 2      } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt index 0fe35e695047..652e62cb26b4 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorActivity.kt @@ -21,7 +21,7 @@ import android.os.Bundle  import androidx.activity.ComponentActivity  import androidx.activity.compose.setContent  import androidx.activity.viewModels -import androidx.wear.compose.material.MaterialTheme +import com.android.credentialmanager.ui.theme.WearCredentialSelectorTheme  import com.android.credentialmanager.ui.WearApp  import com.google.android.horologist.annotations.ExperimentalHorologistApi  import dagger.hilt.android.AndroidEntryPoint @@ -36,7 +36,7 @@ class CredentialSelectorActivity : Hilt_CredentialSelectorActivity() {          super.onCreate(savedInstanceState)          setTheme(android.R.style.Theme_DeviceDefault)          setContent { -            MaterialTheme { +            WearCredentialSelectorTheme {                  WearApp(                      flowEngine = viewModel,                      onCloseApp = { finish() }, diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt index b7fa33e9372f..36085684db57 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt @@ -86,7 +86,7 @@ class CredentialSelectorViewModel @Inject constructor(          when (uiState.value) {              is Get.MultipleEntry -> isPrimaryScreen.value = true              is Create, Close, is Cancel, Idle -> shouldClose.value = true -            is Get.SingleEntry, is Get.SingleEntryPerAccount -> cancel() +            is Get.SingleEntry, is Get.MultipleEntryPrimaryScreen -> cancel()          }      } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt index c05fc93b8223..b2f55c108317 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/FlowEngine.kt @@ -17,6 +17,7 @@  package com.android.credentialmanager  import android.content.Intent +import android.graphics.drawable.Drawable  import androidx.activity.result.IntentSenderRequest  import androidx.compose.runtime.Composable  import com.android.credentialmanager.model.EntryInfo @@ -71,14 +72,14 @@ sealed class CredentialSelectorUiState {          /** Getting credential UI state when there is only one credential available. */          data class SingleEntry(val entry: CredentialEntryInfo) : Get()          /** -         * Getting credential UI state when there is only one account while with multiple -         * credentials, with different types(eg, passkey vs password) or providers. +         * Getting credential UI state on primary screen when there is are multiple accounts.           */ -        data class SingleEntryPerAccount( +        data class MultipleEntryPrimaryScreen( +            val icon: Drawable?,              val sortedEntries: List<CredentialEntryInfo>,              val authenticationEntryList: List<AuthenticationEntryInfo>,              ) : Get() -        /** Getting credential UI state when there are multiple accounts available. */ +        /** Getting credential UI state on secondary screen when there are multiple accounts available. */          data class MultipleEntry(              val accounts: List<PerUserNameEntries>,              val actionEntryList: List<ActionEntryInfo>, diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt index 018db6899f6e..a75aeaff0c48 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt @@ -29,7 +29,7 @@ import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState  import androidx.wear.compose.navigation.rememberSwipeDismissableNavController  import androidx.wear.compose.navigation.rememberSwipeDismissableNavHostState  import com.android.credentialmanager.CredentialSelectorUiState -import com.android.credentialmanager.CredentialSelectorUiState.Get.SingleEntryPerAccount +import com.android.credentialmanager.CredentialSelectorUiState.Get.MultipleEntryPrimaryScreen  import com.android.credentialmanager.CredentialSelectorUiState.Get.SingleEntry  import com.android.credentialmanager.CredentialSelectorUiState.Get.MultipleEntry  import com.android.credentialmanager.FlowEngine @@ -95,7 +95,7 @@ fun WearApp(          scrollable(Screen.MultipleCredentialsScreenFold.route) {              MultiCredentialsFoldScreen( -                credentialSelectorUiState = (remember { uiState } as SingleEntryPerAccount), +                credentialSelectorUiState = (remember { uiState } as MultipleEntryPrimaryScreen),                  columnState = it.columnState,                  flowEngine = flowEngine,              ) @@ -124,7 +124,6 @@ fun WearApp(                  handleGetNavigation(                      navController = navController,                      state = state, -                    onCloseApp = onCloseApp,                      selectEntry = selectEntry                  )              } @@ -147,7 +146,6 @@ fun WearApp(  private fun handleGetNavigation(      navController: NavController,      state: CredentialSelectorUiState.Get, -    onCloseApp: () -> Unit,      selectEntry: (entry: EntryInfo, isAutoSelected: Boolean) -> Unit,  ) {      when (state) { @@ -169,7 +167,7 @@ private fun handleGetNavigation(              }          } -            is SingleEntryPerAccount -> { +            is MultipleEntryPrimaryScreen -> {                  navController.navigateToMultipleCredentialsFoldScreen()              } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/AccountRow.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/AccountRow.kt index 8b19e1b659d2..3088fed83c02 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/AccountRow.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/AccountRow.kt @@ -21,35 +21,25 @@ import androidx.compose.foundation.layout.padding  import androidx.compose.runtime.Composable  import androidx.compose.ui.Alignment  import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.style.TextOverflow  import androidx.compose.ui.unit.dp -import androidx.wear.compose.material.MaterialTheme -import androidx.wear.compose.material.Text +import com.android.credentialmanager.common.ui.components.WearDisplayNameText +import com.android.credentialmanager.common.ui.components.WearUsernameText  import com.google.android.horologist.compose.tools.WearPreview  @Composable  fun AccountRow(      primaryText: String,      secondaryText: String? = null, -    modifier: Modifier = Modifier,  ) { -    Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) { -        Text( +    Column(modifier = Modifier.padding(bottom = 12.dp), +        horizontalAlignment = Alignment.CenterHorizontally) { +        WearDisplayNameText(              text = primaryText, -            color = Color(0xFFE6FF7B), -            overflow = TextOverflow.Ellipsis, -            maxLines = 1, -            style = MaterialTheme.typography.title2          )          if (secondaryText != null) { -            Text( +            WearUsernameText(                  text = secondaryText, -                modifier = Modifier.padding(top = 7.dp), -                color = Color(0xFFCAC5BC), -                overflow = TextOverflow.Ellipsis, -                maxLines = 2, -                style = MaterialTheme.typography.body1, +                modifier = Modifier.padding(top = 8.dp)              )          }      } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt index 8e5a8666621f..c641d7f9f48f 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/CredentialsScreenChip.kt @@ -22,12 +22,9 @@ import androidx.compose.foundation.layout.BoxScope  import androidx.compose.foundation.layout.RowScope  import androidx.compose.foundation.layout.size  import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding  import androidx.compose.runtime.Composable  import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clipToBounds  import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow  import androidx.compose.ui.tooling.preview.Preview  import androidx.compose.ui.unit.dp  import androidx.wear.compose.material.Chip @@ -35,11 +32,12 @@ import androidx.core.graphics.drawable.toBitmap  import androidx.wear.compose.material.ChipColors  import androidx.compose.ui.graphics.asImageBitmap  import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextAlign  import androidx.wear.compose.material.ChipDefaults -import androidx.wear.compose.material.Text  import com.android.credentialmanager.R +import com.android.credentialmanager.common.ui.components.WearButtonText +import com.android.credentialmanager.common.ui.components.WearSecondaryLabel  import com.android.credentialmanager.model.get.AuthenticationEntryInfo -import com.android.credentialmanager.ui.components.CredentialsScreenChip.TOPPADDING  /* Used as credential suggestion or user action chip. */  @Composable @@ -49,36 +47,61 @@ fun CredentialsScreenChip(      secondaryLabel: String? = null,      icon: Drawable? = null,      isAuthenticationEntryLocked: Boolean = false, +    textAlign: TextAlign = TextAlign.Center,      modifier: Modifier = Modifier, -    colors: ChipColors = ChipDefaults.secondaryChipColors(), +    colors: ChipColors = ChipDefaults.secondaryChipColors()  ) { +        return CredentialsScreenChip( +                    onClick, +                    text = { +                        WearButtonText( +                            text = label, +                            textAlign = textAlign, +                            maxLines = if (secondaryLabel != null) 1 else 2 +                        ) +                    }, +                    secondaryLabel, +                    icon, +                    isAuthenticationEntryLocked, +                    modifier, +                    colors +        ) +} + + + +/* Used as credential suggestion or user action chip. */ +@Composable +fun CredentialsScreenChip( +    onClick: () -> Unit, +    text: @Composable () -> Unit, +    secondaryLabel: String? = null, +    icon: Drawable? = null, +    isAuthenticationEntryLocked: Boolean = false, +    modifier: Modifier = Modifier, +    colors: ChipColors = ChipDefaults.primaryChipColors(), +    ) {      val labelParam: (@Composable RowScope.() -> Unit) =          { -            Text( -                text = label, -                overflow = TextOverflow.Ellipsis, -                maxLines = if (secondaryLabel != null) 1 else 2, -            ) +            text()          }      val secondaryLabelParam: (@Composable RowScope.() -> Unit)? =          secondaryLabel?.let {              {                  Row { -                    Text( +                    WearSecondaryLabel(                          text = secondaryLabel, -                        overflow = TextOverflow.Ellipsis, -                        maxLines = 1,                      )                      if (isAuthenticationEntryLocked) -                        // TODO(b/324465527) change this to lock icon and correct size once figma mocks are -                        // updated +                    // TODO(b/324465527) change this to lock icon and correct size once figma mocks are +                    // updated                          Icon(                              bitmap = checkNotNull(icon?.toBitmap()?.asImageBitmap()),                              // Decorative purpose only.                              contentDescription = null, -                            modifier = Modifier.size(20.dp), +                            modifier = Modifier.size(10.dp),                              tint = Color.Unspecified                          )                  } @@ -92,7 +115,7 @@ fun CredentialsScreenChip(                      bitmap = it,                      // Decorative purpose only.                      contentDescription = null, -                    modifier = Modifier.size(32.dp), +                    modifier = Modifier.size(24.dp),                      tint = Color.Unspecified                  )              } @@ -117,9 +140,6 @@ fun CredentialsScreenChipPreview() {          onClick = { },          secondaryLabel = "beckett_bakery@gmail.com",          icon = null, -        modifier = Modifier -            .clipToBounds() -            .padding(top = 2.dp)      )  } @@ -127,9 +147,8 @@ fun CredentialsScreenChipPreview() {  fun SignInOptionsChip(onClick: () -> Unit) {      CredentialsScreenChip(          label = stringResource(R.string.dialog_sign_in_options_button), +        textAlign = TextAlign.Start,          onClick = onClick, -        modifier = Modifier -            .padding(top = TOPPADDING)      )  } @@ -142,10 +161,13 @@ fun SignInOptionsChipPreview() {  @Composable  fun ContinueChip(onClick: () -> Unit) {      CredentialsScreenChip( -        label = stringResource(R.string.dialog_continue_button),          onClick = onClick, -        modifier = Modifier -            .padding(top = TOPPADDING), +        text = { +            WearButtonText( +                text = stringResource(R.string.dialog_continue_button), +                textAlign = TextAlign.Center, +            ) +        },          colors = ChipDefaults.primaryChipColors(),      )  } @@ -161,21 +183,8 @@ fun DismissChip(onClick: () -> Unit) {      CredentialsScreenChip(          label = stringResource(R.string.dialog_dismiss_button),          onClick = onClick, -        modifier = Modifier -            .padding(top = TOPPADDING), -    ) -} - -@Composable -fun SignInOnPhoneChip(onClick: () -> Unit) { -    CredentialsScreenChip( -        label = stringResource(R.string.sign_in_on_phone_button), -        onClick = onClick, -        modifier = Modifier -            .padding(top = TOPPADDING),      )  } -  @Composable  fun LockedProviderChip(      authenticationEntryInfo: AuthenticationEntryInfo, @@ -191,9 +200,9 @@ fun LockedProviderChip(          label = authenticationEntryInfo.title,          icon = authenticationEntryInfo.icon,          secondaryLabel = secondaryLabel, +        textAlign = TextAlign.Start,          isAuthenticationEntryLocked = !authenticationEntryInfo.isUnlockedAndEmpty,          onClick = onClick, -        modifier = Modifier.padding(top = TOPPADDING),      )  } @@ -203,7 +212,3 @@ fun DismissChipPreview() {      DismissChip({})  } -private object CredentialsScreenChip { -    val TOPPADDING = 8.dp -} - diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/PasswordRow.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/PasswordRow.kt index 97900b723bc3..62e1c8501d7a 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/PasswordRow.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/PasswordRow.kt @@ -21,33 +21,22 @@ import androidx.compose.foundation.layout.padding  import androidx.compose.runtime.Composable  import androidx.compose.ui.Alignment  import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.style.TextOverflow  import androidx.compose.ui.unit.dp -import androidx.wear.compose.material.MaterialTheme -import androidx.wear.compose.material.Text +import com.android.credentialmanager.common.ui.components.WearDisplayNameText +import com.android.credentialmanager.common.ui.components.WearUsernameText  import com.google.android.horologist.compose.tools.WearPreview  @Composable  fun PasswordRow(      email: String, -    modifier: Modifier = Modifier,  ) { -    Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) { -        Text( +    Column(modifier = Modifier.padding(bottom = 12.dp), +        horizontalAlignment = Alignment.CenterHorizontally) { +        WearDisplayNameText(              text = email, -            color = Color(0xFFE6FF7B), -            overflow = TextOverflow.Ellipsis, -            maxLines = 2, -            style = MaterialTheme.typography.title2          ) -        Text( -            text = "••••••••••••••", -            modifier = Modifier.padding(top = 7.dp), -            color = Color(0xFFCAC5BC), -            overflow = TextOverflow.Ellipsis, -            maxLines = 1, -            style = MaterialTheme.typography.body1, +        WearUsernameText( +            text = "••••••••••••••"          )      }  } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/SignInHeader.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/SignInHeader.kt index 423662c30d6e..0afef5eba85e 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/SignInHeader.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/SignInHeader.kt @@ -18,49 +18,44 @@ package com.android.credentialmanager.ui.components  import android.graphics.drawable.Drawable  import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.Spacer  import androidx.compose.foundation.layout.size +import androidx.compose.material3.Icon  import androidx.compose.runtime.Composable  import androidx.compose.ui.Alignment  import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color  import androidx.compose.ui.graphics.asImageBitmap  import androidx.compose.ui.unit.dp  import androidx.core.graphics.drawable.toBitmap -import androidx.wear.compose.material.Text -import androidx.compose.ui.graphics.Color -import androidx.compose.material3.Icon -import androidx.wear.compose.material.MaterialTheme as WearMaterialTheme -import androidx.compose.ui.text.style.TextAlign +import com.android.credentialmanager.common.ui.components.WearTitleText  /* Used as header across Credential Selector screens. */  @Composable  fun SignInHeader(      icon: Drawable?,      title: String, -    modifier: Modifier = Modifier,  ) {      Column( -        modifier = modifier, +        modifier = Modifier,          horizontalAlignment = Alignment.CenterHorizontally      ) {          if (icon != null) {              Icon(                  bitmap = icon.toBitmap().asImageBitmap(), -                modifier = Modifier.size(32.dp), +                modifier = Modifier.size(24.dp),                  // Decorative purpose only.                  contentDescription = null,                  tint = Color.Unspecified,              )          } +        Spacer(modifier = Modifier.size(8.dp)) -        Text( +        WearTitleText(              text = title, -            textAlign = TextAlign.Center, -            modifier = Modifier -                .padding(top = 6.dp) -                .padding(horizontal = 10.dp), -            style = WearMaterialTheme.typography.title3          ) + +        Spacer(modifier = Modifier.size(8.dp))      }  } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Spacers.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Spacers.kt new file mode 100644 index 000000000000..c87f176bc06c --- /dev/null +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Spacers.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.credentialmanager.ui.components + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +/** + * Space beneath all elements of screen + */ +@Composable +fun BottomSpacer() { +    Spacer(modifier = Modifier.size(40.dp)) + } + +/** + * Usual space between Credential Screen Chips + */ +@Composable +fun CredentialsScreenChipSpacer() { +    Spacer(modifier = Modifier.size(4.dp)) +}
\ No newline at end of file diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Texts.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Texts.kt new file mode 100644 index 000000000000..22f6bf0f37ee --- /dev/null +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/components/Texts.kt @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.credentialmanager.common.ui.components + +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextLayoutResult +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.wear.compose.material.MaterialTheme as WearMaterialTheme + +@Composable +fun WearTitleText(text: String, modifier: Modifier = Modifier) { +    Text( +        modifier = modifier.wrapContentSize(), +        text = text, +        color = WearMaterialTheme.colors.onSurface, +        textAlign = TextAlign.Center, +        style = WearMaterialTheme.typography.title3, +    ) +} + +@Composable +fun WearDisplayNameText(text: String, modifier: Modifier = Modifier) { +    Text( +        modifier = modifier.wrapContentSize(), +        text = text, +        color = WearMaterialTheme.colors.onSurfaceVariant, +        textAlign = TextAlign.Center, +        overflow = TextOverflow.Ellipsis, +        maxLines = 2, +        style = WearMaterialTheme.typography.title2, +    ) +} + +@Composable +fun WearUsernameText( +    text: String, +    textAlign: TextAlign = TextAlign.Center, +    modifier: Modifier = Modifier, +    onTextLayout: (TextLayoutResult) -> Unit = {}, +) { +    Text( +        modifier = modifier.padding(start = 8.dp, end = 8.dp).wrapContentSize(), +        text = text, +        color = WearMaterialTheme.colors.onSurfaceVariant, +        style = WearMaterialTheme.typography.caption1, +        overflow = TextOverflow.Ellipsis, +        textAlign = textAlign, +        maxLines = 2, +        onTextLayout = onTextLayout, +    ) +} + +// used for primary label in button +@Composable +fun WearButtonText( +    text: String, +    textAlign: TextAlign, +    maxLines: Int = 1, +    modifier: Modifier = Modifier, +    color: Color = WearMaterialTheme.colors.onSurface, +    onTextLayout: (TextLayoutResult) -> Unit = {}, +) { +    Text( +        modifier = modifier.wrapContentSize(), +        text = text, +        color = color, +        style = WearMaterialTheme.typography.button, +        overflow = TextOverflow.Ellipsis, +        textAlign = textAlign, +        maxLines = maxLines, +        onTextLayout = onTextLayout, +    ) +} + +@Composable +fun WearSecondaryLabel( +    text: String, +    modifier: Modifier = Modifier, +    onTextLayout: (TextLayoutResult) -> Unit = {}, +) { +    Text( +        modifier = modifier.wrapContentSize(), +        text = text, +        color = WearMaterialTheme.colors.onSurfaceVariant, +        style = WearMaterialTheme.typography.caption1, +        overflow = TextOverflow.Ellipsis, +        textAlign = TextAlign.Start, +        maxLines = 1, +        onTextLayout = onTextLayout, +    ) +} diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt index 7a936b603ec1..04175335b9db 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt @@ -16,6 +16,7 @@  package com.android.credentialmanager.ui.mappers +import android.graphics.drawable.Drawable  import com.android.credentialmanager.model.Request  import com.android.credentialmanager.CredentialSelectorUiState  import com.android.credentialmanager.CredentialSelectorUiState.Get.MultipleEntry.PerUserNameEntries @@ -35,10 +36,19 @@ fun Request.Get.toGet(isPrimary: Boolean): CredentialSelectorUiState.Get {                  entry = accounts[0].value.minWith(comparator)              )          } else { -            CredentialSelectorUiState.Get.SingleEntryPerAccount( -                sortedEntries = accounts.map { -                    it.value.minWith(comparator) -                }.sortedWith(comparator), +            val sortedEntries = accounts.map { +                it.value.minWith(comparator) +            }.sortedWith(comparator) + +            var icon: Drawable? = null +            // provide icon if all entries have the same provider +            if (sortedEntries.all {it.providerId == sortedEntries[0].providerId}) { +                icon = providerInfos[0].icon +            } + +            CredentialSelectorUiState.Get.MultipleEntryPrimaryScreen( +                sortedEntries = sortedEntries, +                icon = icon,                  authenticationEntryList = providerInfos.flatMap { it.authenticationEntryList }              )          } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/LoadingScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/LoadingScreen.kt index b3ab0c4212db..0b07643056da 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/LoadingScreen.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/LoadingScreen.kt @@ -17,12 +17,9 @@  package com.android.credentialmanager.ui.screens  import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier  @Composable -fun LoadingScreen( -    modifier: Modifier = Modifier -) { +fun LoadingScreen() {      // Don't display anything, assuming that there should be minimal latency      // to parse the Credential Manager intent and define the state of the      // app. If latency is big, then a "loading" screen should be displayed diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt index d54103cd66e8..fb81e736171b 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt @@ -15,20 +15,21 @@   */  package com.android.credentialmanager.ui.screens.multiple +import com.android.credentialmanager.ui.components.CredentialsScreenChip  import androidx.compose.foundation.layout.fillMaxSize  import androidx.compose.foundation.layout.padding  import androidx.compose.runtime.Composable  import androidx.compose.ui.Modifier  import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign  import androidx.compose.ui.unit.dp -import androidx.wear.compose.material.MaterialTheme -import androidx.wear.compose.material.Text -import com.android.credentialmanager.ui.components.SignInHeader  import com.android.credentialmanager.CredentialSelectorUiState.Get.MultipleEntry  import com.android.credentialmanager.FlowEngine  import com.android.credentialmanager.R +import com.android.credentialmanager.common.ui.components.WearButtonText +import com.android.credentialmanager.common.ui.components.WearSecondaryLabel  import com.android.credentialmanager.model.get.CredentialEntryInfo -import com.android.credentialmanager.ui.components.CredentialsScreenChip +import com.android.credentialmanager.ui.components.CredentialsScreenChipSpacer  import com.google.android.horologist.annotations.ExperimentalHorologistApi  import com.google.android.horologist.compose.layout.ScalingLazyColumn  import com.google.android.horologist.compose.layout.ScalingLazyColumnState @@ -55,20 +56,17 @@ fun MultiCredentialsFlattenScreen(      ) {          item {              // make this credential specific if all credentials are same -            SignInHeader( -                icon = null, -                title = stringResource(R.string.sign_in_options_title), +            WearButtonText( +                text = stringResource(R.string.sign_in_options_title), +                textAlign = TextAlign.Start,              )          }          credentialSelectorUiState.accounts.forEach { userNameEntries ->              item { -                Text( +                WearSecondaryLabel(                      text = userNameEntries.userName, -                    modifier = Modifier -                        .padding(top = 6.dp) -                        .padding(horizontal = 10.dp), -                    style = MaterialTheme.typography.title3 +                    modifier = Modifier.padding(top = 12.dp, bottom = 4.dp)                  )              } @@ -79,21 +77,20 @@ fun MultiCredentialsFlattenScreen(                          onClick = { selectEntry(credential, false) },                          secondaryLabel = credential.credentialTypeDisplayName,                          icon = credential.icon, +                        textAlign = TextAlign.Start                      ) + +                    CredentialsScreenChipSpacer()                  }              }          }          item { -            Text( +            WearSecondaryLabel(                  text = stringResource(R.string.provider_list_title), -                modifier = Modifier -                    .padding(top = 6.dp) -                    .padding(horizontal = 10.dp), -                style = MaterialTheme.typography.title3 +                modifier = Modifier.padding(top = 12.dp, bottom = 4.dp)              )          } - -        credentialSelectorUiState.actionEntryList.forEach {actionEntry -> +        credentialSelectorUiState.actionEntryList.forEach { actionEntry ->              item {                      CredentialsScreenChip(                          label = actionEntry.title, @@ -101,9 +98,8 @@ fun MultiCredentialsFlattenScreen(                          secondaryLabel = null,                          icon = actionEntry.icon,                      ) +                    CredentialsScreenChipSpacer()              }          }      }  } - - diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt index 6f32c9906a1d..7addc74aecd0 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFoldScreen.kt @@ -16,10 +16,11 @@  package com.android.credentialmanager.ui.screens.multiple +import androidx.compose.foundation.layout.Spacer  import com.android.credentialmanager.R  import androidx.compose.ui.res.stringResource  import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size  import androidx.compose.runtime.Composable  import androidx.compose.ui.Modifier  import androidx.compose.ui.unit.dp @@ -35,6 +36,8 @@ import com.google.android.horologist.annotations.ExperimentalHorologistApi  import com.google.android.horologist.compose.layout.ScalingLazyColumn  import com.google.android.horologist.compose.layout.ScalingLazyColumnState  import com.android.credentialmanager.model.CredentialType +import com.android.credentialmanager.ui.components.BottomSpacer +import com.android.credentialmanager.ui.components.CredentialsScreenChipSpacer  /**   * Screen that shows multiple credentials to select from. @@ -45,7 +48,7 @@ import com.android.credentialmanager.model.CredentialType  @OptIn(ExperimentalHorologistApi::class)  @Composable  fun MultiCredentialsFoldScreen( -    credentialSelectorUiState: CredentialSelectorUiState.Get.SingleEntryPerAccount, +    credentialSelectorUiState: CredentialSelectorUiState.Get.MultipleEntryPrimaryScreen,      columnState: ScalingLazyColumnState,      flowEngine: FlowEngine,  ) { @@ -58,42 +61,52 @@ fun MultiCredentialsFoldScreen(          val credentials = credentialSelectorUiState.sortedEntries          item {              var title = stringResource(R.string.choose_sign_in_title) -            if (credentials.all{ it.credentialType == CredentialType.PASSKEY }) { + +            if (credentials.isEmpty()) { +                title = stringResource(R.string.choose_sign_in_title) +            } else if (credentials.all{ it.credentialType == CredentialType.PASSKEY }) {                  title = stringResource(R.string.choose_passkey_title)              } else if (credentials.all { it.credentialType == CredentialType.PASSWORD }) {                  title = stringResource(R.string.choose_password_title)              }              SignInHeader( -                icon = null, +                icon = credentialSelectorUiState.icon,                  title = title, -                modifier = Modifier -                    .padding(top = 6.dp),              )          }          credentials.forEach { credential: CredentialEntryInfo -> -                item { -                    CredentialsScreenChip( -                        label = credential.userName, -                        onClick = { selectEntry(credential, false) }, -                        secondaryLabel = credential.credentialTypeDisplayName, -                        icon = credential.icon, -                    ) -                } +            item { +                CredentialsScreenChip( +                    label = credential.userName, +                    onClick = { selectEntry(credential, false) }, +                    secondaryLabel = credential.credentialTypeDisplayName, +                    icon = credential.icon, +                ) +                CredentialsScreenChipSpacer()              } +        }          credentialSelectorUiState.authenticationEntryList.forEach { authenticationEntryInfo ->              item {                  LockedProviderChip(authenticationEntryInfo) { -                    selectEntry(authenticationEntryInfo, false) } +                    selectEntry(authenticationEntryInfo, false) +                } +                CredentialsScreenChipSpacer()              }          } + +        item { +            Spacer(modifier = Modifier.size(8.dp)) +        } +          item {              SignInOptionsChip { flowEngine.openSecondaryScreen() }          }          item {              DismissChip { flowEngine.cancel() } +            BottomSpacer()          }      }  } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/passkey/SinglePasskeyScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/passkey/SinglePasskeyScreen.kt index 56b1c2e3d5a4..03608a48beb6 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/passkey/SinglePasskeyScreen.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/passkey/SinglePasskeyScreen.kt @@ -29,17 +29,19 @@ import com.android.credentialmanager.model.get.CredentialEntryInfo  import com.android.credentialmanager.R  import com.android.credentialmanager.ui.components.AccountRow  import com.android.credentialmanager.ui.components.ContinueChip +import com.android.credentialmanager.ui.components.CredentialsScreenChipSpacer  import com.android.credentialmanager.ui.components.DismissChip  import com.android.credentialmanager.ui.components.SignInHeader  import com.android.credentialmanager.ui.components.SignInOptionsChip  import com.android.credentialmanager.ui.screens.single.SingleAccountScreen  import com.google.android.horologist.annotations.ExperimentalHorologistApi  import com.google.android.horologist.compose.layout.ScalingLazyColumnState +import com.android.credentialmanager.ui.components.BottomSpacer  /** - * Screen that shows sign in with provider credential. + * Screen that shows single passkey credential.   * - * @param entry The password entry + * @param entry The passkey entry   * @param columnState ScalingLazyColumn configuration to be be applied to SingleAccountScreen   * @param modifier styling for composable   * @param flowEngine [FlowEngine] that updates ui state for this screen @@ -49,7 +51,6 @@ import com.google.android.horologist.compose.layout.ScalingLazyColumnState  fun SinglePasskeyScreen(      entry: CredentialEntryInfo,      columnState: ScalingLazyColumnState, -    modifier: Modifier = Modifier,      flowEngine: FlowEngine,  ) {      SingleAccountScreen( @@ -60,21 +61,31 @@ fun SinglePasskeyScreen(              )          },          accountContent = { -            AccountRow( -                    primaryText = checkNotNull(entry.displayName), +            val displayName = entry.displayName +            if (displayName == null || +                entry.displayName.equals(entry.userName, ignoreCase = true)) { +                AccountRow( +                    primaryText = entry.userName, +                ) +            } else { +                AccountRow( +                    primaryText = displayName,                      secondaryText = entry.userName, -                    modifier = Modifier.padding(top = 10.dp),                  ) +            }          },          columnState = columnState, -        modifier = modifier.padding(horizontal = 10.dp) +        modifier = Modifier.padding(horizontal = 10.dp)      ) {          item {              val selectEntry = flowEngine.getEntrySelector()              Column {                  ContinueChip { selectEntry(entry, false) } +                CredentialsScreenChipSpacer()                  SignInOptionsChip{ flowEngine.openSecondaryScreen() } +                CredentialsScreenChipSpacer()                  DismissChip { flowEngine.cancel() } +                BottomSpacer()              }          }      } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt index 2ca8ef13c0cf..818723bf52bf 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreen.kt @@ -33,11 +33,13 @@ import com.android.credentialmanager.ui.components.SignInHeader  import com.android.credentialmanager.ui.components.SignInOptionsChip  import com.android.credentialmanager.ui.screens.single.SingleAccountScreen  import com.android.credentialmanager.model.get.CredentialEntryInfo +import com.android.credentialmanager.ui.components.BottomSpacer +import com.android.credentialmanager.ui.components.CredentialsScreenChipSpacer  import com.google.android.horologist.annotations.ExperimentalHorologistApi  import com.google.android.horologist.compose.layout.ScalingLazyColumnState  /** - * Screen that shows sign in with provider credential. + * Screen that shows password credential.   *   * @param entry The password entry.   * @param columnState ScalingLazyColumn configuration to be be applied to SingleAccountScreen @@ -49,7 +51,6 @@ import com.google.android.horologist.compose.layout.ScalingLazyColumnState  fun SinglePasswordScreen(      entry: CredentialEntryInfo,      columnState: ScalingLazyColumnState, -    modifier: Modifier = Modifier,      flowEngine: FlowEngine,  ) {      val selectEntry = flowEngine.getEntrySelector() @@ -63,17 +64,19 @@ fun SinglePasswordScreen(          accountContent = {              PasswordRow(                  email = entry.userName, -                modifier = Modifier.padding(top = 10.dp),              )          },          columnState = columnState, -        modifier = modifier.padding(horizontal = 10.dp) +        modifier = Modifier.padding(horizontal = 10.dp)      ) {          item {              Column {                  ContinueChip { selectEntry(entry, false) } +                CredentialsScreenChipSpacer()                  SignInOptionsChip{ flowEngine.openSecondaryScreen() } +                CredentialsScreenChipSpacer()                  DismissChip { flowEngine.cancel() } +                BottomSpacer()              }          }      } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/signInWithProvider/SignInWithProviderScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/signInWithProvider/SignInWithProviderScreen.kt index 3a86feb4203b..34d6e977533e 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/signInWithProvider/SignInWithProviderScreen.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/signInWithProvider/SignInWithProviderScreen.kt @@ -24,7 +24,9 @@ import androidx.compose.ui.unit.dp  import com.android.credentialmanager.FlowEngine  import com.android.credentialmanager.model.get.CredentialEntryInfo  import com.android.credentialmanager.ui.components.AccountRow +import com.android.credentialmanager.ui.components.BottomSpacer  import com.android.credentialmanager.ui.components.ContinueChip +import com.android.credentialmanager.ui.components.CredentialsScreenChipSpacer  import com.android.credentialmanager.ui.components.DismissChip  import com.android.credentialmanager.ui.components.SignInHeader  import com.android.credentialmanager.ui.components.SignInOptionsChip @@ -35,7 +37,7 @@ import com.google.android.horologist.compose.layout.ScalingLazyColumnState  /**   * Screen that shows sign in with provider credential.   * - * @param entry The password entry. + * @param entry The custom credential entry.   * @param columnState ScalingLazyColumn configuration to be be applied to SingleAccountScreen   * @param modifier styling for composable   * @param flowEngine [FlowEngine] that updates ui state for this screen @@ -57,16 +59,15 @@ fun SignInWithProviderScreen(          },          accountContent = {              val displayName = entry.displayName -            if (displayName != null) { +            if (displayName == null || +                entry.displayName.equals(entry.userName, ignoreCase = true)) {                  AccountRow( -                    primaryText = displayName, -                    secondaryText = entry.userName, -                    modifier = Modifier.padding(top = 10.dp), +                    primaryText = entry.userName,                  )              } else {                  AccountRow( -                    primaryText = entry.userName, -                    modifier = Modifier.padding(top = 10.dp), +                    primaryText = displayName, +                    secondaryText = entry.userName,                  )              }          }, @@ -77,8 +78,11 @@ fun SignInWithProviderScreen(              val selectEntry = flowEngine.getEntrySelector()              Column {                  ContinueChip { selectEntry(entry, false) } +                CredentialsScreenChipSpacer()                  SignInOptionsChip{ flowEngine.openSecondaryScreen() } +                CredentialsScreenChipSpacer()                  DismissChip { flowEngine.cancel() } +                BottomSpacer()              }          }      } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialSelectorTheme.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialSelectorTheme.kt new file mode 100644 index 000000000000..ee0ba7ba2274 --- /dev/null +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialSelectorTheme.kt @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.credentialmanager.ui.theme + +import android.content.Context +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.annotation.StringRes +import androidx.wear.compose.material.Colors +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.font.DeviceFontFamilyName +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.wear.compose.material.Typography +import androidx.wear.compose.material.MaterialTheme +import com.android.credentialmanager.R +import androidx.compose.ui.graphics.Color + +/** The Material 3 Theme Wrapper for Supporting RRO. */ +@Composable +fun WearCredentialSelectorTheme(content: @Composable () -> Unit) { +    val context = LocalContext.current +    val colors = +        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { +            overlayColors(context) +                .copy(error = MaterialTheme.colors.error, onError = MaterialTheme.colors.onError) +        } else { +            MaterialTheme.colors +        } +    MaterialTheme(colors = colors, typography = deviceDefaultTypography(context), content = content) +} + +/** + * Creates a dynamic color maps that can be overlaid. 100 - Lightest shade; 0 - Darkest Shade; In + * wear we only support dark theme for the time being. Thus the fill colors and variants are dark + * and anything on top is light. We will use this custom redirection until wear compose material + * supports color scheming. + * + * The mapping is best case match on wear material color tokens from + * /android/clockwork/common/wearable/wearmaterial/color/res/values/color-tokens.xml + * + * @param context The context required to get system resource data. + */ +@RequiresApi(Build.VERSION_CODES.S) +internal fun overlayColors(context: Context): Colors { +    val tonalPalette = dynamicTonalPalette(context) +    return Colors( +        background = Color.Black, +        onBackground = Color.White, +        primary = tonalPalette.primary90, +        primaryVariant = tonalPalette.primary80, +        onPrimary = tonalPalette.primary10, +        secondary = tonalPalette.tertiary90, +        secondaryVariant = tonalPalette.tertiary60, +        onSecondary = tonalPalette.tertiary10, +        surface = tonalPalette.neutral20, +        onSurface = tonalPalette.neutral95, +        onSurfaceVariant = tonalPalette.neutralVariant80, +    ) +} + +private fun fontFamily(context: Context, @StringRes id: Int): FontFamily { +    val typefaceName = context.resources.getString(id) +    val font = Font(familyName = DeviceFontFamilyName(typefaceName)) +    return FontFamily(font) +} + +/* + Only customizes font family. The material 3 roles to 2.5 are mapped to the best case matching of + google3/java/com/google/android/wearable/libraries/compose/theme/GoogleMaterialTheme.kt +*/ +internal fun deviceDefaultTypography(context: Context): Typography { +    val defaultTypography = Typography() +    return Typography( +        display1 = +        defaultTypography.display1.copy( +            fontFamily = +            fontFamily(context, R.string.wear_material_compose_display_1_font_family) +        ), +        display2 = +        defaultTypography.display2.copy( +            fontFamily = +            fontFamily(context, R.string.wear_material_compose_display_2_font_family) +        ), +        display3 = +        defaultTypography.display1.copy( +            fontFamily = +            fontFamily(context, R.string.wear_material_compose_display_3_font_family) +        ), +        title1 = +        defaultTypography.title1.copy( +            fontFamily = fontFamily(context, R.string.wear_material_compose_title_1_font_family) +        ), +        title2 = +        defaultTypography.title2.copy( +            fontFamily = fontFamily(context, R.string.wear_material_compose_title_2_font_family) +        ), +        title3 = +        defaultTypography.title3.copy( +            fontFamily = fontFamily(context, R.string.wear_material_compose_title_3_font_family) +        ), +        body1 = +        defaultTypography.body1.copy( +            fontFamily = fontFamily(context, R.string.wear_material_compose_body_1_font_family) +        ), +        body2 = +        defaultTypography.body2.copy( +            fontFamily = fontFamily(context, R.string.wear_material_compose_body_2_font_family) +        ), +        button = +        defaultTypography.button.copy( +            fontFamily = fontFamily(context, R.string.wear_material_compose_button_font_family) +        ), +        caption1 = +        defaultTypography.caption1.copy( +            fontFamily = +            fontFamily(context, R.string.wear_material_compose_caption_1_font_family) +        ), +        caption2 = +        defaultTypography.caption2.copy( +            fontFamily = +            fontFamily(context, R.string.wear_material_compose_caption_2_font_family) +        ), +        caption3 = +        defaultTypography.caption3.copy( +            fontFamily = +            fontFamily(context, R.string.wear_material_compose_caption_3_font_family) +        ), +    ) +}
\ No newline at end of file diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialTonalPalette.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialTonalPalette.kt new file mode 100644 index 000000000000..1d6ed33e65e2 --- /dev/null +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/theme/WearCredentialTonalPalette.kt @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.credentialmanager.ui.theme + +import android.R +import android.content.Context +import android.os.Build +import androidx.annotation.ColorRes +import androidx.annotation.DoNotInline +import androidx.annotation.RequiresApi + +import androidx.compose.ui.graphics.Color + +/** + * Tonal Palette structure in Material. + * + * A tonal palette is comprised of 5 tonal ranges. Each tonal range includes the 13 stops, or tonal + * swatches. + * + * Tonal range names are: + * - Neutral (N) + * - Neutral variant (NV) + * - Primary (P) + * - Secondary (S) + * - Tertiary (T) + */ +internal class WearCredentialSelectorTonalPalette( +    // The neutral tonal range. +    val neutral100: Color, +    val neutral99: Color, +    val neutral95: Color, +    val neutral90: Color, +    val neutral80: Color, +    val neutral70: Color, +    val neutral60: Color, +    val neutral50: Color, +    val neutral40: Color, +    val neutral30: Color, +    val neutral20: Color, +    val neutral10: Color, +    val neutral0: Color, + +    // The neutral variant tonal range, sometimes called "neutral 2" +    val neutralVariant100: Color, +    val neutralVariant99: Color, +    val neutralVariant95: Color, +    val neutralVariant90: Color, +    val neutralVariant80: Color, +    val neutralVariant70: Color, +    val neutralVariant60: Color, +    val neutralVariant50: Color, +    val neutralVariant40: Color, +    val neutralVariant30: Color, +    val neutralVariant20: Color, +    val neutralVariant10: Color, +    val neutralVariant0: Color, + +    // The primary tonal range, also known as accent 1 +    val primary100: Color, +    val primary99: Color, +    val primary95: Color, +    val primary90: Color, +    val primary80: Color, +    val primary70: Color, +    val primary60: Color, +    val primary50: Color, +    val primary40: Color, +    val primary30: Color, +    val primary20: Color, +    val primary10: Color, +    val primary0: Color, + +    // The Secondary tonal range, also know as accent 2 +    val secondary100: Color, +    val secondary99: Color, +    val secondary95: Color, +    val secondary90: Color, +    val secondary80: Color, +    val secondary70: Color, +    val secondary60: Color, +    val secondary50: Color, +    val secondary40: Color, +    val secondary30: Color, +    val secondary20: Color, +    val secondary10: Color, +    val secondary0: Color, + +    // The tertiary tonal range, also known as accent 3 +    val tertiary100: Color, +    val tertiary99: Color, +    val tertiary95: Color, +    val tertiary90: Color, +    val tertiary80: Color, +    val tertiary70: Color, +    val tertiary60: Color, +    val tertiary50: Color, +    val tertiary40: Color, +    val tertiary30: Color, +    val tertiary20: Color, +    val tertiary10: Color, +    val tertiary0: Color, +) +/** Dynamic colors for wear compose material to support resource overlay. */ +@RequiresApi(Build.VERSION_CODES.S) +// TODO: once we have proper support for this on Wear 6+, we will do something similar to +// https://source.corp.google.com/h/android/platform/superproject/+/androidx-main:frameworks/support/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DynamicTonalPalette.android.kt;l=307-362?q=dynamicTonalPalette&sq=repo:android%2Fplatform%2Fsuperproject%20b:androidx-main +// Tracking Bug: b/270720571 +internal fun dynamicTonalPalette(context: Context) = +    WearCredentialSelectorTonalPalette( +        // The neutral tonal range from the generated dynamic color palette. +        neutral100 = ColorResourceHelper.getColor(context, R.color.system_neutral1_0), +        neutral99 = ColorResourceHelper.getColor(context, R.color.system_neutral1_10), +        neutral95 = ColorResourceHelper.getColor(context, R.color.system_neutral1_50), +        neutral90 = ColorResourceHelper.getColor(context, R.color.system_neutral1_100), +        neutral80 = ColorResourceHelper.getColor(context, R.color.system_neutral1_200), +        neutral70 = ColorResourceHelper.getColor(context, R.color.system_neutral1_300), +        neutral60 = ColorResourceHelper.getColor(context, R.color.system_neutral1_400), +        neutral50 = ColorResourceHelper.getColor(context, R.color.system_neutral1_500), +        neutral40 = ColorResourceHelper.getColor(context, R.color.system_neutral1_600), +        neutral30 = ColorResourceHelper.getColor(context, R.color.system_neutral1_700), +        neutral20 = ColorResourceHelper.getColor(context, R.color.system_neutral1_800), +        neutral10 = ColorResourceHelper.getColor(context, R.color.system_neutral1_900), +        neutral0 = ColorResourceHelper.getColor(context, R.color.system_neutral1_1000), + +        // The neutral variant tonal range, sometimes called "neutral 2",  from the +        // generated dynamic color palette. +        neutralVariant100 = ColorResourceHelper.getColor(context, R.color.system_neutral2_0), +        neutralVariant99 = ColorResourceHelper.getColor(context, R.color.system_neutral2_10), +        neutralVariant95 = ColorResourceHelper.getColor(context, R.color.system_neutral2_50), +        neutralVariant90 = ColorResourceHelper.getColor(context, R.color.system_neutral2_100), +        neutralVariant80 = ColorResourceHelper.getColor(context, R.color.system_neutral2_200), +        neutralVariant70 = ColorResourceHelper.getColor(context, R.color.system_neutral2_300), +        neutralVariant60 = ColorResourceHelper.getColor(context, R.color.system_neutral2_400), +        neutralVariant50 = ColorResourceHelper.getColor(context, R.color.system_neutral2_500), +        neutralVariant40 = ColorResourceHelper.getColor(context, R.color.system_neutral2_600), +        neutralVariant30 = ColorResourceHelper.getColor(context, R.color.system_neutral2_700), +        neutralVariant20 = ColorResourceHelper.getColor(context, R.color.system_neutral2_800), +        neutralVariant10 = ColorResourceHelper.getColor(context, R.color.system_neutral2_900), +        neutralVariant0 = ColorResourceHelper.getColor(context, R.color.system_neutral2_1000), + +        // The primary tonal range from the generated dynamic color palette. +        primary100 = ColorResourceHelper.getColor(context, R.color.system_accent1_0), +        primary99 = ColorResourceHelper.getColor(context, R.color.system_accent1_10), +        primary95 = ColorResourceHelper.getColor(context, R.color.system_accent1_50), +        primary90 = ColorResourceHelper.getColor(context, R.color.system_accent1_100), +        primary80 = ColorResourceHelper.getColor(context, R.color.system_accent1_200), +        primary70 = ColorResourceHelper.getColor(context, R.color.system_accent1_300), +        primary60 = ColorResourceHelper.getColor(context, R.color.system_accent1_400), +        primary50 = ColorResourceHelper.getColor(context, R.color.system_accent1_500), +        primary40 = ColorResourceHelper.getColor(context, R.color.system_accent1_600), +        primary30 = ColorResourceHelper.getColor(context, R.color.system_accent1_700), +        primary20 = ColorResourceHelper.getColor(context, R.color.system_accent1_800), +        primary10 = ColorResourceHelper.getColor(context, R.color.system_accent1_900), +        primary0 = ColorResourceHelper.getColor(context, R.color.system_accent1_1000), + +        // The secondary tonal range from the generated dynamic color palette. +        secondary100 = ColorResourceHelper.getColor(context, R.color.system_accent2_0), +        secondary99 = ColorResourceHelper.getColor(context, R.color.system_accent2_10), +        secondary95 = ColorResourceHelper.getColor(context, R.color.system_accent2_50), +        secondary90 = ColorResourceHelper.getColor(context, R.color.system_accent2_100), +        secondary80 = ColorResourceHelper.getColor(context, R.color.system_accent2_200), +        secondary70 = ColorResourceHelper.getColor(context, R.color.system_accent2_300), +        secondary60 = ColorResourceHelper.getColor(context, R.color.system_accent2_400), +        secondary50 = ColorResourceHelper.getColor(context, R.color.system_accent2_500), +        secondary40 = ColorResourceHelper.getColor(context, R.color.system_accent2_600), +        secondary30 = ColorResourceHelper.getColor(context, R.color.system_accent2_700), +        secondary20 = ColorResourceHelper.getColor(context, R.color.system_accent2_800), +        secondary10 = ColorResourceHelper.getColor(context, R.color.system_accent2_900), +        secondary0 = ColorResourceHelper.getColor(context, R.color.system_accent2_1000), + +        // The tertiary tonal range from the generated dynamic color palette. +        tertiary100 = ColorResourceHelper.getColor(context, R.color.system_accent3_0), +        tertiary99 = ColorResourceHelper.getColor(context, R.color.system_accent3_10), +        tertiary95 = ColorResourceHelper.getColor(context, R.color.system_accent3_50), +        tertiary90 = ColorResourceHelper.getColor(context, R.color.system_accent3_100), +        tertiary80 = ColorResourceHelper.getColor(context, R.color.system_accent3_200), +        tertiary70 = ColorResourceHelper.getColor(context, R.color.system_accent3_300), +        tertiary60 = ColorResourceHelper.getColor(context, R.color.system_accent3_400), +        tertiary50 = ColorResourceHelper.getColor(context, R.color.system_accent3_500), +        tertiary40 = ColorResourceHelper.getColor(context, R.color.system_accent3_600), +        tertiary30 = ColorResourceHelper.getColor(context, R.color.system_accent3_700), +        tertiary20 = ColorResourceHelper.getColor(context, R.color.system_accent3_800), +        tertiary10 = ColorResourceHelper.getColor(context, R.color.system_accent3_900), +        tertiary0 = ColorResourceHelper.getColor(context, R.color.system_accent3_1000), +    ) + +private object ColorResourceHelper { +    @DoNotInline +    fun getColor(context: Context, @ColorRes id: Int): Color { +        return Color(context.resources.getColor(id, context.theme)) +    } +}
\ No newline at end of file diff --git a/packages/InputDevices/res/raw/keyboard_layout_thai_kedmanee.kcm b/packages/InputDevices/res/raw/keyboard_layout_thai_kedmanee.kcm new file mode 100644 index 000000000000..2283032e9450 --- /dev/null +++ b/packages/InputDevices/res/raw/keyboard_layout_thai_kedmanee.kcm @@ -0,0 +1,321 @@ +# Copyright 2024 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +#      http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Thai Kedmanee keyboard layout. +# + +type OVERLAY + +map key 86 PLUS + +### ROW 1 + +key GRAVE { +    label:                              '_' +    base:                               '_' +    shift, capslock:                    '%' +} + +key 1 { +    label:                              '\u0e45' +    base:                               '\u0e45' +    shift, capslock:                    '+' +} + +key 2 { +    label:                              '/' +    base:                               '/' +    shift, capslock:                    '\u0e51' +} + +key 3 { +    label:                              '-' +    base:                               '-' +    shift, capslock:                    '\u0e52' +} + +key 4 { +    label:                              '\u0e20' +    base:                               '\u0e20' +    shift, capslock:                    '\u0e53' +} + +key 5 { +    label:                              '\u0e16' +    base:                               '\u0e16' +    shift, capslock:                    '\u0e54' +} + +key 6 { +    label:                              '\u0e38' +    base:                               '\u0e38' +    shift, capslock:                    '\u0e39' +} + +key 7 { +    label:                              '\u0e36' +    base:                               '\u0e36' +    shift, capslock:                    '\u0e3f' +} + +key 8 { +    label:                              '\u0e04' +    base:                               '\u0e04' +    shift, capslock:                    '\u0e55' +} + +key 9 { +    label:                              '\u0e15' +    base:                               '\u0e15' +    shift, capslock:                    '\u0e56' +} + +key 0 { +    label:                              '\u0e08' +    base:                               '\u0e08' +    shift, capslock:                    '\u0e57' +} + +key MINUS { +    label:                              '\u0e02' +    base:                               '\u0e02' +    shift, capslock:                    '\u0e58' +} + +key EQUALS { +    label:                              '\u0e0a' +    base:                               '\u0e0a' +    shift, capslock:                    '\u0e59' +} + +### ROW 2 + +key Q { +    label:                              '\u0e46' +    base:                               '\u0e46' +    shift, capslock:                    '\u0e50' +} + +key W { +    label:                              '\u0e44' +    base:                               '\u0e44' +    shift, capslock:                    '\u0022' +} + +key E { +    label:                              '\u0e33' +    base:                               '\u0e33' +    shift, capslock:                    '\u0e0e' +} + +key R { +    label:                              '\u0e1e' +    base:                               '\u0e1e' +    shift, capslock:                    '\u0e11' +} + +key T { +    label:                              '\u0e30' +    base:                               '\u0e30' +    shift, capslock:                    '\u0e18' +} + +key Y { +    label:                              '\u0e31' +    base:                               '\u0e31' +    shift, capslock:                    '\u0e4d' +} + +key U { +    label:                              '\u0e35' +    base:                               '\u0e35' +    shift, capslock:                    '\u0e4a' +} + +key I { +    label:                              '\u0e23' +    base:                               '\u0e23' +    shift, capslock:                    '\u0e13' +} + +key O { +    label:                              '\u0e19' +    base:                               '\u0e19' +    shift, capslock:                    '\u0e2f' +} + +key P { +    label:                              '\u0e22' +    base:                               '\u0e22' +    shift, capslock:                    '\u0e0d' +} + +key LEFT_BRACKET { +    label:                              '\u0e1a' +    base:                               '\u0e1a' +    shift, capslock:                    '\u0e10' +    ctrl:                               '%' +} + +key RIGHT_BRACKET { +    label:                              '\u0e25' +    base:                               '\u0e25' +    shift, capslock:                    ',' +    ctrl:                               '\u0e51' +} + +### ROW 3 + +key A { +    label:                              '\u0e1f' +    base:                               '\u0e1f' +    shift, capslock:                    '\u0e24' +} + +key S { +    label:                              '\u0e2b' +    base:                               '\u0e2b' +    shift, capslock:                    '\u0e06' +} + +key D { +    label:                              '\u0e01' +    base:                               '\u0e01' +    shift, capslock:                    '\u0e0f' +} + +key F { +    label:                              '\u0e14' +    base:                               '\u0e14' +    shift, capslock:                    '\u0e42' +} + +key G { +    label:                              '\u0e40' +    base:                               '\u0e40' +    shift, capslock:                    '\u0e0c' +} + +key H { +    label:                              '\u0e49' +    base:                               '\u0e49' +    shift, capslock:                    '\u0e47' +} + +key J { +    label:                              '\u0e48' +    base:                               '\u0e48' +    shift, capslock:                    '\u0e4b' +} + +key K { +    label:                              '\u0e32' +    base:                               '\u0e32' +    shift, capslock:                    '\u0e29' +} + +key L { +    label:                              '\u0e2a' +    base:                               '\u0e2a' +    shift, capslock:                    '\u0e28' +} + +key SEMICOLON { +    label:                              '\u0e27' +    base:                               '\u0e27' +    shift, capslock:                    '\u0e0b' +} + +key APOSTROPHE { +    label:                              '\u0e07' +    base:                               '\u0e07' +    shift, capslock:                    '.' +} + +key BACKSLASH { +    label:                              '\u0e03' +    base:                               '\u0e03' +    shift, capslock:                    '\u0e05' +    ctrl:                               '+' +} + +### ROW 4 + +key PLUS { +    label:                              '\u0e03' +    base:                               '\u0e03' +    shift, capslock:                    '\u0e05' +    ctrl:                               '\u0e52' +} + +key Z { +    label:                              '\u0e1c' +    base:                               '\u0e1c' +    shift, capslock:                    '(' +} + +key X { +    label:                              '\u0e1b' +    base:                               '\u0e1b' +    shift, capslock:                    ')' +} + +key C { +    label:                              '\u0e41' +    base:                               '\u0e41' +    shift, capslock:                    '\u0e09' +} + +key V { +    label:                              '\u0e2d' +    base:                               '\u0e2d' +    shift, capslock:                    '\u0e2e' +} + +key B { +    label:                              '\u0e34' +    base:                               '\u0e34' +    shift, capslock:                    '\u0e3a' +} + +key N { +    label:                              '\u0e37' +    base:                               '\u0e37' +    shift, capslock:                    '\u0e4c' +} + +key M { +    label:                              '\u0e17' +    base:                               '\u0e17' +    shift, capslock:                    '?' +} + +key COMMA { +    label:                              '\u0e21' +    base:                               '\u0e21' +    shift, capslock:                    '\u0e12' +} + +key PERIOD { +    label:                              '\u0e43' +    base:                               '\u0e43' +    shift, capslock:                    '\u0e2c' +} + +key SLASH { +    label:                              '\u0e1d' +    base:                               '\u0e1d' +    shift, capslock:                    '\u0e26' +}
\ No newline at end of file diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml index 7208894e1517..5d0c02211345 100644 --- a/packages/InputDevices/res/values-af/strings.xml +++ b/packages/InputDevices/res/values-af/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarussies"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongools"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgies"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml index 16981501d4aa..39d57173dbfd 100644 --- a/packages/InputDevices/res/values-am/strings.xml +++ b/packages/InputDevices/res/values-am/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"ቤላሩስኛ"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"ሞንጎሊያኛ"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ጂዮርጂያኛ"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml index 8ed19722c6ce..431585349bb3 100644 --- a/packages/InputDevices/res/values-ar/strings.xml +++ b/packages/InputDevices/res/values-ar/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"البيلاروسية"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"المنغولية"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"الجورجية"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-as/strings.xml b/packages/InputDevices/res/values-as/strings.xml index 9744a7d39ef9..01714424dcfd 100644 --- a/packages/InputDevices/res/values-as/strings.xml +++ b/packages/InputDevices/res/values-as/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"বেলাৰুছিয়ান"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolian"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgian"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-az/strings.xml b/packages/InputDevices/res/values-az/strings.xml index ee3a337e3ac4..39a12b7daa79 100644 --- a/packages/InputDevices/res/values-az/strings.xml +++ b/packages/InputDevices/res/values-az/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarus dili"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Monqol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gürcü"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-b+sr+Latn/strings.xml b/packages/InputDevices/res/values-b+sr+Latn/strings.xml index 1fc84f3aee11..64aa7f63490c 100644 --- a/packages/InputDevices/res/values-b+sr+Latn/strings.xml +++ b/packages/InputDevices/res/values-b+sr+Latn/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"beloruski"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongolska"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruzijska"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-be/strings.xml b/packages/InputDevices/res/values-be/strings.xml index 50c591088563..a8c11bee63af 100644 --- a/packages/InputDevices/res/values-be/strings.xml +++ b/packages/InputDevices/res/values-be/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Беларуская"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Мангольская"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Грузінская"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml index 1ee9565a666b..6d82a0b03bf4 100644 --- a/packages/InputDevices/res/values-bg/strings.xml +++ b/packages/InputDevices/res/values-bg/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"беларуски"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"монголски"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"грузински"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-bn/strings.xml b/packages/InputDevices/res/values-bn/strings.xml index a9965385fdbc..3fc13157d5d6 100644 --- a/packages/InputDevices/res/values-bn/strings.xml +++ b/packages/InputDevices/res/values-bn/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"বেলারুশীয়"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"মঙ্গোলিয়ান"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"জর্জিয়ান"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-bs/strings.xml b/packages/InputDevices/res/values-bs/strings.xml index c6cacbc93552..b2cf5257010d 100644 --- a/packages/InputDevices/res/values-bs/strings.xml +++ b/packages/InputDevices/res/values-bs/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"bjeloruska"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongolski"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruzijski"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml index 761c248bcdf7..ed04b9434061 100644 --- a/packages/InputDevices/res/values-ca/strings.xml +++ b/packages/InputDevices/res/values-ca/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bielorús"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgià"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml index 3f1b3d0629bd..5cd3ff5708b8 100644 --- a/packages/InputDevices/res/values-cs/strings.xml +++ b/packages/InputDevices/res/values-cs/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"běloruština"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongolština"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruzínština"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml index b160341d003a..4a6c70cb1342 100644 --- a/packages/InputDevices/res/values-da/strings.xml +++ b/packages/InputDevices/res/values-da/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Hviderussisk"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolsk"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgisk"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml index 17d6e4ad8b03..628a7423043d 100644 --- a/packages/InputDevices/res/values-de/strings.xml +++ b/packages/InputDevices/res/values-de/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarussisch"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolisch"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgisch"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml index 1b9b42e0f946..7b9651c1f847 100644 --- a/packages/InputDevices/res/values-el/strings.xml +++ b/packages/InputDevices/res/values-el/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Λευκορωσικά"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Μογγολικά"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Γεωργιανά"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-en-rAU/strings.xml b/packages/InputDevices/res/values-en-rAU/strings.xml index ab48729d5006..76bb2f16abcc 100644 --- a/packages/InputDevices/res/values-en-rAU/strings.xml +++ b/packages/InputDevices/res/values-en-rAU/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarusian"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolian"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgian"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-en-rCA/strings.xml b/packages/InputDevices/res/values-en-rCA/strings.xml index 116178300348..aa4614b600c7 100644 --- a/packages/InputDevices/res/values-en-rCA/strings.xml +++ b/packages/InputDevices/res/values-en-rCA/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarusian"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolian"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgian"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-en-rGB/strings.xml b/packages/InputDevices/res/values-en-rGB/strings.xml index ab48729d5006..76bb2f16abcc 100644 --- a/packages/InputDevices/res/values-en-rGB/strings.xml +++ b/packages/InputDevices/res/values-en-rGB/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarusian"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolian"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgian"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-en-rIN/strings.xml b/packages/InputDevices/res/values-en-rIN/strings.xml index ab48729d5006..76bb2f16abcc 100644 --- a/packages/InputDevices/res/values-en-rIN/strings.xml +++ b/packages/InputDevices/res/values-en-rIN/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarusian"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolian"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgian"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-en-rXC/strings.xml b/packages/InputDevices/res/values-en-rXC/strings.xml index 92c5a5c2f65e..58dbc43add8e 100644 --- a/packages/InputDevices/res/values-en-rXC/strings.xml +++ b/packages/InputDevices/res/values-en-rXC/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarusian"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolian"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgian"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml index b9fe046aa28c..05f5473b691a 100644 --- a/packages/InputDevices/res/values-es-rUS/strings.xml +++ b/packages/InputDevices/res/values-es-rUS/strings.xml @@ -4,7 +4,7 @@      <string name="app_label" msgid="8016145283189546017">"Dispositivos de entrada"</string>      <string name="keyboard_layouts_label" msgid="6688773268302087545">"Teclado de Android"</string>      <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Inglés (Reino Unido)"</string> -    <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Inglés (EE. UU.)"</string> +    <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Inglés (EE.UU.)"</string>      <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglés (EE. UU.), internacional"</string>      <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglés (EE. UU.), Colemak"</string>      <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglés (EE. UU.), Dvorak"</string> @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bielorruso"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml index 216e79fb2599..cd68ad870845 100644 --- a/packages/InputDevices/res/values-es/strings.xml +++ b/packages/InputDevices/res/values-es/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bielorruso"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-et/strings.xml b/packages/InputDevices/res/values-et/strings.xml index 87c486f086cf..9b37264324bf 100644 --- a/packages/InputDevices/res/values-et/strings.xml +++ b/packages/InputDevices/res/values-et/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"valgevene"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongoli"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruusia"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-eu/strings.xml b/packages/InputDevices/res/values-eu/strings.xml index 64628a82fe35..61c64157fdc2 100644 --- a/packages/InputDevices/res/values-eu/strings.xml +++ b/packages/InputDevices/res/values-eu/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bielorrusiarra"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongoliarra"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiarra"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml index a086060a6a17..43892051ba65 100644 --- a/packages/InputDevices/res/values-fa/strings.xml +++ b/packages/InputDevices/res/values-fa/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"بلاروسی"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"مغولی"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"گرجستانی"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml index f3bef4d97117..0e8efff287cb 100644 --- a/packages/InputDevices/res/values-fi/strings.xml +++ b/packages/InputDevices/res/values-fi/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"valkovenäjä"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongoli"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"georgia"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml index 636358248937..e176c7ef2ff3 100644 --- a/packages/InputDevices/res/values-fr-rCA/strings.xml +++ b/packages/InputDevices/res/values-fr-rCA/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Biélorusse"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Géorgien"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-fr/strings.xml b/packages/InputDevices/res/values-fr/strings.xml index 37cde0517feb..4388ec1b396b 100644 --- a/packages/InputDevices/res/values-fr/strings.xml +++ b/packages/InputDevices/res/values-fr/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Biélorusse"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Géorgien"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-gl/strings.xml b/packages/InputDevices/res/values-gl/strings.xml index 9995f79ee732..827071e5c17b 100644 --- a/packages/InputDevices/res/values-gl/strings.xml +++ b/packages/InputDevices/res/values-gl/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belaruso"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Xeorxiano"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-gu/strings.xml b/packages/InputDevices/res/values-gu/strings.xml index 9dfda76c59bc..df095ae6cf7a 100644 --- a/packages/InputDevices/res/values-gu/strings.xml +++ b/packages/InputDevices/res/values-gu/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"બેલારુશિયન"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"મોંગોલિયન"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"જ્યોર્જિઅન"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml index 2562854378d1..550759d185a2 100644 --- a/packages/InputDevices/res/values-hi/strings.xml +++ b/packages/InputDevices/res/values-hi/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"बेलारूसी"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"मंगोलियन"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"जॉर्जियन कीबोर्ड का लेआउट"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml index 6832437e1a4a..e955e77c24c9 100644 --- a/packages/InputDevices/res/values-hr/strings.xml +++ b/packages/InputDevices/res/values-hr/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"bjeloruski"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolski"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gruzijska"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml index f2ac8a2b8085..565bf69a63d6 100644 --- a/packages/InputDevices/res/values-hu/strings.xml +++ b/packages/InputDevices/res/values-hu/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"belarusz"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"grúz"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-hy/strings.xml b/packages/InputDevices/res/values-hy/strings.xml index a6676fe9875a..9722342ff209 100644 --- a/packages/InputDevices/res/values-hy/strings.xml +++ b/packages/InputDevices/res/values-hy/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"բելառուսերեն"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Մոնղոլերեն"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"վրացերեն"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml index 92bd24df2791..19fd692e6822 100644 --- a/packages/InputDevices/res/values-in/strings.xml +++ b/packages/InputDevices/res/values-in/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarusia"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolia"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgia"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-is/strings.xml b/packages/InputDevices/res/values-is/strings.xml index b761a7eb36f0..f76d9d74d52b 100644 --- a/packages/InputDevices/res/values-is/strings.xml +++ b/packages/InputDevices/res/values-is/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"hvítrússneska"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongólska"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"georgíska"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml index a992b8666ba8..ccde851a9dd7 100644 --- a/packages/InputDevices/res/values-it/strings.xml +++ b/packages/InputDevices/res/values-it/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bielorusso"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolo"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml index de9b2767dbd6..4a8b802d7dd1 100644 --- a/packages/InputDevices/res/values-iw/strings.xml +++ b/packages/InputDevices/res/values-iw/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"בלארוסית"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"מונגולית"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"גיאורגית"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml index 6be0b4c7a8e7..b9bab69cbb98 100644 --- a/packages/InputDevices/res/values-ja/strings.xml +++ b/packages/InputDevices/res/values-ja/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"ベラルーシ語"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"モンゴル語"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ジョージア語"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ka/strings.xml b/packages/InputDevices/res/values-ka/strings.xml index 92d94705b0fe..1610d2679735 100644 --- a/packages/InputDevices/res/values-ka/strings.xml +++ b/packages/InputDevices/res/values-ka/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"ბელორუსული"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"მონღოლური"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ქართული"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-kk/strings.xml b/packages/InputDevices/res/values-kk/strings.xml index c8ab7968d844..43bea18f824a 100644 --- a/packages/InputDevices/res/values-kk/strings.xml +++ b/packages/InputDevices/res/values-kk/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Белорус"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Моңғол"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Грузин"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-km/strings.xml b/packages/InputDevices/res/values-km/strings.xml index fd63ab33cd03..eb4324715940 100644 --- a/packages/InputDevices/res/values-km/strings.xml +++ b/packages/InputDevices/res/values-km/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"បេឡារុស"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"មុងហ្គោលី"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ហ្សកហ្ស៊ី"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-kn/strings.xml b/packages/InputDevices/res/values-kn/strings.xml index 761b7ccef00e..575058515cc7 100644 --- a/packages/InputDevices/res/values-kn/strings.xml +++ b/packages/InputDevices/res/values-kn/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"ಬೆಲರೂಸಿಯನ್"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"ಮಂಗೋಲಿಯನ್"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ಜಾರ್ಜಿಯನ್"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml index 2a1cbb00174b..b44249208bae 100644 --- a/packages/InputDevices/res/values-ko/strings.xml +++ b/packages/InputDevices/res/values-ko/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"벨라루스어"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"몽골어"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"조지아어"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ky/strings.xml b/packages/InputDevices/res/values-ky/strings.xml index 70295e1859a8..36cd53990d1d 100644 --- a/packages/InputDevices/res/values-ky/strings.xml +++ b/packages/InputDevices/res/values-ky/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Беларусча"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Монголчо"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Грузинче"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-lo/strings.xml b/packages/InputDevices/res/values-lo/strings.xml index 2b8946b43d64..ab64e24ae5db 100644 --- a/packages/InputDevices/res/values-lo/strings.xml +++ b/packages/InputDevices/res/values-lo/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"ເບລາຣັສຊຽນ"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"ມອງໂກລຽນ"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ຈໍຈຽນ"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml index 5fca46bf3e5a..ec9893753c94 100644 --- a/packages/InputDevices/res/values-lt/strings.xml +++ b/packages/InputDevices/res/values-lt/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Baltarusių k."</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolų"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gruzinų"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml index d2253297c8ff..05e5d2f79bc9 100644 --- a/packages/InputDevices/res/values-lv/strings.xml +++ b/packages/InputDevices/res/values-lv/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Baltkrievu"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongoļu"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gruzīnu"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-mk/strings.xml b/packages/InputDevices/res/values-mk/strings.xml index d98b58b8d799..c2bc8c076187 100644 --- a/packages/InputDevices/res/values-mk/strings.xml +++ b/packages/InputDevices/res/values-mk/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"белоруски"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"монголски"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"грузиски"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ml/strings.xml b/packages/InputDevices/res/values-ml/strings.xml index f3468810decd..33f8f2252236 100644 --- a/packages/InputDevices/res/values-ml/strings.xml +++ b/packages/InputDevices/res/values-ml/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"ബെലാറുഷ്യൻ"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"മംഗോളിയൻ"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ജോര്ജ്ജിയൻ"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-mn/strings.xml b/packages/InputDevices/res/values-mn/strings.xml index 16970971243a..7aad90dc6c92 100644 --- a/packages/InputDevices/res/values-mn/strings.xml +++ b/packages/InputDevices/res/values-mn/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Беларусь хэл"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Монгол"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Гүрж"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-mr/strings.xml b/packages/InputDevices/res/values-mr/strings.xml index 6382f6fc4d61..db607e3960e6 100644 --- a/packages/InputDevices/res/values-mr/strings.xml +++ b/packages/InputDevices/res/values-mr/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"बेलारुशियन"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"मंगोलियन"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"जॉर्जियन"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ms/strings.xml b/packages/InputDevices/res/values-ms/strings.xml index 9bff171385ee..9a001260ac7e 100644 --- a/packages/InputDevices/res/values-ms/strings.xml +++ b/packages/InputDevices/res/values-ms/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bahasa Belarus"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Bahasa Mongolia"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Bahasa Georgia"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-my/strings.xml b/packages/InputDevices/res/values-my/strings.xml index 01b55074d9f7..d87a7b4cf9a1 100644 --- a/packages/InputDevices/res/values-my/strings.xml +++ b/packages/InputDevices/res/values-my/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"ဘီလာရုဇ်"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"မွန်ဂိုလီးယား"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ဂျော်ဂျီယာ"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml index 40eb25ad9f23..fbefd3866520 100644 --- a/packages/InputDevices/res/values-nb/strings.xml +++ b/packages/InputDevices/res/values-nb/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarusisk"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolsk"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgisk"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ne/strings.xml b/packages/InputDevices/res/values-ne/strings.xml index 6e98bf6d9384..642fc5c73bcc 100644 --- a/packages/InputDevices/res/values-ne/strings.xml +++ b/packages/InputDevices/res/values-ne/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"बेलारुसियाली"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"मङ्गोलियाली"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"जर्जियाली"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml index f3a58142f461..a93772f7b23d 100644 --- a/packages/InputDevices/res/values-nl/strings.xml +++ b/packages/InputDevices/res/values-nl/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Wit-Russisch"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongools"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgisch"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-or/strings.xml b/packages/InputDevices/res/values-or/strings.xml index 5b6aaea9ddf9..47af22e3a879 100644 --- a/packages/InputDevices/res/values-or/strings.xml +++ b/packages/InputDevices/res/values-or/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"ବେଲାରୁସିଆନ୍"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"ମଙ୍ଗୋଲିଆନ୍"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ଜର୍ଜିଆନ୍"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-pa/strings.xml b/packages/InputDevices/res/values-pa/strings.xml index 988b4492d5f3..c634223f0d79 100644 --- a/packages/InputDevices/res/values-pa/strings.xml +++ b/packages/InputDevices/res/values-pa/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"ਬੇਲਾਰੂਸੀ"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"ਮੰਗੋਲੀਆਈ"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ਜਾਰਜੀਆਈ"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml index 4d1821594736..232a50590f36 100644 --- a/packages/InputDevices/res/values-pl/strings.xml +++ b/packages/InputDevices/res/values-pl/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"białoruski"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongolski"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruziński"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-pt-rBR/strings.xml b/packages/InputDevices/res/values-pt-rBR/strings.xml index e44f4ae131f9..aba7afc444fb 100644 --- a/packages/InputDevices/res/values-pt-rBR/strings.xml +++ b/packages/InputDevices/res/values-pt-rBR/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bielorrusso"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml index 3ad3e638a680..3d7c603abc79 100644 --- a/packages/InputDevices/res/values-pt-rPT/strings.xml +++ b/packages/InputDevices/res/values-pt-rPT/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bielorrusso"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml index e44f4ae131f9..aba7afc444fb 100644 --- a/packages/InputDevices/res/values-pt/strings.xml +++ b/packages/InputDevices/res/values-pt/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bielorrusso"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiano"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml index 3867e1cae1d6..4cdd54afcb0f 100644 --- a/packages/InputDevices/res/values-ro/strings.xml +++ b/packages/InputDevices/res/values-ro/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarusă"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolă"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgiană"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml index 7c5c95aebe68..fcdd405cb239 100644 --- a/packages/InputDevices/res/values-ru/strings.xml +++ b/packages/InputDevices/res/values-ru/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"белорусский"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"монгольский"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"грузинский"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-si/strings.xml b/packages/InputDevices/res/values-si/strings.xml index f4147f3008ee..44dfd6038174 100644 --- a/packages/InputDevices/res/values-si/strings.xml +++ b/packages/InputDevices/res/values-si/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"බෙලරුසියානු"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"මොන්ගෝලියානු"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ජෝර්ජියානු"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml index 2a375529c3c7..f02b0be1d412 100644 --- a/packages/InputDevices/res/values-sk/strings.xml +++ b/packages/InputDevices/res/values-sk/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"bieloruské"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongolské"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruzínske"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml index 334326c0954a..ab70e0800f8f 100644 --- a/packages/InputDevices/res/values-sl/strings.xml +++ b/packages/InputDevices/res/values-sl/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"beloruščina"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongolščina"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"gruzinščina"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-sq/strings.xml b/packages/InputDevices/res/values-sq/strings.xml index 0863138423b4..d01b2bcf1af0 100644 --- a/packages/InputDevices/res/values-sq/strings.xml +++ b/packages/InputDevices/res/values-sq/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Bjellorusisht"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolisht"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gjeorgjisht"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml index 973b833e6a6a..88978f65712b 100644 --- a/packages/InputDevices/res/values-sr/strings.xml +++ b/packages/InputDevices/res/values-sr/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"белоруски"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"монголска"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"грузијска"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml index b1e5d755b788..a255d248e1f8 100644 --- a/packages/InputDevices/res/values-sv/strings.xml +++ b/packages/InputDevices/res/values-sv/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"vitryska"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongoliska"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"georgiska"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml index 0f4c8466e47e..00979e5fc691 100644 --- a/packages/InputDevices/res/values-sw/strings.xml +++ b/packages/InputDevices/res/values-sw/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Kibelarusi"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Kimongolia"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Kijojia"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ta/strings.xml b/packages/InputDevices/res/values-ta/strings.xml index d3535d440981..355f78dc40c9 100644 --- a/packages/InputDevices/res/values-ta/strings.xml +++ b/packages/InputDevices/res/values-ta/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"பெலரூசியன்"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"மங்கோலியன்"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ஜார்ஜியன்"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-te/strings.xml b/packages/InputDevices/res/values-te/strings.xml index 5a10f6e03f71..1fe885d4d467 100644 --- a/packages/InputDevices/res/values-te/strings.xml +++ b/packages/InputDevices/res/values-te/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"బెలారష్యన్"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"మంగోలియన్"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"జార్జియన్"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml index 131c53613beb..f1b433b7e358 100644 --- a/packages/InputDevices/res/values-th/strings.xml +++ b/packages/InputDevices/res/values-th/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"เบลารุส"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"ภาษามองโกเลีย"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"ภาษาจอร์เจีย"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-tl/strings.xml b/packages/InputDevices/res/values-tl/strings.xml index c42adbcbd785..21ad90927f2e 100644 --- a/packages/InputDevices/res/values-tl/strings.xml +++ b/packages/InputDevices/res/values-tl/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarusian"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongolian"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgian"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml index 1a84d0acf276..a1ac7fd5003a 100644 --- a/packages/InputDevices/res/values-tr/strings.xml +++ b/packages/InputDevices/res/values-tr/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarusça"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Moğolca"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gürcüce"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml index 71b3496c929f..dcc5bcf52a59 100644 --- a/packages/InputDevices/res/values-uk/strings.xml +++ b/packages/InputDevices/res/values-uk/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Білоруська"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Монгольська"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Грузинська"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-ur/strings.xml b/packages/InputDevices/res/values-ur/strings.xml index 0cc9b61ed5ec..e8f327c05c7e 100644 --- a/packages/InputDevices/res/values-ur/strings.xml +++ b/packages/InputDevices/res/values-ur/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"بيلاروسی"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"منگؤلی"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"جارجیائی"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-uz/strings.xml b/packages/InputDevices/res/values-uz/strings.xml index 52ecdfca5492..0968d7a68bdf 100644 --- a/packages/InputDevices/res/values-uz/strings.xml +++ b/packages/InputDevices/res/values-uz/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarus"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Mongol"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Gruzin"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml index 0c638faaecd0..f7c3658e9b08 100644 --- a/packages/InputDevices/res/values-vi/strings.xml +++ b/packages/InputDevices/res/values-vi/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Tiếng Belarus"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"Tiếng Mông Cổ"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Tiếng Georgia"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml index b24977982bce..7d0a12838889 100644 --- a/packages/InputDevices/res/values-zh-rCN/strings.xml +++ b/packages/InputDevices/res/values-zh-rCN/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"白俄罗斯语"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"蒙古语"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"格鲁吉亚语"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml index 60a52e98ae98..a0c3c1a52ca5 100644 --- a/packages/InputDevices/res/values-zh-rHK/strings.xml +++ b/packages/InputDevices/res/values-zh-rHK/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"白俄羅斯文"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"蒙古文"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"格魯吉亞文"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml index c3217e368492..1b8484171953 100644 --- a/packages/InputDevices/res/values-zh-rTW/strings.xml +++ b/packages/InputDevices/res/values-zh-rTW/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"白俄羅斯文"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"蒙古文"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"喬治亞文"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml index 88d55f2ff32a..c4b5d7a73acc 100644 --- a/packages/InputDevices/res/values-zu/strings.xml +++ b/packages/InputDevices/res/values-zu/strings.xml @@ -50,4 +50,6 @@      <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"Belarusian"</string>      <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"isi-Mongolian"</string>      <string name="keyboard_layout_georgian" msgid="4596185456863747454">"Georgian"</string> +    <!-- no translation found for keyboard_layout_thai_kedmanee (6637147314580760938) --> +    <skip />  </resources> diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml index 1e1394096926..33a1d760f417 100644 --- a/packages/InputDevices/res/values/strings.xml +++ b/packages/InputDevices/res/values/strings.xml @@ -146,4 +146,7 @@      <!-- Georgian keyboard layout label. [CHAR LIMIT=35] -->      <string name="keyboard_layout_georgian">Georgian</string> + +    <!-- Thai (Kedmanee variant) keyboard layout label. [CHAR LIMIT=35] --> +    <string name="keyboard_layout_thai_kedmanee">Thai (Kedmanee)</string>  </resources> diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml index ee49b23b3860..4b7ea90eeb38 100644 --- a/packages/InputDevices/res/xml/keyboard_layouts.xml +++ b/packages/InputDevices/res/xml/keyboard_layouts.xml @@ -318,4 +318,11 @@          android:label="@string/keyboard_layout_georgian"          android:keyboardLayout="@raw/keyboard_layout_georgian"          android:keyboardLocale="ka-Geor" /> + +    <keyboard-layout +        android:name="keyboard_layout_thai_kedmanee" +        android:label="@string/keyboard_layout_thai_kedmanee" +        android:keyboardLayout="@raw/keyboard_layout_thai_kedmanee" +        android:keyboardLocale="th-Thai" +        android:keyboardLayoutType="extended" />  </keyboard-layouts> diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml index e788bf7e2f8f..55f960d3af2b 100644 --- a/packages/PackageInstaller/res/values-ky/strings.xml +++ b/packages/PackageInstaller/res/values-ky/strings.xml @@ -63,7 +63,7 @@      <string name="archive_application_text_all_users" msgid="3151229641681672580">"Бул колдонмо бардык колдонуучулар үчүн архивделсинби? Жеке маалыматыңыз сакталат"</string>      <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"Бул колдонмо жумуш профилиңизде архивделсинби? Жеке маалыматыңыз сакталат"</string>      <string name="archive_application_text_user" msgid="2586558895535581451">"Бул колдонмо <xliff:g id="USERNAME">%1$s</xliff:g> үчүн архивделсинби? Жеке маалыматыңыз сакталат"</string> -    <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Бул колдонмо жеке чөйрөдөн архивделсинби? Жеке маалыматыңыз сакталат"</string> +    <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"Бул колдонмо жеке мейкиндиктен архивделсинби? Жеке маалыматыңыз сакталат"</string>      <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Бул колдонмо "<b>"бардык"</b>" колдонуучулардан алынып салынсынбы? Бул колдонмо жана анын дайындары бул түзмөктүн "<b>"бардык"</b>" колдонуучуларынан өчүрүлөт."</string>      <string name="uninstall_application_text_user" msgid="498072714173920526">"Бул колдонмону <xliff:g id="USERNAME">%1$s</xliff:g> үчүн чыгарып саласызбы?"</string>      <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Бул колдонмону жумуш профилиңизден чыгарып саласызбы?"</string> @@ -72,7 +72,7 @@      <string name="uninstall_keep_data" msgid="7002379587465487550">"Колдонмонун <xliff:g id="SIZE">%1$s</xliff:g> дайындарын сактоо."</string>      <string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Бул колдонмону өчүрөсүзбү?"</string>      <string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Бул колдонмону чыгарып саласызбы? <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> клону да өчүрүлөт."</string> -    <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Бул колдонмону жеке чөйрөдөн чыгарып саласызбы?"</string> +    <string name="uninstall_application_text_current_user_private_profile" msgid="867004464945674674">"Бул колдонмону жеке мейкиндиктен чыгарып саласызбы?"</string>      <string name="uninstalling_notification_channel" msgid="840153394325714653">"Чыгарылып салынууда"</string>      <string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Чыгарылып салынбай калгандар"</string>      <string name="uninstalling" msgid="8709566347688966845">"Чыгарылып салынууда…"</string> diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml index 149783d9f5f8..bd288e4bde17 100644 --- a/packages/PackageInstaller/res/values-nl/strings.xml +++ b/packages/PackageInstaller/res/values-nl/strings.xml @@ -98,7 +98,7 @@      <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Uit veiligheidsoverwegingen heeft je tv momenteel geen toestemming om onbekende apps van deze bron te installeren. Je kunt dit wijzigen via Instellingen."</string>      <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"Uit veiligheidsoverwegingen heeft je smartwatch momenteel geen toestemming om onbekende apps van deze bron te installeren. Je kunt dit wijzigen via Instellingen."</string>      <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Uit veiligheidsoverwegingen heeft je telefoon momenteel geen toestemming om onbekende apps van deze bron te installeren. Je kunt dit wijzigen via Instellingen."</string> -    <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Je telefoon en persoonsgegevens zijn kwetsbaarder voor aanvallen door onbekende apps. Als je deze app installeert, ga je ermee akkoord dat je verantwoordelijk bent voor eventuele schade aan je telefoon of gegevensverlies als gevolg van het gebruik van de app."</string> +    <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Je telefoon en persoonsgegevens zijn kwetsbaarder voor aanvallen door onbekende apps. Door deze app te installeren, ga je ermee akkoord dat je verantwoordelijk bent voor eventuele schade aan je telefoon of gegevensverlies als gevolg van het gebruik van de app."</string>      <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Je tablet en persoonsgegevens zijn kwetsbaarder voor aanvallen door onbekende apps. Als je deze app installeert, ga je ermee akkoord dat je verantwoordelijk bent voor eventuele schade aan je tablet of gegevensverlies als gevolg van het gebruik van de app."</string>      <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Je tv en persoonsgegevens zijn kwetsbaarder voor aanvallen door onbekende apps. Als je deze app installeert, ga je ermee akkoord dat je verantwoordelijk bent voor eventuele schade aan je tv of gegevensverlies als gevolg van het gebruik van de app."</string>      <string name="cloned_app_label" msgid="7503612829833756160">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-kloon"</string> diff --git a/packages/PackageInstaller/res/values-th/strings.xml b/packages/PackageInstaller/res/values-th/strings.xml index 7f3708432a19..739d2726b56c 100644 --- a/packages/PackageInstaller/res/values-th/strings.xml +++ b/packages/PackageInstaller/res/values-th/strings.xml @@ -94,10 +94,10 @@      <string name="Parse_error_dlg_text" msgid="1661404001063076789">"พบปัญหาในการแยกวิเคราะห์แพ็กเกจ"</string>      <string name="message_staging" msgid="8032722385658438567">"กำลังปรับสภาพแวดล้อมของแอป…"</string>      <string name="app_name_unknown" msgid="6881210203354323926">"ไม่ทราบ"</string> -    <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"เพื่อความปลอดภัย ปัจจุบันไม่อนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้ในแท็บเล็ต คุณเปลี่ยนแปลงได้ในการตั้งค่า"</string> -    <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"เพื่อความปลอดภัย ปัจจุบันไม่อนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้ในทีวี คุณเปลี่ยนแปลงได้ในการตั้งค่า"</string> -    <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"ปัจจุบันนาฬิกาไม่อนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้เพื่อความปลอดภัยของคุณ คุณเปลี่ยนค่านี้ได้ในการตั้งค่า"</string> -    <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"เพื่อความปลอดภัย ปัจจุบันไม่อนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้ในโทรศัพท์ ซึ่งคุณเปลี่ยนเป็นอนุญาตได้ในการตั้งค่า"</string> +    <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"เพื่อความปลอดภัย โทรศัพท์ของคุณไม่ได้รับอนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้ คุณสามารถเปลี่ยนแปลงได้ที่ \"การตั้งค่า\""</string> +    <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"เพื่อความปลอดภัย โทรศัพท์ของคุณไม่ได้รับอนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้ คุณสามารถเปลี่ยนแปลงได้ที่ \"การตั้งค่า\""</string> +    <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"เพื่อความปลอดภัย นาฬิกาของคุณไม่ได้รับอนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้ คุณสามารถเปลี่ยนแปลงได้ที่ \"การตั้งค่า\""</string> +    <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"เพื่อความปลอดภัย โทรศัพท์ของคุณไม่ได้รับอนุญาตให้ติดตั้งแอปที่ไม่รู้จักจากแหล่งที่มานี้ คุณสามารถเปลี่ยนแปลงได้ที่ \"การตั้งค่า\""</string>      <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"โทรศัพท์และข้อมูลส่วนตัวของคุณมีความเสี่ยงมากขึ้นที่จะถูกโจมตีจากแอปที่ไม่รู้จัก การติดตั้งแอปนี้แสดงว่าคุณยอมรับว่าจะรับผิดชอบต่อความเสียหายใดๆ ที่จะเกิดขึ้นกับโทรศัพท์หรือการสูญเสียข้อมูลที่อาจเกิดจากการใช้งานแอปดังกล่าว"</string>      <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"แท็บเล็ตและข้อมูลส่วนตัวของคุณมีความเสี่ยงมากขึ้นที่จะถูกโจมตีจากแอปที่ไม่รู้จัก การติดตั้งแอปนี้แสดงว่าคุณยอมรับว่าจะรับผิดชอบต่อความเสียหายใดๆ ที่จะเกิดขึ้นกับแท็บเล็ตหรือการสูญเสียข้อมูลที่อาจเกิดจากการใช้งานแอปดังกล่าว"</string>      <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"ทีวีและข้อมูลส่วนตัวของคุณมีความเสี่ยงมากขึ้นที่จะถูกโจมตีจากแอปที่ไม่รู้จัก การติดตั้งแอปนี้แสดงว่าคุณยอมรับว่าจะรับผิดชอบต่อความเสียหายใดๆ ที่จะเกิดขึ้นกับทีวีหรือการสูญเสียข้อมูลที่อาจเกิดจากการใช้งานแอปดังกล่าว"</string> diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml index 5298f8b329ba..6ffad709b2f3 100644 --- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml +++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml @@ -35,7 +35,7 @@      <string name="install_for_print_preview" msgid="6366303997385509332">"Installer un lecteur PDF pour voir l\'aperçu"</string>      <string name="printing_app_crashed" msgid="854477616686566398">"L\'application à l\'origine de l\'impression a planté"</string>      <string name="generating_print_job" msgid="3119608742651698916">"Génération tâche impression…"</string> -    <string name="save_as_pdf" msgid="5718454119847596853">"Enregistrer en format PDF"</string> +    <string name="save_as_pdf" msgid="5718454119847596853">"Enregistrer au format PDF"</string>      <string name="all_printers" msgid="5018829726861876202">"Toutes les imprimantes…"</string>      <string name="print_dialog" msgid="32628687461331979">"Boîte de dialogue d\'impression"</string>      <string name="current_page_template" msgid="5145005201131935302">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g> sur <xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string> diff --git a/packages/SettingsLib/HelpUtils/res/values-pt-rPT/strings.xml b/packages/SettingsLib/HelpUtils/res/values-pt-rPT/strings.xml index 9095f8e4d750..f0bee5e18709 100644 --- a/packages/SettingsLib/HelpUtils/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/HelpUtils/res/values-pt-rPT/strings.xml @@ -17,5 +17,5 @@  <resources xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> -    <string name="help_feedback_label" msgid="7106780063063027882">"Ajuda e comentários"</string> +    <string name="help_feedback_label" msgid="7106780063063027882">"Ajuda e feedback"</string>  </resources> diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml index fa5df16bf35a..b5534b9c9246 100644 --- a/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml +++ b/packages/SettingsLib/RestrictedLockUtils/res/values-hi/strings.xml @@ -18,5 +18,5 @@  <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="disabled_by_admin" msgid="4023569940620832713">"एडमिन की ओर से बंद किया गया"</string> +    <string name="disabled_by_admin" msgid="4023569940620832713">"एडमिन ने यह सुविधा बंद की है"</string>  </resources> diff --git a/packages/SettingsLib/SearchWidget/res/values-bn/strings.xml b/packages/SettingsLib/SearchWidget/res/values-bn/strings.xml index 23f46bf3d655..473231a10bfc 100644 --- a/packages/SettingsLib/SearchWidget/res/values-bn/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-bn/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-ms/strings.xml b/packages/SettingsLib/SearchWidget/res/values-ms/strings.xml index 0d3a4daf2213..99a9b05b9a62 100644 --- a/packages/SettingsLib/SearchWidget/res/values-ms/strings.xml +++ b/packages/SettingsLib/SearchWidget/res/values-ms/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">"Tetapan carian"</string> +    <string name="search_menu" msgid="1914043873178389845">"Cari tetapan"</string>  </resources> diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt index 761bb7918afd..91bd7916b0ab 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt @@ -40,7 +40,7 @@ import com.android.settingslib.spa.gallery.page.FooterPageProvider  import com.android.settingslib.spa.gallery.page.IllustrationPageProvider  import com.android.settingslib.spa.gallery.page.LoadingBarPageProvider  import com.android.settingslib.spa.gallery.page.ProgressBarPageProvider -import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider +import com.android.settingslib.spa.gallery.scaffold.NonScrollablePagerPageProvider  import com.android.settingslib.spa.gallery.page.SliderPageProvider  import com.android.settingslib.spa.gallery.preference.ListPreferencePageProvider  import com.android.settingslib.spa.gallery.preference.MainSwitchPreferencePageProvider @@ -48,10 +48,12 @@ import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider  import com.android.settingslib.spa.gallery.preference.PreferencePageProvider  import com.android.settingslib.spa.gallery.preference.SwitchPreferencePageProvider  import com.android.settingslib.spa.gallery.preference.TwoTargetSwitchPreferencePageProvider +import com.android.settingslib.spa.gallery.scaffold.PagerMainPageProvider  import com.android.settingslib.spa.gallery.scaffold.SearchScaffoldPageProvider  import com.android.settingslib.spa.gallery.scaffold.SuwScaffoldPageProvider  import com.android.settingslib.spa.gallery.ui.CategoryPageProvider  import com.android.settingslib.spa.gallery.ui.CopyablePageProvider +import com.android.settingslib.spa.gallery.scaffold.ScrollablePagerPageProvider  import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider  import com.android.settingslib.spa.slice.SpaSliceBroadcastReceiver @@ -84,7 +86,9 @@ class GallerySpaEnvironment(context: Context) : SpaEnvironment(context) {                  ArgumentPageProvider,                  SliderPageProvider,                  SpinnerPageProvider, -                SettingsPagerPageProvider, +                PagerMainPageProvider, +                NonScrollablePagerPageProvider, +                ScrollablePagerPageProvider,                  FooterPageProvider,                  IllustrationPageProvider,                  CategoryPageProvider, diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt index 1f028d5e7bc9..654719d906a9 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt @@ -39,9 +39,9 @@ import com.android.settingslib.spa.gallery.page.FooterPageProvider  import com.android.settingslib.spa.gallery.page.IllustrationPageProvider  import com.android.settingslib.spa.gallery.page.LoadingBarPageProvider  import com.android.settingslib.spa.gallery.page.ProgressBarPageProvider -import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider  import com.android.settingslib.spa.gallery.page.SliderPageProvider  import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider +import com.android.settingslib.spa.gallery.scaffold.PagerMainPageProvider  import com.android.settingslib.spa.gallery.scaffold.SearchScaffoldPageProvider  import com.android.settingslib.spa.gallery.scaffold.SuwScaffoldPageProvider  import com.android.settingslib.spa.gallery.ui.CategoryPageProvider @@ -63,7 +63,7 @@ object HomePageProvider : SettingsPageProvider {              SuwScaffoldPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),              SliderPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),              SpinnerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), -            SettingsPagerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), +            PagerMainPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),              FooterPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),              IllustrationPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),              CategoryPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/NonScrollablePagerPageProvider.kt index dc45e6da0bc1..029773fdf8df 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/NonScrollablePagerPageProvider.kt @@ -1,5 +1,5 @@  /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2024 The Android Open 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.settingslib.spa.gallery.page +package com.android.settingslib.spa.gallery.scaffold  import android.os.Bundle  import androidx.compose.foundation.layout.Box @@ -33,24 +33,19 @@ import com.android.settingslib.spa.widget.scaffold.SettingsPager  import com.android.settingslib.spa.widget.scaffold.SettingsScaffold  import com.android.settingslib.spa.widget.ui.PlaceholderTitle -private const val TITLE = "Sample SettingsPager" +object NonScrollablePagerPageProvider : SettingsPageProvider { +    override val name = "NonScrollablePager" +    private const val TITLE = "Sample Non Scrollable SettingsPager" -object SettingsPagerPageProvider : SettingsPageProvider { -    override val name = "SettingsPager" - -    fun buildInjectEntry(): SettingsEntryBuilder { -        return SettingsEntryBuilder.createInject(owner = createSettingsPage()) -            .setUiLayoutFn { -                Preference(object : PreferenceModel { -                    override val title = TITLE -                    override val onClick = navigator(name) -                }) -            } -    } +    fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = createSettingsPage()) +        .setUiLayoutFn { +            Preference(object : PreferenceModel { +                override val title = TITLE +                override val onClick = navigator(name) +            }) +        } -    override fun getTitle(arguments: Bundle?): String { -        return TITLE -    } +    override fun getTitle(arguments: Bundle?) = TITLE      @Composable      override fun Page(arguments: Bundle?) { @@ -66,8 +61,8 @@ object SettingsPagerPageProvider : SettingsPageProvider {  @Preview(showBackground = true)  @Composable -private fun SettingsPagerPagePreview() { +private fun NonScrollablePagerPageProviderPreview() {      SettingsTheme { -        SettingsPagerPageProvider.Page(null) +        NonScrollablePagerPageProvider.Page(null)      }  } diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/PagerMainPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/PagerMainPageProvider.kt new file mode 100644 index 000000000000..66cc38f74b07 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/PagerMainPageProvider.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.spa.gallery.scaffold + +import android.os.Bundle +import com.android.settingslib.spa.framework.common.SettingsEntryBuilder +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel + +object PagerMainPageProvider : SettingsPageProvider { +    override val name = "PagerMain" +    private val owner = createSettingsPage() +    private const val TITLE = "Category: Pager" + +    override fun buildEntry(arguments: Bundle?) = listOf( +        NonScrollablePagerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), +        ScrollablePagerPageProvider.buildInjectEntry().setLink(fromPage = owner).build(), +    ) + +    fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = owner) +        .setUiLayoutFn { +            Preference(object : PreferenceModel { +                override val title = TITLE +                override val onClick = navigator(name) +            }) +        } + +    override fun getTitle(arguments: Bundle?) = TITLE +} diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/ScrollablePagerPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/ScrollablePagerPageProvider.kt new file mode 100644 index 000000000000..689a98a16b23 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/ScrollablePagerPageProvider.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.spa.gallery.scaffold + +import android.os.Bundle +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.common.SettingsEntryBuilder +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.common.createSettingsPage +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.scaffold.SettingsPager +import com.android.settingslib.spa.widget.scaffold.SettingsScaffold + +object ScrollablePagerPageProvider : SettingsPageProvider { +    override val name = "ScrollablePager" +    private const val TITLE = "Sample Scrollable SettingsPager" + +    fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner = createSettingsPage()) +        .setUiLayoutFn { +            Preference(object : PreferenceModel { +                override val title = TITLE +                override val onClick = navigator(name) +            }) +        } + +    override fun getTitle(arguments: Bundle?) = TITLE + +    @Composable +    override fun Page(arguments: Bundle?) { +        SettingsScaffold(title = getTitle(arguments)) { paddingValues -> +            Box(Modifier.padding(paddingValues)) { +                SettingsPager(listOf("Personal", "Work")) { +                    LazyColumn { +                        items(30) { +                            Preference(object : PreferenceModel { +                                override val title = it.toString() +                            }) +                        } +                    } +                } +            } +        } +    } +} + +@Preview(showBackground = true) +@Composable +private fun ScrollablePagerPageProviderPreview() { +    SettingsTheme { +        ScrollablePagerPageProvider.Page(null) +    } +} diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SuwScaffoldPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SuwScaffoldPageProvider.kt index 6fc8de3ac49c..a0ab2ce6945d 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SuwScaffoldPageProvider.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/scaffold/SuwScaffoldPageProvider.kt @@ -22,6 +22,10 @@ import androidx.compose.foundation.layout.padding  import androidx.compose.material.icons.Icons  import androidx.compose.material.icons.outlined.SignalCellularAlt  import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue  import androidx.compose.ui.Modifier  import com.android.settingslib.spa.framework.common.SettingsEntryBuilder  import com.android.settingslib.spa.framework.common.SettingsPageProvider @@ -37,6 +41,8 @@ import com.android.settingslib.spa.widget.preference.PreferenceModel  import com.android.settingslib.spa.widget.scaffold.BottomAppBarButton  import com.android.settingslib.spa.widget.scaffold.SuwScaffold  import com.android.settingslib.spa.widget.ui.SettingsBody +import com.android.settingslib.spa.widget.ui.Spinner +import com.android.settingslib.spa.widget.ui.SpinnerOption  private const val TITLE = "Sample SuwScaffold" @@ -67,13 +73,12 @@ private fun Page() {          actionButton = BottomAppBarButton("Next") {},          dismissButton = BottomAppBarButton("Cancel") {},      ) { -        Column(Modifier.padding(SettingsDimension.itemPadding)) { -            SettingsBody("To add another SIM, download a new eSIM.") -        } -        Illustration(object : IllustrationModel { -            override val resId = R.drawable.accessibility_captioning_banner -            override val resourceType = ResourceType.IMAGE -        }) +        var selectedId by rememberSaveable { mutableIntStateOf(1) } +        Spinner( +            options = (1..3).map { SpinnerOption(id = it, text = "Option $it") }, +            selectedId = selectedId, +            setId = { selectedId = it }, +        )          Column(Modifier.padding(SettingsDimension.itemPadding)) {              SettingsBody("To add another SIM, download a new eSIM.")          } diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml index 0ee9d595d875..85ad160f6d66 100644 --- a/packages/SettingsLib/Spa/gradle/libs.versions.toml +++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml @@ -15,7 +15,7 @@  #  [versions] -agp = "8.3.1" +agp = "8.3.2"  compose-compiler = "1.5.11"  dexmaker-mockito = "2.28.3"  jvm = "17" diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.6-bin.zip b/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.7-bin.zip Binary files differindex 5c9634782bbe..7a9ac5afe013 100644 --- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.6-bin.zip +++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.7-bin.zip diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties index 50ff9dff549b..182095e76e76 100644 --- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties +++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties @@ -16,6 +16,6 @@  distributionBase=GRADLE_USER_HOME  distributionPath=wrapper/dists -distributionUrl=gradle-8.6-bin.zip +distributionUrl=gradle-8.7-bin.zip  zipStoreBase=GRADLE_USER_HOME  zipStorePath=wrapper/dists diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts index 2f2ac2467a6c..6344501ce789 100644 --- a/packages/SettingsLib/Spa/spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/spa/build.gradle.kts @@ -65,7 +65,7 @@ dependencies {      api("androidx.lifecycle:lifecycle-runtime-compose")      api("androidx.navigation:navigation-compose:2.8.0-alpha05")      api("com.github.PhilJay:MPAndroidChart:v3.1.0-alpha") -    api("com.google.android.material:material:1.7.0-alpha03") +    api("com.google.android.material:material:1.11.0")      debugApi("androidx.compose.ui:ui-tooling:$jetpackComposeVersion")      implementation("com.airbnb.android:lottie-compose:5.2.0") diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt index 791893b3c056..ef1a137198c2 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt @@ -37,6 +37,7 @@ fun TwoTargetSwitchPreference(              SettingsSwitch(                  checked = model.checked(),                  changeable = model.changeable, +                contentDescription = model.title,                  onCheckedChange = model.onCheckedChange,              )          } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SuwScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SuwScaffold.kt index f372a45f9e59..163766a7a9c5 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SuwScaffold.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SuwScaffold.kt @@ -19,7 +19,6 @@ package com.android.settingslib.spa.widget.scaffold  import androidx.compose.foundation.layout.Box  import androidx.compose.foundation.layout.BoxWithConstraints  import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope  import androidx.compose.foundation.layout.Row  import androidx.compose.foundation.layout.Spacer  import androidx.compose.foundation.layout.padding @@ -33,6 +32,8 @@ import androidx.compose.material3.Scaffold  import androidx.compose.material3.Text  import androidx.compose.material3.TextButton  import androidx.compose.runtime.Composable +import androidx.compose.runtime.movableContentOf +import androidx.compose.runtime.remember  import androidx.compose.ui.Modifier  import androidx.compose.ui.graphics.vector.ImageVector  import com.android.settingslib.spa.framework.theme.SettingsDimension @@ -50,7 +51,7 @@ fun SuwScaffold(      title: String,      actionButton: BottomAppBarButton? = null,      dismissButton: BottomAppBarButton? = null, -    content: @Composable ColumnScope.() -> Unit, +    content: @Composable () -> Unit,  ) {      ActivityTitle(title)      Scaffold { innerPadding -> @@ -59,6 +60,7 @@ fun SuwScaffold(                  .padding(innerPadding)                  .padding(top = SettingsDimension.itemPaddingAround)          ) { +            val movableContent = remember(content) { movableContentOf { content() } }              // Use single column layout in portrait, two columns in landscape.              val useSingleColumn = maxWidth < maxHeight              if (useSingleColumn) { @@ -69,7 +71,7 @@ fun SuwScaffold(                              .verticalScroll(rememberScrollState())                      ) {                          Header(imageVector, title) -                        content() +                        movableContent()                      }                      BottomBar(actionButton, dismissButton)                  } @@ -82,8 +84,9 @@ fun SuwScaffold(                          Column(                              Modifier                                  .weight(1f) -                                .verticalScroll(rememberScrollState())) { -                            content() +                                .verticalScroll(rememberScrollState()) +                        ) { +                            movableContent()                          }                      }                      BottomBar(actionButton, dismissButton) diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt index a0da2418acbc..5155406b6d79 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt @@ -20,12 +20,16 @@ import androidx.compose.foundation.interaction.MutableInteractionSource  import androidx.compose.material3.Switch  import androidx.compose.runtime.Composable  import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics  import com.android.settingslib.spa.framework.util.wrapOnSwitchWithLog  @Composable  internal fun SettingsSwitch(      checked: Boolean?,      changeable: () -> Boolean, +    contentDescription: String? = null,      onCheckedChange: ((newChecked: Boolean) -> Unit)? = null,      interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },  ) { @@ -33,6 +37,9 @@ internal fun SettingsSwitch(          Switch(              checked = checked,              onCheckedChange = wrapOnSwitchWithLog(onCheckedChange), +            modifier = if (contentDescription != null) Modifier.semantics { +                this.contentDescription = contentDescription +            } else Modifier,              enabled = changeable(),              interactionSource = interactionSource,          ) diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ar/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ar/strings.xml index 9a8e7ddc6ef5..f259541fc0d4 100644 --- a/packages/SettingsLib/SpaPrivileged/res/values-ar/strings.xml +++ b/packages/SettingsLib/SpaPrivileged/res/values-ar/strings.xml @@ -20,8 +20,8 @@      <string name="no_applications" msgid="5800789569715871963">"ليس هناك أي تطبيقات."</string>      <string name="menu_show_system" msgid="906304605807554788">"إظهار عمليات النظام"</string>      <string name="menu_hide_system" msgid="374571689914923020">"إخفاء عمليات النظام"</string> -    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"مسموح به"</string> -    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"غير مسموح به"</string> +    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"تطبيق مسموح به"</string> +    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"تطبيق غير مسموح به"</string>      <string name="version_text" msgid="4001669804596458577">"الإصدار <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>      <string name="cloned_app_info_label" msgid="1765651167024478391">"نسخة طبق الأصل من \"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>\""</string>  </resources> diff --git a/packages/SettingsLib/SpaPrivileged/res/values-in/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-in/strings.xml index a2a4289c1bf5..b1d572195391 100644 --- a/packages/SettingsLib/SpaPrivileged/res/values-in/strings.xml +++ b/packages/SettingsLib/SpaPrivileged/res/values-in/strings.xml @@ -17,7 +17,7 @@  <resources xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> -    <string name="no_applications" msgid="5800789569715871963">"Tidak ada aplikasi."</string> +    <string name="no_applications" msgid="5800789569715871963">"Tidak ada aplikasi"</string>      <string name="menu_show_system" msgid="906304605807554788">"Tampilkan sistem"</string>      <string name="menu_hide_system" msgid="374571689914923020">"Sembunyikan sistem"</string>      <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Diizinkan"</string> diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ne/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ne/strings.xml index 7f3a52325814..87d0762cf1e9 100644 --- a/packages/SettingsLib/SpaPrivileged/res/values-ne/strings.xml +++ b/packages/SettingsLib/SpaPrivileged/res/values-ne/strings.xml @@ -18,8 +18,8 @@  <resources xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">      <string name="no_applications" msgid="5800789569715871963">"कुनै पनि एप छैन।"</string> -    <string name="menu_show_system" msgid="906304605807554788">"सिस्टम देखाइयोस्"</string> -    <string name="menu_hide_system" msgid="374571689914923020">"सिस्टम लुकाइयोस्"</string> +    <string name="menu_show_system" msgid="906304605807554788">"सिस्टम देखाउनुहोस्"</string> +    <string name="menu_hide_system" msgid="374571689914923020">"सिस्टम लुकाउनुहोस्"</string>      <string name="app_permission_summary_allowed" msgid="6115213465364138103">"अनुमति दिइएका एप"</string>      <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"अनुमति नदिइएका एप"</string>      <string name="version_text" msgid="4001669804596458577">"संस्करण <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string> diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java index a4089c0d8697..7f4bebcf4a62 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java @@ -52,16 +52,12 @@ import java.util.ArrayList;  import java.util.Comparator;  import java.util.HashMap; -/** - * Description of a single dashboard tile that the user can select. - */ +/** Description of a single dashboard tile that the user can select. */  public abstract class Tile implements Parcelable {      private static final String TAG = "Tile"; -    /** -     * Optional list of user handles which the intent should be launched on. -     */ +    /** Optional list of user handles which the intent should be launched on. */      public ArrayList<UserHandle> userHandle = new ArrayList<>();      public HashMap<UserHandle, PendingIntent> pendingIntentMap = new HashMap<>(); @@ -76,6 +72,7 @@ public abstract class Tile implements Parcelable {      private CharSequence mSummaryOverride;      private Bundle mMetaData;      private String mCategory; +    private String mGroupKey;      public Tile(ComponentInfo info, String category, Bundle metaData) {          mComponentInfo = info; @@ -83,6 +80,9 @@ public abstract class Tile implements Parcelable {          mComponentName = mComponentInfo.name;          mCategory = category;          mMetaData = metaData; +        if (mMetaData != null) { +            mGroupKey = metaData.getString(META_DATA_PREFERENCE_GROUP_KEY); +        }          mIntent = new Intent().setClassName(mComponentPackage, mComponentName);          if (isNewTask()) {              mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -102,6 +102,7 @@ public abstract class Tile implements Parcelable {          if (isNewTask()) {              mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);          } +        mGroupKey = in.readString();      }      @Override @@ -121,16 +122,13 @@ public abstract class Tile implements Parcelable {          }          dest.writeString(mCategory);          dest.writeBundle(mMetaData); +        dest.writeString(mGroupKey);      } -    /** -     * Unique ID of the tile -     */ +    /** Unique ID of the tile */      public abstract int getId(); -    /** -     * Human-readable description of the tile -     */ +    /** Human-readable description of the tile */      public abstract String getDescription();      protected abstract ComponentInfo getComponentInfo(Context context); @@ -147,16 +145,12 @@ public abstract class Tile implements Parcelable {          return mComponentName;      } -    /** -     * Intent to launch when the preference is selected. -     */ +    /** Intent to launch when the preference is selected. */      public Intent getIntent() {          return mIntent;      } -    /** -     * Category in which the tile should be placed. -     */ +    /** Category in which the tile should be placed. */      public String getCategory() {          return mCategory;      } @@ -165,9 +159,7 @@ public abstract class Tile implements Parcelable {          mCategory = newCategoryKey;      } -    /** -     * Priority of this tile, used for display ordering. -     */ +    /** Priority of this tile, used for display ordering. */      public int getOrder() {          if (hasOrder()) {              return mMetaData.getInt(META_DATA_KEY_ORDER); @@ -176,32 +168,24 @@ public abstract class Tile implements Parcelable {          }      } -    /** -     * Check whether tile has order. -     */ +    /** Check whether tile has order. */      public boolean hasOrder() {          return mMetaData != null                  && mMetaData.containsKey(META_DATA_KEY_ORDER)                  && mMetaData.get(META_DATA_KEY_ORDER) instanceof Integer;      } -    /** -     * Check whether tile has a switch. -     */ +    /** Check whether tile has a switch. */      public boolean hasSwitch() {          return mMetaData != null && mMetaData.containsKey(META_DATA_PREFERENCE_SWITCH_URI);      } -    /** -     * Check whether tile has a pending intent. -     */ +    /** Check whether tile has a pending intent. */      public boolean hasPendingIntent() {          return !pendingIntentMap.isEmpty();      } -    /** -     * Title of the tile that is shown to the user. -     */ +    /** Title of the tile that is shown to the user. */      public CharSequence getTitle(Context context) {          CharSequence title = null;          ensureMetadataNotStale(context); @@ -238,9 +222,7 @@ public abstract class Tile implements Parcelable {          mSummaryOverride = summaryOverride;      } -    /** -     * Optional summary describing what this tile controls. -     */ +    /** Optional summary describing what this tile controls. */      public CharSequence getSummary(Context context) {          if (mSummaryOverride != null) {              return mSummaryOverride; @@ -275,16 +257,12 @@ public abstract class Tile implements Parcelable {          mMetaData = metaData;      } -    /** -     * The metaData from the activity that defines this tile. -     */ +    /** The metaData from the activity that defines this tile. */      public Bundle getMetaData() {          return mMetaData;      } -    /** -     * Optional key to use for this tile. -     */ +    /** Optional key to use for this tile. */      public String getKey(Context context) {          ensureMetadataNotStale(context);          if (!hasKey()) { @@ -297,9 +275,7 @@ public abstract class Tile implements Parcelable {          }      } -    /** -     * Check whether title has key. -     */ +    /** Check whether title has key. */      public boolean hasKey() {          return mMetaData != null && mMetaData.containsKey(META_DATA_PREFERENCE_KEYHINT);      } @@ -325,8 +301,9 @@ public abstract class Tile implements Parcelable {          if (iconResId != 0 && iconResId != android.R.color.transparent) {              final Icon icon = Icon.createWithResource(componentInfo.packageName, iconResId);              if (isIconTintable(context)) { -                final TypedArray a = context.obtainStyledAttributes(new int[]{ -                        android.R.attr.colorControlNormal}); +                final TypedArray a = +                        context.obtainStyledAttributes( +                                new int[] {android.R.attr.colorControlNormal});                  final int tintColor = a.getColor(0, 0);                  a.recycle();                  icon.setTint(tintColor); @@ -349,26 +326,22 @@ public abstract class Tile implements Parcelable {          return false;      } -    /** -     * Whether the {@link Activity} should be launched in a separate task. -     */ +    /** Whether the {@link Activity} should be launched in a separate task. */      public boolean isNewTask() { -        if (mMetaData != null -                && mMetaData.containsKey(META_DATA_NEW_TASK)) { +        if (mMetaData != null && mMetaData.containsKey(META_DATA_NEW_TASK)) {              return mMetaData.getBoolean(META_DATA_NEW_TASK);          }          return false;      } -    /** -     * Ensures metadata is not stale for this tile. -     */ +    /** Ensures metadata is not stale for this tile. */      private void ensureMetadataNotStale(Context context) {          final PackageManager pm = context.getApplicationContext().getPackageManager();          try { -            final long lastUpdateTime = pm.getPackageInfo(mComponentPackage, -                    PackageManager.GET_META_DATA).lastUpdateTime; +            final long lastUpdateTime = +                    pm.getPackageInfo(mComponentPackage, PackageManager.GET_META_DATA) +                            .lastUpdateTime;              if (lastUpdateTime == mLastUpdateTime) {                  // All good. Do nothing                  return; @@ -382,72 +355,60 @@ public abstract class Tile implements Parcelable {          }      } -    public static final Creator<Tile> CREATOR = new Creator<Tile>() { -        public Tile createFromParcel(Parcel source) { -            final boolean isProviderTile = source.readBoolean(); -            // reset the Parcel pointer before delegating to the real constructor. -            source.setDataPosition(0); -            return isProviderTile ? new ProviderTile(source) : new ActivityTile(source); -        } +    public static final Creator<Tile> CREATOR = +            new Creator<Tile>() { +                public Tile createFromParcel(Parcel source) { +                    final boolean isProviderTile = source.readBoolean(); +                    // reset the Parcel pointer before delegating to the real constructor. +                    source.setDataPosition(0); +                    return isProviderTile ? new ProviderTile(source) : new ActivityTile(source); +                } -        public Tile[] newArray(int size) { -            return new Tile[size]; -        } -    }; +                public Tile[] newArray(int size) { +                    return new Tile[size]; +                } +            }; -    /** -     * Check whether tile only has primary profile. -     */ +    /** Check whether tile only has primary profile. */      public boolean isPrimaryProfileOnly() {          return isPrimaryProfileOnly(mMetaData);      }      static boolean isPrimaryProfileOnly(Bundle metaData) { -        String profile = metaData != null -                ? metaData.getString(META_DATA_KEY_PROFILE) : PROFILE_ALL; +        String profile = metaData != null ? metaData.getString(META_DATA_KEY_PROFILE) : PROFILE_ALL;          profile = (profile != null ? profile : PROFILE_ALL);          return TextUtils.equals(profile, PROFILE_PRIMARY);      } -    /** -     * Returns whether the tile belongs to another group / category. -     */ +    /** Returns whether the tile belongs to another group / category. */      public boolean hasGroupKey() { -        return mMetaData != null -                && !TextUtils.isEmpty(mMetaData.getString(META_DATA_PREFERENCE_GROUP_KEY)); +        return !TextUtils.isEmpty(mGroupKey);      } -    /** -     * Returns the group / category key this tile belongs to. -     */ +    /** Set the group / PreferenceCategory key this tile belongs to. */ +    public void setGroupKey(String groupKey) { +        mGroupKey = groupKey; +    } + +    /** Returns the group / category key this tile belongs to. */      public String getGroupKey() { -        return (mMetaData == null) ? null : mMetaData.getString(META_DATA_PREFERENCE_GROUP_KEY); +        return mGroupKey;      } -    /** -     * Returns if this is searchable. -     */ +    /** Returns if this is searchable. */      public boolean isSearchable() {          return mMetaData == null || mMetaData.getBoolean(META_DATA_PREFERENCE_SEARCHABLE, true);      } -    /** -     * The type of the tile. -     */ +    /** The type of the tile. */      public enum Type { -        /** -         * A preference that can be tapped on to open a new page. -         */ +        /** A preference that can be tapped on to open a new page. */          ACTION, -        /** -         * A preference that can be tapped on to open an external app. -         */ +        /** A preference that can be tapped on to open an external app. */          EXTERNAL_ACTION, -        /** -         * A preference that shows an on / off switch that can be toggled by the user. -         */ +        /** A preference that shows an on / off switch that can be toggled by the user. */          SWITCH,          /** @@ -460,7 +421,7 @@ public abstract class Tile implements Parcelable {           * A preference category with a title that can be used to group multiple preferences           * together.           */ -        GROUP; +        GROUP      }      /** diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java index d0929e19bc9b..b949cd58a862 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java @@ -77,9 +77,7 @@ public class TileUtils {       */      public static final String IA_SETTINGS_ACTION = "com.android.settings.action.IA_SETTINGS"; -    /** -     * Same as #EXTRA_SETTINGS_ACTION but used for the platform Settings activities. -     */ +    /** Same as #EXTRA_SETTINGS_ACTION but used for the platform Settings activities. */      private static final String SETTINGS_ACTION = "com.android.settings.action.SETTINGS";      private static final String OPERATOR_SETTINGS = @@ -101,9 +99,7 @@ public class TileUtils {       */      static final String EXTRA_CATEGORY_KEY = "com.android.settings.category"; -    /** -     * The key used to get the package name of the icon resource for the preference. -     */ +    /** The key used to get the package name of the icon resource for the preference. */      static final String EXTRA_PREFERENCE_ICON_PACKAGE = "com.android.settings.icon_package";      /** @@ -145,18 +141,17 @@ public class TileUtils {              "com.android.settings.bg.argb";      /** -     * Name of the meta-data item that should be set in the AndroidManifest.xml -     * to specify the content provider providing the icon that should be displayed for -     * the preference. +     * Name of the meta-data item that should be set in the AndroidManifest.xml to specify the +     * content provider providing the icon that should be displayed for the preference.       * -     * Icon provided by the content provider overrides any static icon. +     * <p>Icon provided by the content provider overrides any static icon.       */      public static final String META_DATA_PREFERENCE_ICON_URI = "com.android.settings.icon_uri";      /** -     * Name of the meta-data item that should be set in the AndroidManifest.xml -     * to specify whether the icon is tintable. This should be a boolean value {@code true} or -     * {@code false}, set using {@code android:value} +     * Name of the meta-data item that should be set in the AndroidManifest.xml to specify whether +     * the icon is tintable. This should be a boolean value {@code true} or {@code false}, set using +     * {@code android:value}       */      public static final String META_DATA_PREFERENCE_ICON_TINTABLE =              "com.android.settings.icon_tintable"; @@ -171,41 +166,36 @@ public class TileUtils {      public static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title";      /** -     * Name of the meta-data item that should be set in the AndroidManifest.xml -     * to specify the content provider providing the title text that should be displayed for the -     * preference. +     * Name of the meta-data item that should be set in the AndroidManifest.xml to specify the +     * content provider providing the title text that should be displayed for the preference.       * -     * Title provided by the content provider overrides any static title. +     * <p>Title provided by the content provider overrides any static title.       */ -    public static final String META_DATA_PREFERENCE_TITLE_URI = -            "com.android.settings.title_uri"; +    public static final String META_DATA_PREFERENCE_TITLE_URI = "com.android.settings.title_uri";      /** -     * Name of the meta-data item that should be set in the AndroidManifest.xml -     * to specify the summary text that should be displayed for the preference. +     * Name of the meta-data item that should be set in the AndroidManifest.xml to specify the +     * summary text that should be displayed for the preference.       */      public static final String META_DATA_PREFERENCE_SUMMARY = "com.android.settings.summary";      /** -     * Name of the meta-data item that should be set in the AndroidManifest.xml -     * to specify the content provider providing the summary text that should be displayed for the -     * preference. +     * Name of the meta-data item that should be set in the AndroidManifest.xml to specify the +     * content provider providing the summary text that should be displayed for the preference.       * -     * Summary provided by the content provider overrides any static summary. +     * <p>Summary provided by the content provider overrides any static summary.       */      public static final String META_DATA_PREFERENCE_SUMMARY_URI =              "com.android.settings.summary_uri";      /** -     * Name of the meta-data item that should be set in the AndroidManifest.xml -     * to specify the content provider providing the switch that should be displayed for the -     * preference. +     * Name of the meta-data item that should be set in the AndroidManifest.xml to specify the +     * content provider providing the switch that should be displayed for the preference.       * -     * This works with {@link #META_DATA_PREFERENCE_KEYHINT} which should also be set in the +     * <p>This works with {@link #META_DATA_PREFERENCE_KEYHINT} which should also be set in the       * AndroidManifest.xml       */ -    public static final String META_DATA_PREFERENCE_SWITCH_URI = -            "com.android.settings.switch_uri"; +    public static final String META_DATA_PREFERENCE_SWITCH_URI = "com.android.settings.switch_uri";      /**       * Name of the meta-data item that can be set from the content provider providing the intent @@ -215,8 +205,8 @@ public class TileUtils {              "com.android.settings.pending_intent";      /** -     * Value for {@link #META_DATA_KEY_PROFILE}. When the device has a managed profile, -     * the app will always be run in the primary profile. +     * Value for {@link #META_DATA_KEY_PROFILE}. When the device has a managed profile, the app will +     * always be run in the primary profile.       *       * @see #META_DATA_KEY_PROFILE       */ @@ -231,11 +221,11 @@ public class TileUtils {      public static final String PROFILE_ALL = "all_profiles";      /** -     * Name of the meta-data item that should be set in the AndroidManifest.xml -     * to specify the profile in which the app should be run when the device has a managed profile. -     * The default value is {@link #PROFILE_ALL} which means the user will be presented with a -     * dialog to choose the profile. If set to {@link #PROFILE_PRIMARY} the app will always be -     * run in the primary profile. +     * Name of the meta-data item that should be set in the AndroidManifest.xml to specify the +     * profile in which the app should be run when the device has a managed profile. The default +     * value is {@link #PROFILE_ALL} which means the user will be presented with a dialog to choose +     * the profile. If set to {@link #PROFILE_PRIMARY} the app will always be run in the primary +     * profile.       *       * @see #PROFILE_PRIMARY       * @see #PROFILE_ALL @@ -243,20 +233,16 @@ public class TileUtils {      public static final String META_DATA_KEY_PROFILE = "com.android.settings.profile";      /** -     * Name of the meta-data item that should be set in the AndroidManifest.xml -     * to specify whether the {@link android.app.Activity} should be launched in a separate task. -     * This should be a boolean value {@code true} or {@code false}, set using {@code android:value} +     * Name of the meta-data item that should be set in the AndroidManifest.xml to specify whether +     * the {@link android.app.Activity} should be launched in a separate task. This should be a +     * boolean value {@code true} or {@code false}, set using {@code android:value}       */      public static final String META_DATA_NEW_TASK = "com.android.settings.new_task"; -    /** -     * If the entry should be shown in settings search results. Defaults to true. -     */ +    /** If the entry should be shown in settings search results. Defaults to true. */      public static final String META_DATA_PREFERENCE_SEARCHABLE = "com.android.settings.searchable"; -    /** -     * Build a list of DashboardCategory. -     */ +    /** Build a list of DashboardCategory. */      public static List<DashboardCategory> getCategories(Context context,              Map<Pair<String, String>, Tile> cache) {          final long startTime = System.currentTimeMillis(); @@ -341,8 +327,8 @@ public class TileUtils {              UserHandle user, Map<Pair<String, String>, Tile> addedCache,              String defaultCategory, List<Tile> outTiles, Intent intent) {          final PackageManager pm = context.getPackageManager(); -        final List<ResolveInfo> results = pm.queryIntentContentProvidersAsUser(intent, -                0 /* flags */, user.getIdentifier()); +        final List<ResolveInfo> results = +                pm.queryIntentContentProvidersAsUser(intent, 0 /* flags */, user.getIdentifier());          for (ResolveInfo resolved : results) {              if (!resolved.system) {                  // Do not allow any app to add to settings, only system ones. @@ -403,6 +389,8 @@ public class TileUtils {              tile.setMetaData(metaData);          } +        tile.setGroupKey(metaData.getString(META_DATA_PREFERENCE_GROUP_KEY)); +          if (!tile.userHandle.contains(user)) {              tile.userHandle.add(user);          } @@ -448,15 +436,15 @@ public class TileUtils {      /**       * Returns the complete uri from the meta data key of the tile.       * -     * A complete uri should contain at least one path segment and be one of the following types: -     *      content://authority/method -     *      content://authority/method/key +     * <p>A complete uri should contain at least one path segment and be one of the following types: +     * <br>content://authority/method +     * <br>content://authority/method/key       * -     * If the uri from the tile is not complete, build a uri by the default method and the +     * <p>If the uri from the tile is not complete, build a uri by the default method and the       * preference key.       * -     * @param tile          Tile which contains meta data -     * @param metaDataKey   Key mapping to the uri in meta data +     * @param tile Tile which contains meta data +     * @param metaDataKey Key mapping to the uri in meta data       * @param defaultMethod Method to be attached to the uri by default if it has no path segment       * @return Uri associated with the key       */ @@ -501,9 +489,9 @@ public class TileUtils {      /**       * Gets the icon package name and resource id from content provider.       * -     * @param context     context +     * @param context context       * @param packageName package name of the target activity -     * @param uri         URI for the content provider +     * @param uri URI for the content provider       * @param providerMap Maps URI authorities to providers       * @return package name and resource id of the icon specified       */ @@ -532,10 +520,10 @@ public class TileUtils {      /**       * Gets text associated with the input key from the content provider.       * -     * @param context     context -     * @param uri         URI for the content provider +     * @param context context +     * @param uri URI for the content provider       * @param providerMap Maps URI authorities to providers -     * @param key         Key mapping to the text in bundle returned by the content provider +     * @param key Key mapping to the text in bundle returned by the content provider       * @return Text associated with the key, if returned by the content provider       */      public static String getTextFromUri(Context context, Uri uri, @@ -547,10 +535,10 @@ public class TileUtils {      /**       * Gets boolean associated with the input key from the content provider.       * -     * @param context     context -     * @param uri         URI for the content provider +     * @param context context +     * @param uri URI for the content provider       * @param providerMap Maps URI authorities to providers -     * @param key         Key mapping to the text in bundle returned by the content provider +     * @param key Key mapping to the text in bundle returned by the content provider       * @return Boolean associated with the key, if returned by the content provider       */      public static boolean getBooleanFromUri(Context context, Uri uri, @@ -562,11 +550,11 @@ public class TileUtils {      /**       * Puts boolean associated with the input key to the content provider.       * -     * @param context     context -     * @param uri         URI for the content provider +     * @param context context +     * @param uri URI for the content provider       * @param providerMap Maps URI authorities to providers -     * @param key         Key mapping to the text in bundle returned by the content provider -     * @param value       Boolean associated with the key +     * @param key Key mapping to the text in bundle returned by the content provider +     * @param value Boolean associated with the key       * @return Bundle associated with the action, if returned by the content provider       */      public static Bundle putBooleanToUriAndGetResult(Context context, Uri uri, diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig index e09ab0086451..89f54d9b3b3b 100644 --- a/packages/SettingsLib/aconfig/settingslib.aconfig +++ b/packages/SettingsLib/aconfig/settingslib.aconfig @@ -36,14 +36,14 @@ flag {    name: "enable_le_audio_sharing"    namespace: "pixel_cross_device_control"    description: "Gates whether to enable LE audio sharing" -  bug: "305620450" +  bug: "323125723"  }  flag {    name: "enable_le_audio_qr_code_private_broadcast_sharing"    namespace: "pixel_cross_device_control"    description: "Gates whether to enable LE audio private broadcast sharing via QR code" -  bug: "308368124" +  bug: "323125723"  }  flag { @@ -52,3 +52,13 @@ flag {    description: "Hide exclusively managed Bluetooth devices in BT settings menu."    bug: "324475542"  } + +flag { +    name: "enable_set_preferred_transport_for_le_audio_device" +    namespace: "bluetooth" +    description: "Enable setting preferred transport for Le Audio device" +    bug: "330581926" +    metadata { +        purpose: PURPOSE_BUGFIX +    } +} diff --git a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml index 89d6ac39598b..3ed17247a5e3 100644 --- a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml +++ b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml @@ -53,7 +53,7 @@      <EditText          android:id="@+id/user_name"          android:layout_width="match_parent" -        android:layout_height="@dimen/user_name_height_in_user_info_dialog" +        android:layout_height="wrap_content"          android:layout_gravity="center"          android:minWidth="200dp"          android:layout_marginStart="6dp" diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index eb3d4afca431..ef77a56e3a78 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktief, net links"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktief, net regs"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktief, links en regs"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktiewe (net media), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>-battery"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktiewe (net media), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>-battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>-battery"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Gekoppelde (steun oudiodeling), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>-battery"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Gekoppelde (steun oudiodeling), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>-battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>-battery"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Gekoppelde (steun oudiodeling), linkerkantse <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Gekoppelde (steun oudiodeling), regterkantse <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktief (net media)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Steun oudiodeling"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktief (net media), net linkerkant"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktief (net media), net regterkant"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktief (net media), linker- en regterkant"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Media-oudio"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Foonoproepe"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Lêeroordrag"</string> @@ -335,8 +324,8 @@      <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Wanneer hierdie modus geaktiveer is, kan hierdie toestel se MAC-adres verander elke keer wanneer dit aan \'n netwerk koppel waarvoor MAC-verewekansiging geaktiveer is."</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> -    <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Kies loggergroottes per logbuffer"</string> +    <string name="select_logd_size_title" msgid="1604578195914595173">"Logskepperbuffer se groottes"</string> +    <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Kies logskeppergroottes per logbuffer"</string>      <string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"Maak logskrywer se aanhoudende berging skoon?"</string>      <string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"Wanneer ons nie meer monitering met die aanhoudende logskrywer uitvoer nie, word ons vereis om die logskrywerdata wat op jou toestel is, uit te vee."</string>      <string name="select_logpersist_title" msgid="447071974007104196">"Berg logskrywerdata aanhoudend op toestel"</string> @@ -411,7 +400,7 @@      <string name="show_non_rect_clip" msgid="7499758654867881817">"Ontfout nie-reghoekige knipbedrywighede"</string>      <string name="track_frame_time" msgid="522674651937771106">"Profiel-HWUI-lewering"</string>      <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Aktiveer GPU-ontfoutlae"</string> -    <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Laat laai van GPU-ontfoutlae vir ontfoutprogramme toe"</string> +    <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Laat laai van GPU-ontfoutlae vir ontfoutapps toe"</string>      <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Aktiveer woordryke verkoperloginskrywing"</string>      <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Sluit bykomende toestelspesifieke verkoperloglêers by foutverslae in, wat privaat inligting kan bevat, meer batterykrag kan gebruik, en/of meer berging kan gebruik."</string>      <string name="window_animation_scale_title" msgid="5236381298376812508">"Vensteranimasieskaal"</string> @@ -514,7 +503,7 @@      <string name="disabled" msgid="8017887509554714950">"Gedeaktiveer"</string>      <string name="external_source_trusted" msgid="1146522036773132905">"Toegelaat"</string>      <string name="external_source_untrusted" msgid="5037891688911672227">"Nie toegelaat nie"</string> -    <string name="install_other_apps" msgid="3232595082023199454">"Installeer onbekende programme"</string> +    <string name="install_other_apps" msgid="3232595082023199454">"Installeer onbekende apps"</string>      <string name="home" msgid="973834627243661438">"Instellingstuisblad"</string>    <string-array name="battery_labels">      <item msgid="7878690469765357158">"0%"</item> @@ -709,7 +698,7 @@      <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Verstek"</string>      <string name="turn_screen_on_title" msgid="3266937298097573424">"Skakel skerm aan"</string>      <string name="allow_turn_screen_on" msgid="6194845766392742639">"Laat toe dat die skerm aangeskakel word"</string> -    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Laat ’n program toe om die skerm aan te skakel. As jy toestemming gee, kan die program die skerm enige tyd sonder jou uitdruklike bedoeling aanskakel."</string> +    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Laat ’n app toe om die skerm aan te skakel. As jy toestemming gee, kan die app die skerm enige tyd sonder jou uitdruklike bedoeling aanskakel."</string>      <string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Hou op om <xliff:g id="APP_NAME">%1$s</xliff:g> uit te saai?"</string>      <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"As jy <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitsaai of die uitvoer verander, sal jou huidige uitsending stop"</string>      <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Saai <xliff:g id="SWITCHAPP">%1$s</xliff:g> uit"</string> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index bda027756952..b590287098ef 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ገቢር፣ ግራ ብቻ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ገቢር፣ ቀኝ ብቻ"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ገቢር፣ ግራ እና ቀኝ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"ገቢር (ሚዲያ ብቻ), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ባትሪ"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"ገቢር (ሚዲያ ብቻ), ግ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ባትሪ፣ ቀ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ባትሪ"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"የተገናኘ (የድምፅ ማጋራት ይደግፋል), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ባትሪ"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"የተገናኘ (የድምፅ ማጋራት ይደግፋል) ግ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ባትሪ፣ ቀ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ባትሪ"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"የተገናኘ (የድምፅ ማጋራት ይደግፋል)፣ ግራ<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"የተገናኘ (የድምፅ ማጋራት ይደግፋል)፣ ቀኝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ገቢር (ሚዲያ ብቻ)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ድምፅ ማጋራትን ይደግፋል"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ገቢር (ሚዲያ ብቻ)፣ ግራ ብቻ"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ገቢር (ሚዲያ ብቻ) ቀኝ ብቻ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ገቢር (ሚዲያ ብቻ)፣ ግራ እና ቀኝ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"የማህደረ መረጃ ኦዲዮ"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"የስልክ ጥሪዎች"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ፋይል ማስተላለፍ"</string> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index ba93f65aa5b6..353df68740ae 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -106,32 +106,21 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"السمّاعة الطبية اليسرى فقط مفعَّلة"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"السمّاعة الطبية اليمنى فقط مفعَّلة"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"السمّاعتان اليسرى واليمنى مفعَّلتان"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"البلوتوث مفعَّل (للوسائط فقط)، مستوى شحن البطارية: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"البلوتوث مفعَّل (للوسائط فقط)، مستوى الشحن في السماعة اليسرى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، مستوى الشحن في السماعة اليمنى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"البلوتوث متصل (ميزة \"مشاركة الصوت\" متاحة)، مستوى شحن البطارية: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"البلوتوث متصل (ميزة \"مشاركة الصوت\" متاحة)، مستوى الشحن في السماعة اليسرى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، مستوى الشحن في السماعة اليمنى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"البلوتوث متصل (ميزة \"مشاركة الصوت\" متاحة)، مستوى الشحن في السماعة اليسرى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"البلوتوث متصل (ميزة \"مشاركة الصوت\" متاحة)، مستوى الشحن في السماعة اليمنى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"البلوتوث مفعَّل (للوسائط فقط)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"تتوفّر ميزة \"مشاركة الصوت\""</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"السماعة اليسرى فقط مشغَّلة (للوسائط فقط)"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"السماعة اليمنى فقط مشغَّلة (للوسائط فقط)"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"السماعتان اليسرى واليمنى مشغَّلتان (للوسائط فقط)"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"الإعدادات الصوتية للوسائط"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"المكالمات الهاتفية"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"نقل الملف"</string> -    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"جهاز الإرسال"</string> +    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"جهاز إدخال بيانات"</string>      <string name="bluetooth_profile_pan" msgid="1006235139308318188">"الوصول إلى الإنترنت"</string>      <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"السماح بالوصول إلى جهات الاتصال وسجلّ المكالمات"</string>      <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"سيتم استخدام المعلومات لإرسال إشعارات المكالمات وغيرها"</string> @@ -202,8 +191,8 @@      <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_default_rate_title" msgid="3964187817364304022">"معدل سرعة الكلام"</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>      <string name="tts_default_pitch_summary" msgid="9132719475281551884">"للتأثير في نبرة الكلام المُرَكَّب"</string> @@ -512,8 +501,8 @@      <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"إعدادات يتحكم فيها المشرف"</string>      <string name="disabled_by_app_ops_text" msgid="8373595926549098012">"يتحكّم فيه إعداد محظور"</string>      <string name="disabled" msgid="8017887509554714950">"غير مفعّل"</string> -    <string name="external_source_trusted" msgid="1146522036773132905">"مسموح به"</string> -    <string name="external_source_untrusted" msgid="5037891688911672227">"غير مسموح به"</string> +    <string name="external_source_trusted" msgid="1146522036773132905">"تطبيق مسموح به"</string> +    <string name="external_source_untrusted" msgid="5037891688911672227">"تطبيق غير مسموح به"</string>      <string name="install_other_apps" msgid="3232595082023199454">"تثبيت التطبيقات غير المعروفة"</string>      <string name="home" msgid="973834627243661438">"الشاشة الرئيسية للإعدادات"</string>    <string-array name="battery_labels"> @@ -555,7 +544,7 @@      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"المنبّهات والتذكيرات"</string>      <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"السماح بضبط المنبّهات والتذكيرات"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"المنبّهات والتذكيرات"</string> -    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"يمكنك السماح لهذا التطبيق بضبط المنبّهات وجدولة الإجراءات لتنفيذها في الوقت المناسب. ويسمح هذا الإذن بتشغيل التطبيق في الخلفية، ما قد يستهلك المزيد من البطارية.\n\nفي حال عدم تفعيل هذا الإذن، لن تعمل المنبهات الحالية والأحداث المستندة إلى الوقت المضبوطة في هذا التطبيق."</string> +    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"يمكنك السماح لهذا التطبيق بضبط المنبّهات وجدولة الإجراءات لتنفيذها في الوقت المناسب. ويسمح هذا الإذن بتشغيل التطبيق في الخلفية، ما قد يستهلك المزيد من البطارية.\n\nفي حال عدم تفعيل هذا الإذن، لن تعمل المنبهات المضبوطة والأحداث المستندة إلى الوقت المجدولة حاليًا في هذا التطبيق."</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"جدول زمني، جدولة، منبّه، تذكير، ساعة"</string>      <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"تفعيل"</string>      <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"تفعيل ميزة \"عدم الإزعاج\""</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index ef53fafa6e36..a9ad715b2232 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"কেৱল বাঁওফালৰটো সক্ৰিয় হৈছে"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"কেৱল সোঁফালৰটো সক্ৰিয় হৈছে"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"বাওঁ আৰু সোঁ দুয়োফালৰ সক্ৰিয় হৈছে"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া), বাওঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> বেটাৰী, সোঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> বেটাৰী"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"সংযুক্ত হৈ আছে (অডিঅ’ শ্বেয়াৰিং সমৰ্থন কৰে), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"সংযুক্ত হৈ আছে (অডিঅ’ শ্বেয়াৰিং সমৰ্থন কৰে), বাওঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> বেটাৰী, সোঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> বেটাৰী"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"সংযুক্ত হৈ আছে (অডিঅ’ শ্বেয়াৰিং সমৰ্থন কৰে), বাওঁ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"সংযুক্ত হৈ আছে (অডিঅ’ শ্বেয়াৰিং সমৰ্থন কৰে), সোঁ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"অডিঅ’ শ্বেয়াৰিং সমৰ্থন কৰে"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া), কেৱল বাওঁ"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া), কেৱল সোঁ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া), বাওঁ আৰু সোঁ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"মিডিয়াৰ অডিঅ’"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ফ\'ন কলসমূহ"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ফাইল স্থানান্তৰণ"</string> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index 48c68f41bafd..10ac5fce416f 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, yalnız sol"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, yalnız sağ"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, sol və sağ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktiv (yalnız media), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batareya"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktiv (yalnız media), Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batareya, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batareya"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Qoşulub (audio paylaşma dəstəklənir), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batareya"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Qoşulub (audio paylaşma dəstəklənir), Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batareya, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batareya"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Qoşulub (audio paylaşma dəstəklənir), sol <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Qoşulub (audio paylaşma dəstəklənir), sağ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiv (yalnız media)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Audio paylaşma dəstəklənir"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiv (yalnız media), yalnız sol"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiv (yalnız media), yalnız sağ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiv (yalnız media), sol və sağ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Media audio"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefon zəngləri"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Fayl transferi"</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 04c6d944ceac..86229e8f2636 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivno, samo s leve strane"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, s desne strane"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, s leve i desne strane"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktivan (samo za medije), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktivan (samo za medije), levo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterije, desno: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Povezan (podržava deljenje zvuka), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Povezan (podržava deljenje zvuka), levo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterije, desno: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Povezan (podržava deljenje zvuka), levo <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Povezan (podržava deljenje zvuka), desno <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktivan (samo za medije)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podržava deljenje zvuka"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktivan (samo za medije), samo levo"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktivan (samo za medije), samo desno"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktivan (samo za medije), levo i desno"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvuk medija"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonski pozivi"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Prenos datoteke"</string> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index f8c88e67bf5d..680aaa2a4dfa 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Уключана, толькі для левага вуха"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Уключана, толькі для правага вуха"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Уключана, для левага і правага вуха"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Выкарыстоўваецца (толькі для мультымедыя), зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Выкарыстоўваецца (толькі для мультымедыя), зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (левы навушнік), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (правы навушнік)"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Падключана (падтрымліваецца абагульванне аўдыя), зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Падключана (падтрымліваецца абагульванне аўдыя), зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (левы навушнік), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (правы навушнік)"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Падключана (падтрымліваецца абагульванне аўдыя), зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (левы навушнік)"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Падключана (падтрымліваецца абагульванне аўдыя), зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (правы навушнік)"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Выкарыстоўваецца (толькі для мультымедыя)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Падтрымліваецца абагульванне аўдыя"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Выкарыстоўваецца (толькі для мультымедыя), толькі левы навушнік"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Выкарыстоўваецца (толькі для мультымедыя), толькі правы навушнік"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Выкарыстоўваецца (толькі для мультымедыя), левы і правы навушнікі"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Аўдыя медыяфайлаў"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Тэлефонныя выклікі"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Перадача файлаў"</string> diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml index 9388e660e840..31d24c1f7d74 100644 --- a/packages/SettingsLib/res/values-bg/arrays.xml +++ b/packages/SettingsLib/res/values-bg/arrays.xml @@ -188,7 +188,7 @@      <item msgid="409235464399258501">"Изключено"</item>      <item msgid="4195153527464162486">"Рег. буфер – 64 КБ"</item>      <item msgid="7464037639415220106">"Рег. буфер – 256 КБ"</item> -    <item msgid="8539423820514360724">"Рег. буфер – 1 МБ"</item> +    <item msgid="8539423820514360724">"Рег. буфер – 1 млн."</item>      <item msgid="1984761927103140651">"Рег. буфер – 4 МБ"</item>      <item msgid="2983219471251787208">"Регистрационен буфер – 8 МБ"</item>    </string-array> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 0457f10bd5ab..1cfe768fbd57 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -106,35 +106,24 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активно – само лявото"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активно – само дясното"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активно – лявото и дясното"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Активно (само за мултимедия), батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Активно (само за мултимедия), Л: батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Д: батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Свързано (поддържа споделяне на звука), батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Свързано (поддържа споделяне на звука), Л: батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Д: батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Свързано (поддържа споделяне на звука), лява – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Свързано (поддържа споделяне на звука), дясна – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Активно (само за мултимедия)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Поддържа споделяне на звука"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Активно (само за мултимедия), само лявата"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Активно (само за мултимедия), само дясната"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Активно (само за мултимедия), лявата и дясната"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Мултимедийно аудио"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Телефонни обаждания"</string>      <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="2103406516858653017">"Разреш. на достъпа до контактите и историята на обажд."</string> -    <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Информацията ще се ползва за съобщения чрез обаждания и др."</string> +    <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Информацията ще се ползва за обявяване на обажданията и др."</string>      <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Споделяне на връзката с интернет"</string>      <string name="bluetooth_profile_map" msgid="8907204701162107271">"Текстови съобщения"</string>      <string name="bluetooth_profile_sap" msgid="8304170950447934386">"Достъп до SIM картата"</string> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index e9367ff44c63..6e5135a9dfe0 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"শুধুমাত্র বাঁদিকের হিয়ারিং এড অ্যাক্টিভ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"শুধুমাত্র ডানদিকের হিয়ারিং এড অ্যাক্টিভ"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"বাঁ ও ডানদিকের হিয়ারিং এড, অ্যাক্টিভ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"চালু আছে (শুধুমাত্র মিডিয়া), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ব্যাটারি"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"চালু আছে (শুধুমাত্র মিডিয়া), বাঁদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ব্যাটারি, ডানদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ব্যাটারি"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"কানেক্ট করা আছে (অডিও শেয়ারিংয়ে কাজ করে), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ব্যাটারি"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"কানেক্ট করা আছে (অডিও শেয়ারিংয়ে কাজ করে), বাঁদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ব্যাটারি, ডানদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ব্যাটারি"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"কানেক্ট করা আছে (অডিও শেয়ারিংয়ে কাজ করে), বাঁদিক <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"কানেক্ট করা আছে (অডিও শেয়ারিংয়ে কাজ করে), ডানদিক <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"চালু আছে (শুধুমাত্র মিডিয়া)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"অডিও শেয়ারিংয়ে কাজ করে"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"চালু আছে (শুধুমাত্র মিডিয়া), শুধুমাত্র বাঁদিক"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"চালু আছে (শুধুমাত্র মিডিয়া), শুধুমাত্র ডানদিক"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"চালু আছে (শুধুমাত্র মিডিয়া), বাঁদিক ও ডানদিক"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"মিডিয়া অডিও"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ফোন কল"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ফাইল স্থানান্তর"</string> @@ -537,7 +526,7 @@      <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"সিস্টেমের ভাষাগুলি ব্যবহার করুন"</string>      <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> জন্য সেটিংস খুলতে ব্যর্থ হয়েছে"</string>      <string name="ime_security_warning" msgid="6547562217880551450">"এই ইনপুট পদ্ধতিটি হয়ত পাসওয়ার্ড এবং ক্রেডিট কার্ড নম্বর সহ আপনার টাইপ করা সমস্ত টেক্সট সংগ্রহ করতে সক্ষম হতে পারে। এটি <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> অ্যাপ থেকে এসেছে। এই ইনপুট পদ্ধতিটি ব্যবহার করবেন?"</string> -    <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"দ্রষ্টব্য: পুনরায় চালু করার পরে, আপনি আপনার ফোন আনলক না করা পর্যন্ত এই অ্যাপটিকে চালু করতে পারবেন না"</string> +    <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"দ্রষ্টব্য: রিবুট করার পরে, আপনি আপনার ফোন আনলক না করা পর্যন্ত এই অ্যাপটিকে চালু করতে পারবেন না"</string>      <string name="ims_reg_title" msgid="8197592958123671062">"IMS রেজিস্ট্রেশনের স্থিতি"</string>      <string name="ims_reg_status_registered" msgid="884916398194885457">"রেজিস্টার করা"</string>      <string name="ims_reg_status_not_registered" msgid="2989287366045704694">"রেজিস্টার করা নয়"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index 7fb522552c94..d991bd6f7cc9 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivno, samo lijevi"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, samo desni"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, lijevi i desni"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktivno (samo za medijski sadržaj), baterija: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktivno (samo za medijski sadržaj), baterija L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, baterija D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Povezano (podržava dijeljenje zvuka), baterija: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Povezano (podržava dijeljenje zvuka), baterija L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, baterija D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Povezano (podržava dijeljenje zvuka), lijevo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Povezano (podržava dijeljenje zvuka), desno: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktivno (samo za medijski sadržaj)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podržava dijeljenje zvuka"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktivno (samo za medijski sadržaj), samo lijevo"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktivno (samo za medijski sadržaj), samo desno"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktivno (samo za medijski sadržaj), lijevo i desno"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvuk medija"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonski pozivi"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Prenošenje fajla"</string> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 18da1bec6f34..738871588541 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Actiu, només l\'esquerre"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Actiu, només el dret"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Actiu, esquerre i dret"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Actiu (només contingut multimèdia), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Actiu (només contingut multimèdia), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Connectat (admet compartició d\'àudio), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Connectat (admet compartició d\'àudio), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Connectat (admet compartició d\'àudio), esquerre <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Connectat (admet compartició d\'àudio), dret <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Actiu (només contingut multimèdia)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Admet compartició d\'àudio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Actiu (només contingut multimèdia), només esquerre"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Actiu (només contingut multimèdia), només dret"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Actiu (només contingut multimèdia), esquerre i dret"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Àudio multimèdia"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Trucades telefòniques"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferència de fitxers"</string> @@ -487,7 +476,7 @@      <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Hauria de durar aproximadament fins a les <xliff:g id="TIME">%1$s</xliff:g> segons l\'ús que en facis"</string>      <string name="power_discharge_by" msgid="4113180890060388350">"Hauria de durar aproximadament fins a les <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">"Hauria de durar aproximadament fins a les <xliff:g id="TIME">%1$s</xliff:g>"</string> -    <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Fins a les <xliff:g id="TIME">%1$s</xliff:g>"</string> +    <string name="power_discharge_by_only_short" msgid="5883041507426914446">"fins a les <xliff:g id="TIME">%1$s</xliff:g>"</string>      <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"És possible que la bateria s\'esgoti a les <xliff:g id="TIME">%1$s</xliff:g>"</string>      <string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Temps restant inferior a <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>      <string name="power_remaining_less_than_duration" msgid="318215464914990578">"Temps restant inferior a <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -514,7 +503,7 @@      <string name="disabled" msgid="8017887509554714950">"Desactivat"</string>      <string name="external_source_trusted" msgid="1146522036773132905">"Amb permís"</string>      <string name="external_source_untrusted" msgid="5037891688911672227">"Sense permís"</string> -    <string name="install_other_apps" msgid="3232595082023199454">"Instal·lar aplicacions desconegudes"</string> +    <string name="install_other_apps" msgid="3232595082023199454">"Instal·la aplicacions desconegudes"</string>      <string name="home" msgid="973834627243661438">"Pàgina d\'inici de configuració"</string>    <string-array name="battery_labels">      <item msgid="7878690469765357158">"0%"</item> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index f4bfe505c437..e09d303f7c5e 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivní, pouze levé"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivní, pouze pravé"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivní, levé a pravé"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktivní (pouze média), baterie: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktivní (pouze média), baterie: L <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Připojeno (podporuje sdílení zvuku), baterie: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Připojeno (podporuje sdílení zvuku), baterie: L <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Připojeno (podporuje sdílení zvuku), levé <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Připojeno (podporuje sdílení zvuku), pravé <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktivní (pouze média)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podporuje sdílení zvuku"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktivní (pouze média), pouze levé"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktivní (pouze média), pouze pravé"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktivní (pouze média), levé a pravé"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvuk médií"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonní hovory"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Přenos souborů"</string> @@ -709,7 +698,7 @@      <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Výchozí"</string>      <string name="turn_screen_on_title" msgid="3266937298097573424">"Zapínání obrazovky"</string>      <string name="allow_turn_screen_on" msgid="6194845766392742639">"Povolit zapínání obrazovky"</string> -    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Povolte aplikaci zapínat obrazovku. Pokud aplikace bude mít toto oprávnění, může kdykoli zapnout obrazovku bez požadavku uživatele."</string> +    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Aplikaci můžete povolit zapínat obrazovku. Pokud bude mít toto oprávnění, může kdykoli zapnout obrazovku bez požadavku uživatele."</string>      <string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Zastavit vysílání v aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Pokud budete vysílat v aplikaci <xliff:g id="SWITCHAPP">%1$s</xliff:g> nebo změníte výstup, aktuální vysílání se zastaví"</string>      <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Vysílat v aplikaci <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index d51f8b9fb818..09902b856c96 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, kun venstre"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, kun højre"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, venstre og højre"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktiveret (kun for medier), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktiveret (kun for medier), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Forbundet (understøtter lyddeling), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Forbundet (understøtter lyddeling), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Forbundet (understøtter lyddeling), venstre <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Forbundet (understøtter lyddeling), højre <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiveret (kun for medier)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Understøtter lyddeling"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiveret (kun for medier), kun venstre"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiveret (kun for medier), kun højre"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiveret (kun for medier), venstre og højre"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Medielyd"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonopkald"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Filoverførsel"</string> @@ -709,7 +698,7 @@      <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>      <string name="turn_screen_on_title" msgid="3266937298097573424">"Aktivér skærmen"</string>      <string name="allow_turn_screen_on" msgid="6194845766392742639">"Tillad aktivering af skærmen"</string> -    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Tillad, at en app aktiverer skærmen. Hvis du giver denne tilladelse, kan appen til enhver tid aktiverer skærmen, uden at du eksplicit har bedt om det."</string> +    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Tillad, at en app aktiverer skærmen. Hvis du giver denne tilladelse, kan appen til enhver tid aktivere skærmen, uden at du eksplicit har bedt om det."</string>      <string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Stop udsendelsen <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Hvis du udsender <xliff:g id="SWITCHAPP">%1$s</xliff:g> eller skifter output, stopper din aktuelle udsendelse"</string>      <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Udsend <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 08ca14a248e8..d542d0fc9ee8 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, nur links"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, nur rechts"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, links und rechts"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktiv (nur Medien), Akku: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktiv (nur Medien), Akku links: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Akku rechts: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Verbunden (unterstützt Audiofreigabe), Akku: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Verbunden (unterstützt Audiofreigabe), Akku links: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Akku rechts: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Verbunden (unterstützt Audiofreigabe), Akku links: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Verbunden (unterstützt Audiofreigabe), Akku rechts: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiv (nur Medien)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Unterstützt Audiofreigabe"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiv (nur Medien), nur links"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiv (nur Medien), nur rechts"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiv (nur Medien), links und rechts"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Medien-Audio"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonanrufe"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Dateiübertragung"</string> @@ -472,7 +461,7 @@      <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (Rot-Grün-Sehschwäche)"</string>      <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (Blau-Gelb-Sehschwäche)"</string>      <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Farbkorrektur"</string> -    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Die Farbkorrektur kann nützlich sein, wenn du:<br/> <ol> <li>&nbsp;Farben noch genauer sehen möchtest</li> <li>&nbsp;bestimmte Farben entfernen möchtest, um dich besser zu konzentrieren</li> </ol>"</string> +    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Die Farbkorrektur kann nützlich sein, wenn du:<br/> <ol> <li>&nbsp;Farben noch genauer sehen möchtest</li> <li>&nbsp;Bestimmte Farben entfernen möchtest, um dich besser zu konzentrieren</li> </ol>"</string>      <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Außer Kraft gesetzt von \"<xliff:g id="TITLE">%1$s</xliff:g>\""</string>      <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>      <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ladevorgang zum Schutz des Akkus angehalten"</string> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index c38034a585dc..af21647ca8fc 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ενεργό, μόνο το αριστερό"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ενεργό, μόνο το δεξί"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ενεργό, αριστερό και δεξί"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Ενεργό (μόνο για μέσα), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> μπαταρία"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Ενεργό (μόνο για μέσα), Α: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> μπαταρία, Δ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> μπαταρία"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Συνδεδεμένο (υποστηρίζει κοινή χρήση ήχου), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> μπαταρία"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Συνδεδεμένο (υποστηρίζει κοινή χρήση ήχου), Α: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> μπαταρία, Δ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> μπαταρία"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Συνδεδεμένο (υποστηρίζει κοινή χρήση ήχου), αριστερό <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Συνδεδεμένο (υποστηρίζει κοινή χρήση ήχου), δεξί <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ενεργό (μόνο για μέσα)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Υποστηρίζει κοινή χρήση ήχου"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ενεργό (μόνο για μέσα), μόνο αριστερό"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ενεργό (μόνο για μέσα), μόνο δεξί"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ενεργό (μόνο για μέσα), αριστερό και δεξί"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Ήχος πολυμέσων"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Τηλεφωνικές κλήσεις"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Μεταφορά αρχείου"</string> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index c787c6360cb0..93c17bde9550 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Active, left only"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Active, right only"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Active, left and right"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Active (media only), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Active (media only), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Connected (supports audio sharing), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Connected (supports audio sharing), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Connected (supports audio sharing), left <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Connected (supports audio sharing), right <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Active (media only)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Supports audio sharing"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Active (media only), left only"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Active (media only), right only"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Active (media only), left and right"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Media audio"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Phone calls"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"File transfer"</string> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index c787c6360cb0..93c17bde9550 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Active, left only"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Active, right only"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Active, left and right"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Active (media only), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Active (media only), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Connected (supports audio sharing), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Connected (supports audio sharing), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Connected (supports audio sharing), left <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Connected (supports audio sharing), right <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Active (media only)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Supports audio sharing"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Active (media only), left only"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Active (media only), right only"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Active (media only), left and right"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Media audio"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Phone calls"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"File transfer"</string> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index c787c6360cb0..93c17bde9550 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Active, left only"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Active, right only"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Active, left and right"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Active (media only), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Active (media only), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Connected (supports audio sharing), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Connected (supports audio sharing), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> battery, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Connected (supports audio sharing), left <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Connected (supports audio sharing), right <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Active (media only)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Supports audio sharing"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Active (media only), left only"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Active (media only), right only"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Active (media only), left and right"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Media audio"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Phone calls"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"File transfer"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml index be125725a53c..4d4d7c9be0e3 100644 --- a/packages/SettingsLib/res/values-es-rUS/arrays.xml +++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml @@ -186,10 +186,10 @@    </string-array>    <string-array name="select_logd_size_summaries">      <item msgid="409235464399258501">"Desactivado"</item> -    <item msgid="4195153527464162486">"64 K/búfer registro"</item> -    <item msgid="7464037639415220106">"256 K/búfer registro"</item> -    <item msgid="8539423820514360724">"1 M/búfer registro"</item> -    <item msgid="1984761927103140651">"4 M/búfer registro"</item> +    <item msgid="4195153527464162486">"64 K/búfer de registro"</item> +    <item msgid="7464037639415220106">"256 K/búfer de registro"</item> +    <item msgid="8539423820514360724">"1 M/búfer de registro"</item> +    <item msgid="1984761927103140651">"4 M/búfer de registro"</item>      <item msgid="2983219471251787208">"8 M/búfer de registro"</item>    </string-array>    <string-array name="select_logpersist_titles"> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 1903c6be8125..682f7322f8d9 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Activo; solo oído izquierdo"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Activo; solo oído derecho"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Activo; oídos izquierdo y derecho"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Activo (solo para contenido multimedia); <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Activo (solo para contenido multimedia); I: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería; D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Conectado (admite el uso compartido de audio); <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Conectado (admite el uso compartido de audio); I: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería; D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Conectado (admite el uso compartido de audio); izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Conectado (admite el uso compartido de audio); derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Activo (solo para contenido multimedia)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Admite el uso compartido de audio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Activo (solo para contenido multimedia); solo izquierdo"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Activo (solo para contenido multimedia); solo derecho"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Activo (solo para contenido multimedia); izquierdo y derecho"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio multimedia"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Llamadas telefónicas"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferencia de archivos"</string> @@ -335,7 +324,7 @@      <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Si este modo está habilitado, es posible que la dirección MAC del dispositivo cambie cada vez que se conecte a una red que tenga habilitada la aleatorización de MAC."</string>      <string name="wifi_metered_label" msgid="8737187690304098638">"De 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> +    <string name="select_logd_size_title" msgid="1604578195914595173">"Tamaños de los búferes de registro"</string>      <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Selecciona el tamaño del Logger por búfer"</string>      <string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"¿Borrar el almacenamiento persistente del registrador?"</string>      <string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"Cuando ya no usamos el registrador persistente para monitorear, debemos borrar los datos que almacena el registrador en tu dispositivo."</string> @@ -411,7 +400,7 @@      <string name="show_non_rect_clip" msgid="7499758654867881817">"Depurar operaciones de recorte no rectangulares"</string>      <string name="track_frame_time" msgid="522674651937771106">"Perfil procesamiento HWUI"</string>      <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Habilitar depuración GPU"</string> -    <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Permite capas de GPU para apps de depuración"</string> +    <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Permite cargar capas de depuración de GPU para apps de depuración"</string>      <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Habilitar registro detallado"</string>      <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Incluye otros registros de proveedor específicos del dispositivo en los informes de errores, que podrían contener información privada, consumir más batería o usar más espacio de almacenamiento."</string>      <string name="window_animation_scale_title" msgid="5236381298376812508">"Escala de animación de ventana"</string> @@ -471,7 +460,7 @@      <string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"Deuteronomalía (rojo-verde)"</string>      <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string>      <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string> -    <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string> +    <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de colores"</string>      <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"La corrección de colores puede ser útil cuando quieres hacer lo siguiente:<br/> <ol> <li>&nbsp;Ver los colores con mayor precisión</li> <li>&nbsp;Quitar colores para concentrarte</li> </ol>"</string>      <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>      <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index 29b29b6b5e72..f3a23f05c432 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -106,35 +106,24 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Activo, solo oído izquierdo"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Activo, solo oído derecho"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Activo, oídos izquierdo y derecho"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Activo (solo multimedia), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Activo (solo multimedia), izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería, derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Conectado (permite compartir audio), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Conectado (permite compartir audio), izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería, derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Conectado (permite compartir audio), izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Conectado (permite compartir audio), derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Activo (solo multimedia)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Permite compartir audio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Activo (solo multimedia), solo el izquierdo"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Activo (solo multimedia), solo el derecho"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Activo (solo multimedia), izquierdo y derecho"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio multimedia"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Llamadas de teléfono"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferencia de archivos"</string>      <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Dispositivo de entrada"</string>      <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Acceso a Internet"</string>      <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Acceso a contactos e historial de llamadas"</string> -    <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"La información se utilizará para avisos de llamada y más"</string> +    <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"La información se usará para avisos de llamada y más"</string>      <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Compartir conexión a Internet"</string>      <string name="bluetooth_profile_map" msgid="8907204701162107271">"Mensajes de texto"</string>      <string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acceso a tarjeta SIM"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index 9f77bd9d2008..8ad05d8affe2 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiivne, ainult vasak"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiivne, ainult parem"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiivne, vasak ja parem"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktiivne (ainult meedia), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> aku täituvus"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktiivne (ainult meedia), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> aku täituvus, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> aku täituvus"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Ühendatud (toetab heli jagamist), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> aku täituvus"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Ühendatud (toetab heli jagamist), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> aku täituvus, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> aku täituvus"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Ühendatud (toetab heli jagamist), vasak <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Ühendatud (toetab heli jagamist), parem <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiivne (ainult meedia)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Toetab heli jagamist"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiivne (ainult meedia), ainult vasak"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiivne (ainult meedia), ainult parem"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiivne (ainult meedia), vasak ja parem"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Meediaheli"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonikõned"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Failiedastus"</string> @@ -505,7 +494,7 @@      <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Juhtmevaba laadimine"</string>      <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Laadimine"</string>      <string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei lae"</string> -    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Ühendatud, kuid ei laadita"</string> +    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Ühendatud, kuid ei laeta"</string>      <string name="battery_info_status_full" msgid="1339002294876531312">"Laetud"</string>      <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Täielikult laetud"</string>      <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Laadimine on ootele pandud"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 05f3ac713c6e..f43d6175be2e 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -106,32 +106,21 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktibo, ezkerrekoa soilik"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktibo, eskuinekoa soilik"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktibo, ezkerreko eta eskuineko audifonoak"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktibo (multimedia-edukia soilik); bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktibo (multimedia-edukia soilik); L aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. R aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Konektatuta (audioa partekatzeko eginbidea onartzen du); bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Konektatuta (audioa partekatzeko eginbidea onartzen du); L aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. R aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Konektatuta (audioa partekatzeko eginbidea onartzen du); ezkerreko aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Konektatuta (audioa partekatzeko eginbidea onartzen du); eskuineko aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktibo (multimedia-edukia soilik)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Audioa partekatzeko eginbidea onartzen du"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktibo (multimedia-edukia soilik); ezkerreko aldea soilik"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktibo (multimedia-edukia soilik); eskuineko aldea soilik"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktibo (multimedia-edukia soilik); ezkerreko eta eskuineko aldeak"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Euskarriaren audioa"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefono-deiak"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Fitxategi-transferentzia"</string> -    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Sarrerako gailua"</string> +    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Sarrera-gailua"</string>      <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Interneteko konexioa"</string>      <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Eman kontaktuak eta deien historia erabiltzeko baimena"</string>      <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Deiak iragartzeko eta abarrerako erabiliko da informazioa"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 658fb0fcca31..c404f54d0155 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"فعال، فقط چپ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"فعال، فقط راست"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"فعال، چپ و راست"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"فعال (فقط رسانه)، <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> باتری"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"فعال (فقط رسانه)، چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> باتری، راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> باتری"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"متصل (از اشتراک صدا پشتیبانی میکند)، <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> باتری"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"متصل (از اشتراک صدا پشتیبانی میکند)، چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> باتری، راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> باتری"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"متصل (از اشتراک صدا پشتیبانی میکند)، چپ<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"متصل (از اشتراک صدا پشتیبانی میکند)، راست <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"فعال (فقط رسانه)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"از اشتراک صدا پشتیبانی میکند"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"فعال (فقط رسانه)، فقط چپ"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"فعال (فقط رسانه)، فقط راست"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"فعال (فقط رسانه)، چپ و راست"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"رسانه صوتی"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"تماسهای تلفنی"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"انتقال فایل"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 14b1701e7d9b..6c52bf25cddc 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiivinen, vain vasen"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiivinen, vain oikea"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiivinen, vasen ja oikea"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktiivinen (vain media), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> virtaa"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktiivinen (vain media), vasen: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> virtaa, oikea: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> virtaa"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Yhdistetty (tukee audionjakoa), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> virtaa"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Yhdistetty (tukee audionjakoa), vasen: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> virtaa, oikea: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> virtaa"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Yhdistetty (tukee audionjakoa), vasen: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Yhdistetty (tukee audionjakoa), oikea: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiivinen (vain media)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Tukee audionjakoa"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiivinen (vain media), vain vasen"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiivinen (vain media), vain oikea"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiivinen (vain media), vasen ja oikea"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Median ääni"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Puhelut"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Tiedostonsiirto"</string> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index e4ae14557949..3b2a1855cedb 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Actif, gauche seulement"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Active, droite seulement"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Active, gauche et droite"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Actif (contenu multimédia uniquement), pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Actif (contenu multimédia uniquement), G. : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D. : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Connecté (prise en charge du partage audio), pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Connecté (prise en charge du partage audio), G. : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D. : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Connecté (prise en charge du partage audio), côté gauche : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Connecté (prise en charge du partage audio), côté droit : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Actif (contenu multimédia uniquement)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Prise en charge du partage audio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Actif (contenu multimédia uniquement), côté gauche seulement"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Actif (contenu multimédia uniquement), côté droit seulement"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Actif (contenu multimédia uniquement), côtés gauche et droit"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Paramètres audio du support"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Appels téléphoniques"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transfert de fichier"</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 09b40acef578..5be267d251a2 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Actif, gauche uniquement"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Actif, droit uniquement"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Actifs, gauche et droit"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Activé (multimédia uniquement), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batterie"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Activé (multimédia uniquement), gauche : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batterie, droit : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batterie"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Connecté (compatible avec le partage audio), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batterie"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Connecté (compatible avec le partage audio), gauche : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batterie, droit : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batterie"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Connecté (compatible avec le partage audio), gauche <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Connecté (compatible avec le partage audio), droit <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Activé (multimédia uniquement)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Compatible avec le partage audio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Activé (multimédia uniquement), gauche uniquement"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Activé (multimédia uniquement), droit uniquement"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Activé (multimédia uniquement), gauche et droit"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio multimédia"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Appels téléphoniques"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transfert de fichiers"</string> @@ -339,7 +328,7 @@      <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Tailles enreg. par tampon journal"</string>      <string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"Effacer l\'espace de stockage persistant de l\'enregistreur ?"</string>      <string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"Lorsque nous n\'effectuons plus de suivi avec l\'enregistreur persistant, nous sommes tenus d\'effacer les données associées à ce dernier qui sont stockées sur votre appareil."</string> -    <string name="select_logpersist_title" msgid="447071974007104196">"Stocker données enregistreur en permanence sur appareil"</string> +    <string name="select_logpersist_title" msgid="447071974007104196">"Stocker données journaux sur appareil de manière persistante"</string>      <string name="select_logpersist_dialog_title" msgid="7745193591195485594">"Sélectionner les mémoires tampon journal à stocker en permanence sur l\'appareil"</string>      <string name="select_usb_configuration_title" msgid="6339801314922294586">"Sélectionner une configuration USB"</string>      <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"Sélectionner une configuration USB"</string> @@ -718,7 +707,7 @@      <string name="back_navigation_animation_summary" msgid="741292224121599456">"Activer les animations système pour la prévisualisation du Retour"</string>      <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Ce paramètre active les animations système pour la prévisualisation du geste de retour. Pour cela, enableOnBackInvokedCallback doit être défini sur \"True\" dans le fichier manifeste de chaque appli."</string>      <string name="font_scale_percentage" msgid="2624057443622817886">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> -    <string name="not_specified" msgid="5423502443185110328">"Non défini"</string> +    <string name="not_specified" msgid="5423502443185110328">"Non personnalisé"</string>      <string name="neuter" msgid="2075249330106127310">"Neutre"</string>      <string name="feminine" msgid="1529155595310784757">"Féminin"</string>      <string name="masculine" msgid="4653978041013996303">"Masculin"</string> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index db40500d4e00..1dc9ec41e089 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Activo (só o esquerdo)"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Activo (só o dereito)"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Activos (o esquerdo e o dereito)"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Activo (só contido multimedia), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Activo (só contido multimedia), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Conectado (compatible con audio compartido), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Conectado (compatible con audio compartido), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Conectado (compatible con audio compartido), esquerdo<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Conectado (compatible con audio compartido), dereito <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Activo (só contido multimedia)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Compatible con audio compartido"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Activo (só contido multimedia), só esquerdo"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Activo (só contido multimedia), só dereito"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Activo (só contido multimedia), esquerdo e dereito"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio multimedia"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Chamadas telefónicas"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferencia de ficheiros"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index c1eeca5c7cc0..9127301a22eb 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"સક્રિય, માત્ર ડાબું"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"સક્રિય, માત્ર જમણું"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"સક્રિય, ડાબું અને જમણું બન્ને"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"સક્રિય છે (માત્ર મીડિયા માટે), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"સક્રિય છે (માત્ર મીડિયા માટે), ડાબી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> બૅટરી, જમણી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> બૅટરી"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"કનેક્ટેડ છે (ઑડિયો શેરિંગને સપોર્ટ કરે છે), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"કનેક્ટેડ છે (ઑડિયો શેરિંગને સપોર્ટ કરે છે), ડાબી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> બૅટરી, જમણી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> બૅટરી"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"કનેક્ટેડ છે (ઑડિયો શેરિંગને સપોર્ટ કરે છે), ડાબી બાજુ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"કનેક્ટેડ છે (ઑડિયો શેરિંગને સપોર્ટ કરે છે), જમણી બાજુ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"સક્રિય છે (માત્ર મીડિયા માટે)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ઑડિયો શેરિંગને સપોર્ટ કરે છે"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"સક્રિય છે (માત્ર મીડિયા માટે), માત્ર ડાબી બાજુ"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"સક્રિય છે (માત્ર મીડિયા માટે), માત્ર જમણી બાજુ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"સક્રિય છે (માત્ર મીડિયા માટે), ડાબી અને જમણી બાજુ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"મીડિયા ઑડિયો"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ફોન કૉલ"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ફાઇલ સ્થાનાંતરણ"</string> @@ -335,7 +324,7 @@      <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"આ મોડ ચાલુ કરેલો હોય ત્યારે 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> +    <string name="select_logd_size_title" msgid="1604578195914595173">"લૉગર બફર કદ"</string>      <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"લૉગ દીઠ લૉગર કદ બફર પસંદ કરો"</string>      <string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"લૉગર નિરંતર સ્ટોરેજ સાફ કરીએ?"</string>      <string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"જ્યારે અમે હવે નિરંતર લૉગર સાથે મોનીટર કરતાં નથી, તો તમારા ઉપકરણ પર રહેલો લૉગર ડેટા કાઢી નાખવાની જરૂર છે."</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index a5b3c88e1606..3f956e36db5f 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"सिर्फ़ बाईं तरफ़ वाला चालू है"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"सिर्फ़ दाईं तरफ़ वाला चालू है"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"बाईं और दाईं तरफ़ वाला चालू है"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"चालू है (सिर्फ़ मीडिया के लिए), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"चालू है (सिर्फ़ मीडिया के लिए), बायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> बैटरी, दायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बैटरी"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"कनेक्ट हो गया (ऑडियो शेयर करने की सुविधा काम करती है), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"कनेक्ट हो गया (ऑडियो शेयर करने की सुविधा काम करती है), बायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> बैटरी, दायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बैटरी"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"कनेक्ट हो गया (ऑडियो शेयर करने की सुविधा काम करती है), बायां हेडसेट<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"कनेक्ट हो गया (ऑडियो शेयर करने की सुविधा काम करती है), दायां हेडसेट <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"चालू है (सिर्फ़ मीडिया के लिए)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ऑडियो शेयर करने की सुविधा काम करती है"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"चालू है (सिर्फ़ मीडिया के लिए), सिर्फ़ बाएं कान की मशीन"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"चालू है (सिर्फ़ मीडिया के लिए), सिर्फ़ दाएं कान की मशीन"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"चालू है (सिर्फ़ मीडिया के लिए), बाएं और दाएं कान की मशीन"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"मीडिया ऑडियो"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"फ़ोन कॉल"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"फ़ाइल स्थानांतरण"</string> @@ -537,7 +526,7 @@      <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"सिस्टम की भाषाओं का इस्तेमाल करें"</string>      <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> के लिए सेटिंग खोलने में विफल रहा"</string>      <string name="ime_security_warning" msgid="6547562217880551450">"इनपुट का यह तरीका, आपके पासवर्ड और क्रेडिट कार्ड नंबर जैसे निजी डेटा के साथ-साथ उस सभी डेटा को इकट्ठा कर सकता है जिसे आप लिखते हैं. यह <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> ऐप्लिकेशन से आता है. इनपुट के इस तरीके का इस्तेमाल करें?"</string> -    <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"नोट: पुनः बूट करने के बाद, यह ऐप्लिकेशन तब तक शुरू नहीं हो सकता है जब तक कि आप अपना फ़ोन अनलॉक ना कर लें"</string> +    <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"ध्यान दें: डिवाइस को फिर से चालू करने पर, यह ऐप्लिकेशन तब तक शुरू नहीं होगा, जब तक आप अपना फ़ोन अनलॉक न कर लें"</string>      <string name="ims_reg_title" msgid="8197592958123671062">"IMS रजिस्ट्रेशन की स्थिति"</string>      <string name="ims_reg_status_registered" msgid="884916398194885457">"रजिस्टर है"</string>      <string name="ims_reg_status_not_registered" msgid="2989287366045704694">"रजिस्टर नहीं है"</string> @@ -616,7 +605,7 @@      <string name="user_add_profile_item_title" msgid="3111051717414643029">"प्रतिबंधित प्रोफ़ाइल"</string>      <string name="user_add_user_title" msgid="5457079143694924885">"नया उपयोगकर्ता जोड़ें?"</string>      <string name="user_add_user_message_long" msgid="1527434966294733380">"नए उपयोगकर्ता जोड़कर इस डिवाइस को दूसरे लोगों के साथ शेयर किया जा सकता है. हर उपयोगकर्ता के पास अपनी जगह होती है, जिसमें वे ऐप्लिकेशन, वॉलपेपर, और दूसरी चीज़ों में मनमुताबिक बदलाव कर सकते हैं. उपयोगकर्ता, वाई-फ़ाई जैसी डिवाइस सेटिंग में भी बदलाव कर सकते हैं. इसका असर हर किसी पर पड़ता है.\n\nजब किसी नए उपयोगकर्ता को जोड़ा जाता है, तो उसे अपनी जगह सेट अप करनी होती है.\n\nकोई भी उपयोगकर्ता, दूसरे सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है. ऐसा भी हो सकता है कि सुलभता सेटिंग और सेवाएं नए उपयोगकर्ता को ट्रांसफ़र न हो पाएं."</string> -    <string name="user_add_user_message_short" msgid="3295959985795716166">"कोई नया उपयोगकर्ता जोड़ने पर, उसे अपनी जगह सेट करनी होती है.\n\nकोई भी उपयोगकर्ता, बाकी सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है."</string> +    <string name="user_add_user_message_short" msgid="3295959985795716166">"जब किसी नए उपयोगकर्ता को जोड़ा जाता है, तो उस व्यक्ति को डिवाइस में अपनी जगह सेट करनी होती है.\n\nकोई भी उपयोगकर्ता, बाकी सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है."</string>      <string name="user_grant_admin_title" msgid="5157031020083343984">"क्या इस व्यक्ति को एडमिन बनाना है?"</string>      <string name="user_grant_admin_message" msgid="1673791931033486709">"एडमिन के पास अन्य लोगों के मुकाबले खास अधिकार होते हैं. एडमिन के पास ये अधिकार होते हैं: सभी लोगों को मैनेज करना, इस डिवाइस को अपडेट या रीसेट करना, सेटिंग में बदलाव करना, इंस्टॉल किए गए सभी ऐप्लिकेशन देखना, और अन्य लोगों को एडमिन के खास अधिकार देना या उन्हें वापस लेना."</string>      <string name="user_grant_admin_button" msgid="5441486731331725756">"एडमिन बनाएं"</string> @@ -638,7 +627,7 @@      <string name="add_user_failed" msgid="4809887794313944872">"नया उपयोगकर्ता जोड़ा नहीं जा सका"</string>      <string name="add_guest_failed" msgid="8074548434469843443">"नया मेहमान खाता नहीं बनाया जा सका"</string>      <string name="user_nickname" msgid="262624187455825083">"निकनेम"</string> -    <string name="edit_user_info_message" msgid="6677556031419002895">"आपकी चुनी गई फ़ोटो और नाम, उन सभी लोगों को दिखेगा जो इस डिवाइस का इस्तेमाल करते हैं."</string> +    <string name="edit_user_info_message" msgid="6677556031419002895">"आपका नाम और चुनी गई फ़ोटो, इस डिवाइस का इस्तेमाल करने वाले हर व्यक्ति को दिखेगी."</string>      <string name="user_add_user" msgid="7876449291500212468">"उपयोगकर्ता जोड़ें"</string>      <string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string>      <string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान को हटाएं"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index a504c9a010bb..fcac2c853a43 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivno, samo lijevo"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, samo desno"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, lijevo i desno"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktivno (samo medijski sadržaji), razina baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktivno (samo medijski sadržaji), L: razina baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: razina baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Povezano (podržava zajedničko slušanje), razina baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Povezano (podržava zajedničko slušanje), L: razina baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: razina baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Povezano (podržava zajedničko slušanje), lijeva <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Povezano (podržava zajedničko slušanje), desna <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktivno (samo medijski sadržaji)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podržava zajedničko slušanje"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktivno (samo medijski sadržaji), samo lijeva"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktivno (samo medijski sadržaji), samo desna"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktivno (samo medijski sadržaji), lijeva i desna"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvuk medija"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonski pozivi"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Prijenos datoteke"</string> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index 3838d7d078f8..5cf57963b68a 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktív, csak bal"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktív, csak jobb"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktív, bal és jobb"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktív (csak médiatartalom lejátszása), akkumulátor töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktív (csak médiatartalom lejátszása), bal eszköz akkumulátorának töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, jobb eszköz akkumulátorának töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Csatlakoztatva (támogatja a hang megosztását), akkumulátor töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Csatlakoztatva (támogatja a hang megosztását), bal eszköz akkumulátorának töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, jobb eszköz akkumulátorának töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Csatlakoztatva (támogatja a hang megosztását), bal eszköz akkumulátorának töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Csatlakoztatva (támogatja a hang megosztását), jobb eszköz akkumulátorának töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktív (csak médiatartalom lejátszása)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Támogatja a hang megosztását"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktív (csak médiatartalom lejátszása), csak a bal"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktív (csak médiatartalom lejátszása), csak a jobb"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktív (csak médiatartalom lejátszása), bal és jobb"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Médiahang"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonhívások"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Fájlátvitel"</string> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index 00691758b6a3..327c048944f3 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ակտիվ, միայն ձախ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ակտիվ, միայն աջ"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ակտիվ, ձախ և աջ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Ակտիվ է (միայն մեդիա), մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Ակտիվ է (միայն մեդիա), Ձ՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Ա՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Միացված է (աջակցում է աուդիոյի փոխանցում), մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Միացված է (աջակցում է աուդիոյի փոխանցում), Ձ՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Ա՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Միացված է (աջակցում է աուդիոյի փոխանցում), ձախ՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Միացված է (աջակցում է աուդիոյի փոխանցում), աջ՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ակտիվ է (միայն մեդիա)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Աջակցում է աուդիոյի փոխանցում"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ակտիվ է (միայն մեդիա), միայն ձախ"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ակտիվ է (միայն մեդիա), միայն աջ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ակտիվ է (միայն մեդիա), աջ և ձախ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Մեդիա աուդիո"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Հեռախոսազանգեր"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Ֆայլերի փոխանցում"</string> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 6254f7bd72ba..1677985518b0 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -106,32 +106,21 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktif, hanya kiri"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktif, hanya kanan"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktif, kiri dan kanan"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktif (hanya media), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterai"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktif (hanya media), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterai, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterai"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Terhubung (mendukung berbagi audio), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterai"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Terhubung (mendukung berbagi audio), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterai, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterai"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Terhubung (mendukung berbagi audio), kiri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Terhubung (mendukung berbagi audio), kanan <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktif (hanya media)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Mendukung berbagi audio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktif (hanya media), hanya kiri"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktif (hanya media), hanya kanan"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktif (hanya media), kiri dan kanan"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio media"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Panggilan telepon"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transfer file"</string> -    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Perangkat masukan"</string> +    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Perangkat input"</string>      <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Akses Internet"</string>      <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Izinkan akses ke kontak dan histori panggilan"</string>      <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Info akan digunakan untuk pengumuman panggilan dan lain-lain"</string> @@ -555,7 +544,7 @@      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarm dan pengingat"</string>      <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Izinkan menyetel alarm dan pengingat"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarm & pengingat"</string> -    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Izinkan aplikasi ini menyetel alarm dan menjadwalkan tindakan yang sensitif waktu. Hal ini memungkinkan aplikasi berjalan di latar belakang, sehingga mungkin menggunakan lebih banyak daya baterai.\n\nJika izin ini dinonaktifkan, alarm dan acara berbasis waktu yang dijadwalkan oleh aplikasi ini tidak akan berfungsi."</string> +    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Mengizinkan aplikasi ini menyetel alarm dan menjadwalkan tindakan yang sensitif waktu. Hal ini memungkinkan aplikasi berjalan di latar belakang, sehingga mungkin menggunakan lebih banyak daya baterai.\n\nJika izin ini dinonaktifkan, alarm dan acara berbasis waktu yang dijadwalkan oleh aplikasi ini tidak akan berfungsi."</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"jadwal, alarm, pengingat, jam"</string>      <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktifkan"</string>      <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktifkan mode Jangan Ganggu"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 0f57670d04f3..f4afdb523945 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Virkt, aðeins vinstra"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Virkt, aðeins hægra"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Virkt, vinstra og hægra"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Virkt (eingöngu margmiðlunarefni), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> rafhlaða"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Virkt (eingöngu margmiðlunarefni), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> rafhlaða, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> rafhlaða"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Tengt (styður hljóðdeilingu), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> rafhlaða"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Tengt (styður hljóðdeilingu), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> rafhlaða, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> rafhlaða"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Tengt (styður hljóðdeilingu), vinstri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Tengt (styður hljóðdeilingu), hægri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Virkt (eingöngu margmiðlunarefni)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Styður hljóðdeilingu"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Virkt (eingöngu margmiðlunarefni), eingöngu vinstri"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Virkt (eingöngu margmiðlunarefni), eingöngu hægri"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Virkt (eingöngu margmiðlunarefni), vinstri og hægri"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Hljóð efnis"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Símtöl"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Skráaflutningur"</string> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index 950237400d55..8b1132543c07 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Attiva, solo sinistra"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Attiva, solo destra"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Attivo, destra e sinistra"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Attivo (solo contenuti multimediali), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> di batteria"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Attivo (solo contenuti multimediali), S: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> di batteria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> di batteria"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Connesso (supporta la condivisione audio), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> di batteria"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Connesso (supporta la condivisione audio), S: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> di batteria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> di batteria"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Connesso (supporta la condivisione audio), sinistro <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Connesso (supporta la condivisione audio), destro <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Attivo (solo contenuti multimediali)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Supporta la condivisione audio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Attivo (solo contenuti multimediali), solo sinistro"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Attivo (solo contenuti multimediali), solo destro"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Attivo (solo contenuti multimediali), sinistro e destro"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio multimediale"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonate"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Trasferimento file"</string> @@ -167,7 +156,7 @@      <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Annulla"</string>      <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"L\'accoppiamento consente l\'accesso ai tuoi contatti e alla cronologia chiamate quando i dispositivi sono connessi."</string>      <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Impossibile eseguire l\'accoppiamento con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> -    <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Impossibile eseguire l\'accoppiamento con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. La password o il PIN sono errati."</string> +    <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Impossibile eseguire l\'accoppiamento con <xliff:g id="DEVICE_NAME">%1$s</xliff:g> perché la passkey o il PIN sono errati."</string>      <string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Impossibile comunicare con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>      <string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"Accoppiamento rifiutato da <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>      <string name="bluetooth_talkback_computer" msgid="3736623135703893773">"Computer"</string> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index dea8ca361e99..7fd38b3ad7df 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -106,32 +106,21 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"פועל: שמאל בלבד"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"פועל: ימין בלבד"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"פועל: ימין ושמאל"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"פעיל (מדיה בלבד), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> סוללה"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"פעיל (מדיה בלבד), שמאל: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> סוללה, ימין: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> סוללה"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"מחובר (תמיכה בשיתוף אודיו), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> סוללה"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"מחובר (תמיכה בשיתוף אודיו), שמאל: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> סוללה, ימין: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> סוללה"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"מחובר (תמיכה בשיתוף אודיו), שמאל <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"מחובר (תמיכה בשיתוף אודיו), ימין <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"פעיל (מדיה בלבד)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"תמיכה בשיתוף אודיו"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"פעיל (מדיה בלבד), שמאל בלבד"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"פעיל (מדיה בלבד), ימין בלבד"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"פעיל (מדיה בלבד), שמאל וימין"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"אודיו של מדיה"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"שיחות טלפון"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"העברת קבצים"</string> -    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"מכשיר קלט"</string> +    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"התקן קלט"</string>      <string name="bluetooth_profile_pan" msgid="1006235139308318188">"גישה לאינטרנט"</string>      <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"אישור גישה אל אנשי קשר והיסטוריית שיחות"</string>      <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"המידע ישמש להודעות על שיחות ועוד"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index c7f3c0a8aa87..b8aae295888d 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"有効、左のみ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"有効、右のみ"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"有効、左と右"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"有効(メディアのみ)、バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"有効(メディアのみ)、左: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>、右: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"接続済み(音声の共有をサポート)、バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"接続済み(音声の共有をサポート)、左: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>、右: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"接続済み(音声の共有をサポート)、左 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"接続済み(音声の共有をサポート)、右 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"有効(メディアのみ)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"音声の共有をサポートしています"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"有効(メディアのみ)、左のみ"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"有効(メディアのみ)、右のみ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"有効(メディアのみ)、左右"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"メディアの音声"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"電話"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ファイル転送"</string> @@ -279,7 +268,7 @@      <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_title" msgid="1906409667944674707">"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> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index a94a4011c8f2..35ebabd2af83 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"აქტიური, მხოლოდ მარცხნივ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"აქტიური, მხოლოდ მარჯვნივ"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"აქტიური, მარცხნივ და მარჯვნივ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"აქტიური (მხოლოდ მედია), ბატარეა: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"აქტიური (მხოლოდ მედია), მარცხენა: ბატარეა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, მარჯვენა: ბატარეა<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"დაკავშირებული (აუდიოს გაზიარება მხარდაჭერილია), ბატარეა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"დაკავშირებული (აუდიოს გაზიარება მხარდაჭერილია), მარცხენა: ბატარეა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, მარჯვენა: ბატარეა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"დაკავშირებული (აუდიოს გაზიარება მხარდაჭერილია), მარცხენა: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"დაკავშირებული (აუდიოს გაზიარება მხარდაჭერილია), მარჯვენა: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"აქტიური (მხოლოდ მედია)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"აუდიოს გაზიარება მხარდაჭერილია"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"აქტიური (მხოლოდ მედია), მხოლოდ მარცხენა"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"აქტიური (მხოლოდ მედია), მხოლოდ მარჯვენა"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"აქტიური (მხოლოდ მედია), მარცხენა და მარჯვენა"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"მედია აუდიო"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"სატელეფონო ზარები"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ფაილების გადაცემა"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 1c80ad471f82..e79e3c568e44 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -106,32 +106,21 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Тек сол жағы қосулы"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Тек оң жағы қосулы"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Екеуі де қосулы"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Істеп тұр (тек мультимедиа), батарея зарядының деңгейі: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Істеп тұр (тек мультимедиа). Сол жақ: батарея зарядының деңгейі — <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. Оң жақ: батарея зарядының деңгейі — <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Қосылды (аудио бөлісуге мүмкіндік береді), батарея зарядының деңгейі:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Қосылды (аудио бөлісуге мүмкіндік береді). Сол жақ: батарея зарядының деңгейі — <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. Оң жақ: батарея зарядының деңгейі — <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Қосылды (аудио бөлісуге мүмкіндік береді), сол жақ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Қосылды (аудио бөлісуге мүмкіндік береді), оң жақ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Істеп тұр (тек мультимедиа)."</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Аудио бөлісуге мүмкіндік береді."</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Тек сол жақ істеп тұр (мультимедиа ғана)."</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Тек оң жақ істеп тұр (мультимедиа ғана)."</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Сол және оң жақ істеп тұр (мультимедиа ғана)."</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Mультимeдиа дыбысы"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Телефон қоңыраулары"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Файл жіберу"</string> -    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Кіріс құрылғысы"</string> +    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Енгізу құрылғысы"</string>      <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Интернетке қосылу"</string>      <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Контакт пен қоңырау тарихына рұқсат беру"</string>      <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Ақпарат қоңырау туралы хабарландыру, т.б. үшін қолданылады."</string> @@ -208,7 +197,7 @@      <string name="tts_default_pitch_title" msgid="6988592215554485479">"Дауыс жиілігі"</string>      <string name="tts_default_pitch_summary" msgid="9132719475281551884">"Синтезделген сөйлеу үніне әсер етеді"</string>      <string name="tts_default_lang_title" msgid="4698933575028098940">"Тіл"</string> -    <string name="tts_lang_use_system" msgid="6312945299804012406">"Жүйелік тілді пайдалану"</string> +    <string name="tts_lang_use_system" msgid="6312945299804012406">"Жүйе тілін пайдалану"</string>      <string name="tts_lang_not_selected" msgid="7927823081096056147">"Тіл таңдалған жоқ"</string>      <string name="tts_default_lang_summary" msgid="9042620014800063470">"Сөйлеу мәтіні үшін тілге тән дауыс орнатады"</string>      <string name="tts_play_example_title" msgid="1599468547216481684">"Үлгіні тыңдау"</string> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index 23bd55c16ec3..e016eb1f28c7 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"សកម្ម ខាងឆ្វេងតែប៉ុណ្ណោះ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"សកម្មខាងស្ដាំតែប៉ុណ្ណោះ"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"សកម្មខាងឆ្វេង និងស្ដាំ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ) ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ) ឆ្វេង៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ស្ដាំ៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"បានភ្ជាប់ (អាចប្រើការស្ដាប់សំឡេងរួមគ្នា) ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"បានភ្ជាប់ (អាចប្រើការស្ដាប់សំឡេងរួមគ្នា) ឆ្វេង៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ស្ដាំ៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"បានភ្ជាប់ (អាចប្រើការស្ដាប់សំឡេងរួមគ្នា) ឆ្វេង <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"បានភ្ជាប់ (អាចប្រើការស្ដាប់សំឡេងរួមគ្នា) ស្ដាំ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"អាចប្រើការស្ដាប់សំឡេងរួមគ្នា"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ) តែខាងឆ្វេងប៉ុណ្ណោះ"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ) តែខាងស្ដាំប៉ុណ្ណោះ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ) ឆ្វេង និងស្ដាំ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"សំឡេងមេឌៀ"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ការហៅទូរសព្ទ"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ផ្ទេរឯកសារ"</string> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index c636dd5dd01e..2ef70ec7068a 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ಎಡಕಿವಿಯ ಸಾಧನ ಮಾತ್ರ ಸಕ್ರಿಯವಾಗಿದೆ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ಬಲಕಿವಿಯ ಸಾಧನ ಮಾತ್ರ ಸಕ್ರಿಯವಾಗಿದೆ"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ಎಡ ಮತ್ತು ಬಲಕಿವಿಯ ಸಾಧನಗಳು ಸಕ್ರಿಯವಾಗಿವೆ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"ಕನೆಕ್ಟ್ ಆಗಿದೆ (ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"ಕನೆಕ್ಟ್ ಆಗಿದೆ (ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"ಕನೆಕ್ಟ್ ಆಗಿದೆ (ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ), ಎಡ ಭಾಗದ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"ಕನೆಕ್ಟ್ ಆಗಿದೆ (ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ), ಬಲ ಭಾಗದ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ), ಎಡ ಭಾಗದ ಮಾತ್ರ"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ), ಬಲ ಭಾಗದ ಮಾತ್ರ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ), ಎಡ ಮತ್ತು ಬಲ ಭಾಗದ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"ಮಾಧ್ಯಮ ಆಡಿಯೋ"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ಫೋನ್ ಕರೆಗಳು"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ಫೈಲ್ ವರ್ಗಾವಣೆ"</string> @@ -333,7 +322,7 @@      <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_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"ಈ ಮೋಡ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದಾಗ, MAC ಯಾದೃಚ್ಛಿಕರಣವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದ ನೆಟ್ವರ್ಕ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಿದಾಗ ಈ ಸಾಧನದ MAC ವಿಳಾಸವು ಪ್ರತಿ ಬಾರಿಯೂ ಬದಲಾಗಬಹುದು."</string> -    <string name="wifi_metered_label" msgid="8737187690304098638">"ಮೀಟರ್ ಮಾಡಲಾಗಿದೆ"</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>      <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ ಲಾಗರ್ ಗಾತ್ರಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> @@ -487,7 +476,7 @@      <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_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="8956656616031395152">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ಕ್ಕಿಂತ ಕಡಿಮೆ ಸಮಯ ಉಳಿದಿದೆ"</string>      <string name="power_remaining_less_than_duration" msgid="318215464914990578">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ಕ್ಕಿಂತ ಕಡಿಮೆ ಸಮಯ ಉಳಿದಿದೆ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -537,7 +526,7 @@      <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"ಸಿಸ್ಟಂ ಭಾಷೆಗಳನ್ನು ಬಳಸಿ"</string>      <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> ಗಾಗಿ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಲು ವಿಫಲವಾಗಿದೆ"</string>      <string name="ime_security_warning" msgid="6547562217880551450">"ವೈಯಕ್ತಿಕ ಡೇಟಾಗಳಾದ ಪಾಸ್ವರ್ಡ್ಗಳು ಮತ್ತು ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್ ಸಂಖ್ಯೆಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನೀವು ಟೈಪ್ ಮಾಡುವ ಎಲ್ಲ ಪಠ್ಯವನ್ನು ಸಂಗ್ರಹಿಸಲು ಈ ಇನ್ಪುಟ್ ವಿಧಾನಕ್ಕೆ ಸಾಧ್ಯವಾಗಬಹುದು. ಇದು <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> ಅಪ್ಲಿಕೇಶನ್ನಿಂದ ಬರುತ್ತದೆ. ಈ ಇನ್ಪುಟ್ ವಿಧಾನವನ್ನು ಬಳಸುವುದೇ?"</string> -    <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"ಗಮನಿಸಿ: ರೀಬೂಟ್ ನಂತರ, ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೀವು ಅನ್ಲಾಕ್ ಮಾಡುವ ತನಕ ಈ ಆಪ್ ಪ್ರಾರಂಭಗೊಳ್ಳುವುದಿಲ್ಲ"</string> +    <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"ಗಮನಿಸಿ: ರೀಬೂಟ್ ನಂತರ, ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೀವು ಅನ್ಲಾಕ್ ಮಾಡುವ ತನಕ ಈ ಆ್ಯಪ್ ಪ್ರಾರಂಭಗೊಳ್ಳುವುದಿಲ್ಲ"</string>      <string name="ims_reg_title" msgid="8197592958123671062">"IMS ನೋಂದಣಿ ಸ್ಥಿತಿ"</string>      <string name="ims_reg_status_registered" msgid="884916398194885457">"ನೋಂದಾಯಿಸಲಾಗಿದೆ"</string>      <string name="ims_reg_status_not_registered" msgid="2989287366045704694">"ನೋಂದಾಯಿಸಲಾಗಿಲ್ಲ"</string> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index f193fef44220..881da4396378 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"활성, 왼쪽만"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"활성, 오른쪽만"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"활성, 왼쪽 및 오른쪽"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"사용 중(미디어 전용), 배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"사용 중(미디어 전용), 왼쪽: 배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, 오른쪽: 배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"연결됨(오디오 공유 지원), 배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"연결됨(오디오 공유 지원), 왼쪽: 배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, 오른쪽: 배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"연결됨(오디오 공유 지원), 왼쪽 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"연결됨(오디오 공유 지원), 오른쪽 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"사용 중(미디어 전용)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"오디오 공유 지원"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"사용 중(미디어 전용), 왼쪽만"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"사용 중(미디어 전용), 오른쪽만"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"사용 중(미디어 전용), 왼쪽 및 오른쪽"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"미디어 오디오"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"전화 통화"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"파일 전송"</string> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 86426fa2350d..1863ed5e51cd 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Иштеп жатат, сол кулак гана"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Жигердүү, оң кулакчын гана"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Жигердүү, сол жана оң кулакчын"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Активдүү (медиа үчүн гана), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарея"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Активдүү (медиа үчүн гана), С: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батарея, О: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батарея"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Туташкан (чогуу угуу колдоого алынат), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарея"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Туташкан (чогуу угуу колдоого алынат), С: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батарея, О: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батарея"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Туташкан (чогуу угуу колдоого алынат), сол <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Туташкан (чогуу угуу колдоого алынат), оң <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Активдүү (медиа үчүн гана)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Чогуу угуу колдоого алынат"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Активдүү (медиа үчүн гана), сол кулакчын гана"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Активдүү (медиа үчүн гана), оң кулакчын гана"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Активдүү (медиа үчүн гана), сол жана оң кулакчын"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Аудио"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Телефон чалуулар"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Файл алмашуу"</string> @@ -339,7 +328,7 @@      <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Каттоо буфери үчүн Каттагычтын көлөмүн тандаңыз"</string>      <string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"Таржымалдын туруктуу диски тазалансынбы?"</string>      <string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"Туруктуу таржымалга көз салууну токтотсок, анын түзмөктө сакталган дайындарын жок кылууга аргасыз болобуз."</string> -    <string name="select_logpersist_title" msgid="447071974007104196">"Журналдагы маалымат түзмөккө сакталсын"</string> +    <string name="select_logpersist_title" msgid="447071974007104196">"Журналдагы нерселерди түзмөккө сактоо"</string>      <string name="select_logpersist_dialog_title" msgid="7745193591195485594">"Түзмөккө туруктуу сактоо үчүн таржымал буферлерин тандаңыз"</string>      <string name="select_usb_configuration_title" msgid="6339801314922294586">"USB конфигурациясын тандоо"</string>      <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"USB конфигурациясын тандоо"</string> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index ad1529d2c6e8..d764123d4b64 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ນຳໃຊ້ຢູ່, ຊ້າຍເທົ່ານັ້ນ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ນຳໃຊ້ຢູ່, ຂວາເທົ່ານັ້ນ"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ນຳໃຊ້ຢູ່, ຊ້າຍ ແລະ ຂວາ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ), ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ), ຊ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ຂ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"ເຊື່ອມຕໍ່ແລ້ວ (ຮອງຮັບການແບ່ງປັນສຽງ), ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"ເຊື່ອມຕໍ່ແລ້ວ (ຮອງຮັບການແບ່ງປັນສຽງ), ຊ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ຂ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"ເຊື່ອມຕໍ່ແລ້ວ (ຮອງຮັບການແບ່ງປັນສຽງ), ຊ້າຍ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"ເຊື່ອມຕໍ່ແລ້ວ (ຮອງຮັບການແບ່ງປັນສຽງ), ຂວາ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ຮອງຮັບການແບ່ງປັນສຽງ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ), ຊ້າຍເທົ່ານັ້ນ"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ), ຂວາເທົ່ານັ້ນ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ), ຊ້າຍ ແລະ ຂວາ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"ສຽງ"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ການໂທ"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ການໂອນຍ້າຍໄຟລ໌"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index 10ef2c46a360..b388d96402eb 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktyvus, tik kairysis"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktyvus, tik dešinysis"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktyvus, kairysis ir dešinysis"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktyvus (tik medija), akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktyvus (tik medija), kairė: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, dešinė: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Prijungta (palaikomas garso įrašų bendrinimas), akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Prijungta (palaikomas garso įrašų bendrinimas), kairė: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, dešinė: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Prijungta (palaikomas garso įrašų bendrinimas), kairė: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Prijungta (palaikomas garso įrašų bendrinimas), kairė: akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktyvus (tik medija)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Palaikomas garso įrašų bendrinimas"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktyvus (tik medija), tik kairė"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktyvus (tik medija), tik dešinė"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktyvus (tik medija), kairė ir dešinė"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Medijos garsas"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefono skambučiai"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Failo perkėlimas"</string> @@ -555,7 +544,7 @@      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Signalai ir priminimai"</string>      <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Leisti nustatyti signalus ir priminimus"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Signalai ir priminimai"</string> -    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Leisti šiai programai nustatyti signalus ir suplanuoti veiksmus, kuriems svarbus laiko veiksnys. Dėl to programa gali veikti fone ir sunaudoti daugiau akumuliatoriaus energijos.\n\nJei šis leidimas išjungtas, šios programos suplanuoti esami signalai ir laiku pagrįsti įvykiai neveiks."</string> +    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Leiskite šiai programai nustatyti signalus ir suplanuoti veiksmus, kuriems svarbus laiko veiksnys. Dėl to programa gali veikti fone ir sunaudoti daugiau akumuliatoriaus energijos.\n\nJei šis leidimas išjungtas, šios programos suplanuoti esami signalai ir laiku pagrįsti įvykiai neveiks."</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"tvarkaraštis, signalas, priminimas, laikrodis"</string>      <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Įjungti"</string>      <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Netrukdymo režimo įjungimas"</string> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index c52e9ddc861d..b28a2e9faf72 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ierīce aktīva, tikai kreisā auss"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ierīce aktīva, tikai labā auss"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ierīces aktīvas, kreisā un labā auss"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktīvs (tikai multividei), akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktīvs (tikai multividei), labās austiņas akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, kreisās austiņas akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Izveidots savienojums (atbalsta audio kopīgošanu), akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Izveidots savienojums (atbalsta audio kopīgošanu), labās austiņas akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, kreisās austiņas akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Izveidots savienojums (atbalsta audio kopīgošanu), kreisās austiņas akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Izveidots savienojums (atbalsta audio kopīgošanu), labās austiņas akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktīvs (tikai multividei)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Atbalsta audio kopīgošanu"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktīvs (tikai multivide), tikai kreisās puses aparāts"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktīvs (tikai multivide), tikai labās puses aparāts"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktīvs (tikai multivide), kreisās un labās puses aparāts"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Multivides audio"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Tālruņa zvani"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Failu pārsūtīšana"</string> @@ -162,7 +151,7 @@      <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Izmantot ievadei"</string>      <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"Izmantot dzirdes aparātiem"</string>      <string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Izmantot LE_AUDIO profilam"</string> -    <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Izveidot pāri"</string> +    <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Savienot pārī"</string>      <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SAVIENOT PĀRĪ"</string>      <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Atcelt"</string>      <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Veicot savienošanu pārī, šī ierīce savienojuma laikā varēs piekļūt jūsu kontaktpersonām un zvanu vēsturei."</string> @@ -487,7 +476,7 @@      <string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"Ņemot vērā lietojumu, darbosies aptuveni līdz <xliff:g id="TIME">%1$s</xliff:g>"</string>      <string name="power_discharge_by" msgid="4113180890060388350">"Darbosies aptuveni līdz <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">"Darbosies aptuveni līdz <xliff:g id="TIME">%1$s</xliff:g>"</string> -    <string name="power_discharge_by_only_short" msgid="5883041507426914446">"Līdz <xliff:g id="TIME">%1$s</xliff:g>"</string> +    <string name="power_discharge_by_only_short" msgid="5883041507426914446">"līdz <xliff:g id="TIME">%1$s</xliff:g>"</string>      <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"Iespējams, akumulators izlādēsies līdz <xliff:g id="TIME">%1$s</xliff:g>"</string>      <string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"Atlicis: mazāk nekā <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>      <string name="power_remaining_less_than_duration" msgid="318215464914990578">"Atlicis: mazāk nekā <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -514,7 +503,7 @@      <string name="disabled" msgid="8017887509554714950">"Atspējots"</string>      <string name="external_source_trusted" msgid="1146522036773132905">"Atļauts"</string>      <string name="external_source_untrusted" msgid="5037891688911672227">"Nav atļauts"</string> -    <string name="install_other_apps" msgid="3232595082023199454">"Instalēt nez. lietotnes"</string> +    <string name="install_other_apps" msgid="3232595082023199454">"Nezināmu lietotņu instalēšana"</string>      <string name="home" msgid="973834627243661438">"Iestatījumu sākumekrāns"</string>    <string-array name="battery_labels">      <item msgid="7878690469765357158">"0%"</item> @@ -541,7 +530,7 @@      <string name="ims_reg_title" msgid="8197592958123671062">"IMS reģistrācijas statuss"</string>      <string name="ims_reg_status_registered" msgid="884916398194885457">"Reģistrēts"</string>      <string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Nav reģistrēts"</string> -    <string name="status_unavailable" msgid="5279036186589861608">"Nepieejams"</string> +    <string name="status_unavailable" msgid="5279036186589861608">"Nepieejama"</string>      <string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC ir atlasīts nejaušā secībā"</string>      <string name="wifi_tether_connected_summary" msgid="5100712926640492336">"{count,plural, =1{Pievienota 1 ierīce.}zero{Pievienotas # ierīces.}one{Pievienota # ierīce.}other{Pievienotas # ierīces.}}"</string>      <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Vairāk laika."</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index 554b92ec60d0..3b530062ff7a 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -96,7 +96,7 @@      <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Поврзан со <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (без телефон и аудиовизуелни содржини), ниво на батеријата <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>      <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Активен, <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија"</string>      <string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Активен, Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батерија, Д: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерија"</string> -    <string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија"</string> +    <string name="bluetooth_battery_level" msgid="2893696778200201555">"Батерија: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>      <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"Батерија: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>      <string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батерија, Д: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерија"</string>      <string name="bluetooth_battery_level_untethered_left" msgid="2952823007648782646">"Одлево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активно, само лево"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активно, само десно"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активно, лево и десно"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Активно (само аудиовизуелни содржини), батерија: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Активно (само аудиовизуелни содржини), батерија Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, батерија Д: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Поврзано (поддржува споделување аудио), батерија:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Поврзано (поддржува споделување аудио), батерија Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, батерија Д: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Поврзано (поддржува споделување аудио), лево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Поврзано (поддржува споделување аудио), десно: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Активно (само аудиовизуелни содржини)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Поддржува споделување аудио"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Активно (само аудиовизуелни содржини), само лево"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Активно (само аудиовизуелни содржини), само десно"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Активно (само аудиовизуелни содржини), лево и десно"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Звук на аудио/видео"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Телефонски повици"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Пренос на датотека"</string> @@ -201,7 +190,7 @@      <string name="running_process_item_user_label" msgid="3988506293099805796">"Корисник: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>      <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" msgid="8130616705989351312">"Поставки за „Од текст во говор“"</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> @@ -474,9 +463,9 @@      <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Корекција на боите"</string>      <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Корекцијата на боите може да биде корисна кога сакате:<br/> <ol> <li>&nbsp;да ги гледате боите попрецизно</li> <li>&nbsp;да ги отстраните боите за полесно да се концентрирате</li> </ol>"</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_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - полнењето е паузирано за да се заштити батеријата"</string> -    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%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_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – полнењето е паузирано за да се заштити батеријата"</string> +    <string name="power_incompatible_charging_settings_home_page" msgid="1322050766135126880">"<xliff:g id="LEVEL">%1$s</xliff:g> – Проверете го додатокот за полнење"</string>      <string name="power_remaining_duration_only" msgid="8264199158671531431">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>      <string name="power_discharging_duration" msgid="1076561255466053220">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>      <string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g> според вашето користење"</string> @@ -496,8 +485,8 @@      <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="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до полна батерија"</string>      <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полна батерија"</string> -    <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Полнењето е оптимизирано"</string> -    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ се полни"</string> +    <string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> – полнењето е оптимизирано"</string> +    <string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$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> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index 61bcc44feba0..06e7a239e8c7 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"സജീവമാണ്, ഇടത്തേത് മാത്രം"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"സജീവമാണ്, വലത്തേത് മാത്രം"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"സജീവമാണ്, ഇടത്തേതും വലത്തേതും"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"സജീവം (മീഡിയ മാത്രം), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"സജീവം (മീഡിയ മാത്രം), ഇടതുവശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ബാറ്ററി, വലതുവശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ബാറ്ററി"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"കണക്റ്റ് ചെയ്തു (ഓഡിയോ പങ്കിടൽ പിന്തുണയ്ക്കുന്നു), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"കണക്റ്റ് ചെയ്തു (ഓഡിയോ പങ്കിടൽ പിന്തുണയ്ക്കുന്നു), ഇടതുവശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ബാറ്ററി, വലതുവശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ബാറ്ററി"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"കണക്റ്റ് ചെയ്തു (ഓഡിയോ പങ്കിടൽ പിന്തുണയ്ക്കുന്നു), ഇടതുവശത്ത് <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"കണക്റ്റ് ചെയ്തു (ഓഡിയോ പങ്കിടൽ പിന്തുണയ്ക്കുന്നു), വലതുവശത്ത് <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"സജീവം (മീഡിയ മാത്രം)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ഓഡിയോ പങ്കിടൽ പിന്തുണയ്ക്കുന്നു"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"സജീവം (മീഡിയ മാത്രം), ഇടതുവശത്ത് മാത്രം"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"സജീവം (മീഡിയ മാത്രം), വലതുവശത്ത് മാത്രം"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"സജീവം (മീഡിയ മാത്രം), ഇടതുവശത്തെയും വലതുവശത്തെയും"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"മീഡിയ ഓഡിയോ"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ഫോണ് കോളുകൾ"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ഫയൽ കൈമാറൽ"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index c2c22e611870..0a23494569b1 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Идэвхтэй, зөвхөн зүүн тал"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Идэвхтэй, зөвхөн баруун тал"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Идэвхтэй, зүүн болон баруун тал"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Идэвхтэй (зөвхөн медиа), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарей"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Идэвхтэй (зөвхөн медиа), З: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батарей, Б: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батарей"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Холбогдсон (аудио хуваалцахыг дэмждэг), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарей"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Холбогдсон (аудио хуваалцахыг дэмждэг), З: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батарей, Б: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батарей"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Холбогдсон (аудио хуваалцахыг дэмждэг), зүүн <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Холбогдсон (аудио хуваалцахыг дэмждэг), баруун <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Идэвхтэй (зөвхөн медиа)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Аудио хуваалцахыг дэмждэг"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Идэвхтэй (зөвхөн медиа), зөвхөн зүүн"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Идэвхтэй (зөвхөн медиа), зөвхөн баруун"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Идэвхтэй (зөвхөн медиа), зүүн болон баруун"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Медиа аудио"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Утасны дуудлага"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Файл дамжуулалт"</string> @@ -472,7 +461,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="1522101114585266455">"Өнгө тохируулга нь таныг дараахыг хийхийг хүсэх үед хэрэгтэй байж болно:<br/> <ol> <li>&nbsp;Өнгөнүүдийг илүү нарийвчилж харах</li> <li>&nbsp;Төвлөрөхийн тулд өнгөнүүдийг хасах</li> </ol>"</string> +    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Өнгө засах нь таныг дараахыг хийхийг хүсэх үед хэрэгтэй байж болно:<br/> <ol> <li> Өнгөнүүдийг илүү нарийвчилж харах</li> <li> Төвлөрөхийн тулд өнгөнүүдийг хасах</li> </ol>"</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_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батарейг хамгаалахын тулд цэнэглэхийг хүлээлгэсэн"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index 1e56118883a7..b40ba9e5b2fa 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"फक्त डावे अॅक्टिव्ह आहे"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"फक्त उजवे अॅक्टिव्ह आहे"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"डावे आणि उजवे अॅक्टिव्ह आहे"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"अॅक्टिव्ह आहे (फक्त मीडिया), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"ॲक्टिव्ह आहे (फक्त मीडिया), डावे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> बॅटरी, उजवे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बॅटरी"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"कनेक्ट केले आहे (ऑडिओ शेअरिंगला सपोर्ट करते), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"कनेक्ट केले आहे (ऑडिओ शेअरिंगला सपोर्ट करते), डावे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> बॅटरी, उजवे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बॅटरी"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"कनेक्ट केले आहे (ऑडिओ शेअरिंगला सपोर्ट करते), डावे <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"कनेक्ट केले आहे (ऑडिओ शेअरिंगला सपोर्ट करते), उजवे <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"अॅक्टिव्ह आहे (फक्त मीडिया)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ऑडिओ शेअरिंगला सपोर्ट करते"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"अॅक्टिव्ह आहे (फक्त मीडिया), फक्त डावे"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"अॅक्टिव्ह आहे (फक्त मीडिया), फक्त उजवे"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"अॅक्टिव्ह आहे (फक्त मीडिया), डावे आणि उजवे"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"मीडिया ऑडिओ"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"फोन कॉल"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"फाइल स्थानांतरण"</string> @@ -537,7 +526,7 @@      <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"सिस्टम भाषा वापरा"</string>      <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> साठी सेटिंग्ज उघडण्यात अयशस्वी"</string>      <string name="ime_security_warning" msgid="6547562217880551450">"ही इनपुट पद्धत पासवर्ड आणि क्रेडिट कार्ड नंबर यासह, तुम्ही टाइप करता तो सर्व मजकूर संकलित करण्यात सक्षम होऊ शकते. ही <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> ॲपवरून येते. ही इनपुट पद्धत वापरायची?"</string> -    <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"टीप: रीबूट केल्यानंतर, तुम्ही तुमचा फोन अनलॉक करे पर्यंत हे अॅप सुरू होऊ शकत नाही"</string> +    <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"टीप: रीबूट केल्यानंतर, तुम्ही तुमचा फोन अनलॉक करेपर्यंत हे अॅप सुरू होऊ शकत नाही"</string>      <string name="ims_reg_title" msgid="8197592958123671062">"IMS नोंदणी स्थिती"</string>      <string name="ims_reg_status_registered" msgid="884916398194885457">"नोंदवलेले"</string>      <string name="ims_reg_status_not_registered" msgid="2989287366045704694">"नोंदवलेले नाही"</string> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index a93c459d3650..2858ab2039a2 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktif, kiri sahaja"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktif, kanan sahaja"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktif, kiri dan kanan"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktif (media sahaja), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> bateri"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktif (media sahaja), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> bateri, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> bateri"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Disambungkan (menyokong perkongsian audio), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> bateri"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Disambungkan (menyokong perkongsian audio), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> bateri, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> bateri"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Disambungkan (menyokong perkongsian audio), kiri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Disambungkan (menyokong perkongsian audio), kanan <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktif (media sahaja)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Menyokong perkongsian audio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktif (media sahaja), kiri sahaja"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktif (media sahaja), kanan sahaja"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktif (media sahaja), kiri dan kanan"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio media"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Panggilan telefon"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Pemindahan fail"</string> @@ -555,7 +544,7 @@      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Penggera dan peringatan"</string>      <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Benarkan penetapan penggera dan peringatan"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Penggera & peringatan"</string> -    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Benarkan apl ini menetapkan penggera dan menjadualkan tindakan yang sensitif masa. Ini membolehkan apl berjalan di latar, yang mungkin menggunakan lebih banyak bateri.\n\nJika kebenaran ini dimatikan, penggera sedia ada dan acara berdasarkan masa yang dijadualkan oleh apl ini tidak akan berfungsi."</string> +    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Benarkan apl ini menetapkan penggera dan menjadualkan tindakan yang sensitif masa. Hal ini membolehkan apl berjalan di latar, yang mungkin menggunakan lebih banyak bateri.\n\nJika kebenaran ini dimatikan, penggera sedia ada dan acara berdasarkan masa yang dijadualkan oleh apl ini tidak akan berfungsi."</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"jadual, penggera, peringatan, jam"</string>      <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Hidupkan"</string>      <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Hidupkan Jangan Ganggu"</string> @@ -638,7 +627,7 @@      <string name="add_user_failed" msgid="4809887794313944872">"Gagal membuat pengguna baharu"</string>      <string name="add_guest_failed" msgid="8074548434469843443">"Gagal membuat tetamu baharu"</string>      <string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string> -    <string name="edit_user_info_message" msgid="6677556031419002895">"Nama dan gambar yang anda pilih akan dipaparkan kepada sesiapa sahaja yang menggunakan peranti ini."</string> +    <string name="edit_user_info_message" msgid="6677556031419002895">"Nama dan gambar yang anda pilih dapat dilihat oleh sesiapa sahaja yang menggunakan peranti ini."</string>      <string name="user_add_user" msgid="7876449291500212468">"Tambah pengguna"</string>      <string name="guest_new_guest" msgid="3482026122932643557">"Tambah tetamu"</string>      <string name="guest_exit_guest" msgid="5908239569510734136">"Alih keluar tetamu"</string> @@ -708,7 +697,7 @@      <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Pilih susun atur papan kekunci"</string>      <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Lalai"</string>      <string name="turn_screen_on_title" msgid="3266937298097573424">"Hidupkan skrin"</string> -    <string name="allow_turn_screen_on" msgid="6194845766392742639">"Benarkan menghidupkan skrin"</string> +    <string name="allow_turn_screen_on" msgid="6194845766392742639">"Benarkan apl menghidupkan skrin"</string>      <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Benarkan apl menghidupkan skrin. Jika dibenarkan, apl boleh menghidupkan skrin pada bila-bila masa tanpa niat eksplisit anda."</string>      <string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Hentikan siaran <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>      <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Jika anda siarkan <xliff:g id="SWITCHAPP">%1$s</xliff:g> atau tukarkan output, siaran semasa anda akan berhenti"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index 7880c37fb51c..3898f8dcf838 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ဖွင့်ထားသည်၊ ဘယ်သီးသန့်"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ဖွင့်ထားသည်၊ ညာသီးသန့်"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ဖွင့်ထားသည်၊ ဘယ်နှင့် ညာ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"သုံးနေသည် (မီဒီယာသီးသန့်)၊ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ဘက်ထရီ"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"သုံးနေသည် (မီဒီယာသီးသန့်)၊ L- <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ဘက်ထရီ၊ R- <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ဘက်ထရီ"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"ချိတ်ဆက်ထားသည် (အော်ဒီယို မျှဝေခြင်း ပံ့ပိုးသည်)၊ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ဘက်ထရီ"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"ချိတ်ဆက်ထားသည် (အော်ဒီယို မျှဝေခြင်း ပံ့ပိုးသည်)၊ L- <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ဘက်ထရီ၊ R- <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ဘက်ထရီ"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"ချိတ်ဆက်ထားသည် (အော်ဒီယို မျှဝေခြင်း ပံ့ပိုးသည်)၊ ဘယ် <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"ချိတ်ဆက်ထားသည် (အော်ဒီယို မျှဝေခြင်း ပံ့ပိုးသည်)၊ ညာ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"သုံးနေသည် (မီဒီယာသီးသန့်)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"အော်ဒီယို မျှဝေခြင်း ပံ့ပိုးသည်"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"သုံးနေသည် (မီဒီယာသီးသန့်)၊ ဘယ်သီးသန့်"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"သုံးနေသည် (မီဒီယာသီးသန့်)၊ ညာသီးသန့်"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"သုံးနေသည် (မီဒီယာသီးသန့်)၊ ဘယ်နှင့် ညာ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"မီဒီယာ အသံ"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ဖုန်းခေါ်ဆိုမှုများ"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ဖိုင်လွဲပြောင်းခြင်း"</string> @@ -272,7 +261,7 @@      <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>      <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"စက်ပစ္စည်းနှင့် အတူတွဲပါ"</string> -    <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi အတူတွဲချိတ်ရန် ကုဒ်"</string> +    <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi တွဲချိတ်ကုဒ်"</string>      <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"တွဲချိတ်ခြင်း မအောင်မြင်ပါ"</string>      <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"စက်ပစ္စည်းသည် ကွန်ရက်တစ်ခုတည်းသို့ ချိတ်ဆက်ထားခြင်းရှိမရှိ စစ်ဆေးပါ။"</string>      <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR ကုဒ် စကင်ဖတ်ခြင်းဖြင့် Wi-Fi ပေါ်တွင် စက်ပစ္စည်းကို အတူတွဲပါ"</string> @@ -471,7 +460,7 @@      <string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"Deuteranomaly (အနီ-အစိမ်း)"</string>      <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomaly (အနီ-အစိမ်း)"</string>      <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomaly (အပြာ-အဝါ)"</string> -    <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"အရောင်ပြင်ခြင်း"</string> +    <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"အရောင် အမှန်ပြင်ခြင်း"</string>      <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"အရောင် အမှန်ပြင်ခြင်းသည် အောက်ပါတို့အတွက် အသုံးဝင်နိုင်သည်-<br/> <ol> <li>&nbsp;အရောင်များကို ပိုမိုမှန်ကန်စွာ ကြည့်ရှုခြင်း</li> <li>&nbsp;အာရုံစိုက်နိုင်ရန် အရောင်များ ဖယ်ရှားခြင်း</li> </ol>"</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> @@ -555,7 +544,7 @@      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"နှိုးစက်နှင့် သတိပေးချက်များ"</string>      <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"နှိုးစက်နှင့် သတိပေးချက်များ သတ်မှတ်ခွင့်ပြုရန်"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"နှိုးစက်နှင့် သတိပေးချက်များ"</string> -    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"နှိုးစက်သတ်မှတ်ရန်နှင့် အချိန်တိကျရန် လိုအပ်သည့် လုပ်ဆောင်ချက်များ အစီအစဉ်ဆွဲရန် ဤအက်ပ်ကို ခွင့်ပြုပါ။ ၎င်းက အက်ပ်ကို နောက်ခံတွင် လုပ်ဆောင်ခွင့်ပေးပြီး ဘက်ထရီပိုသုံးနိုင်သည်။\n\nဤခွင့်ပြုချက်ကို ပိတ်ထားပါက ဤအက်ပ်ဖြင့် အစီအစဉ်ဆွဲထားသော လက်ရှိနှိုးစက်နှင့် အချိန်သတ်မှတ်ထားသည့် အစီအစဉ်များ အလုပ်လုပ်တော့မည် မဟုတ်ပါ။"</string> +    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"နှိုးစက်သတ်မှတ်ရန်နှင့် အချိန်တိကျရန် လိုအပ်သည့် လုပ်ဆောင်ချက်များအတွက် အစီအစဉ်ဆွဲရန် ဤအက်ပ်ကို ခွင့်ပြုသည်။ ၎င်းက အက်ပ်ကို နောက်ခံတွင် လုပ်ဆောင်ခွင့်ပေးပြီး ဘက်ထရီပိုသုံးနိုင်သည်။\n\nဤခွင့်ပြုချက်ကို ပိတ်ထားပါက ဤအက်ပ်ဖြင့် အစီအစဉ်ဆွဲထားသော လက်ရှိနှိုးစက်နှင့် အချိန်သတ်မှတ်ထားသည့် အစီအစဉ်များ အလုပ်လုပ်တော့မည် မဟုတ်ပါ။"</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"အချိန်ဇယား၊ နှိုးစက်၊ သတိပေးချက်၊ နာရီ"</string>      <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ဖွင့်ရန်"</string>      <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\'မနှောင့်ယှက်ရ\' ဖွင့်ခြင်း"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 0eacc5e6024f..7edaba733ec5 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, bare venstre"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, bare høyre"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, venstre og høyre"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktiv (bare medieinnhold), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktiv (bare medieinnhold), v: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, h: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Tilkoblet (støtter lyddeling), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Tilkoblet (støtter lyddeling), v: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, h: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Tilkoblet (støtter lyddeling), venstre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Tilkoblet (støtter lyddeling), høyre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiv (bare medieinnhold)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Støtter lyddeling"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiv (bare medieinnhold), bare venstre"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiv (bare medieinnhold), bare høyre"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiv (bare medieinnhold), høyre og venstre"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Medielyd"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonsamtaler"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Filoverføring"</string> diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml index 447cd8027b1a..d2c3729ea9c1 100644 --- a/packages/SettingsLib/res/values-ne/arrays.xml +++ b/packages/SettingsLib/res/values-ne/arrays.xml @@ -55,7 +55,7 @@    </string-array>    <string-array name="hdcp_checking_summaries">      <item msgid="4045840870658484038">"HDCP परीक्षण कहिल्यै प्रयोग नगर्नुहोस्"</item> -    <item msgid="8254225038262324761">"DRM सामग्रीको लागि मात्र HDCP जाँचको प्रयोग गरियोस्"</item> +    <item msgid="8254225038262324761">"DRM सामग्रीको लागि मात्र HDCP जाँचको प्रयोग गर्नुहोस्"</item>      <item msgid="6421717003037072581">"सधैँ HDCP जाँच प्रयोग गर्नुहोस्"</item>    </string-array>    <string-array name="bt_hci_snoop_log_entries"> @@ -97,7 +97,7 @@      <item msgid="8147982633566548515">"map14"</item>    </string-array>    <string-array name="bluetooth_a2dp_codec_titles"> -    <item msgid="2494959071796102843">"सिस्टमको छनौट प्रयोग गरियोस् (डिफल्ट)"</item> +    <item msgid="2494959071796102843">"सिस्टमको छनौट प्रयोग गर्नुहोस् (डिफल्ट)"</item>      <item msgid="4055460186095649420">"SBC"</item>      <item msgid="720249083677397051">"AAC"</item>      <item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> अडियो"</item> @@ -107,7 +107,7 @@      <item msgid="506175145534048710">"Opus"</item>    </string-array>    <string-array name="bluetooth_a2dp_codec_summaries"> -    <item msgid="8868109554557331312">"सिस्टमको छनौट प्रयोग गरियोस् (डिफल्ट)"</item> +    <item msgid="8868109554557331312">"सिस्टमको छनौट प्रयोग गर्नुहोस् (डिफल्ट)"</item>      <item msgid="9024885861221697796">"SBC"</item>      <item msgid="4688890470703790013">"AAC"</item>      <item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> अडियो"</item> @@ -117,38 +117,38 @@      <item msgid="7940970833006181407">"Opus"</item>    </string-array>    <string-array name="bluetooth_a2dp_codec_sample_rate_titles"> -    <item msgid="926809261293414607">"सिस्टमको छनौट प्रयोग गरियोस् (डिफल्ट)"</item> +    <item msgid="926809261293414607">"सिस्टमको छनौट प्रयोग गर्नुहोस् (डिफल्ट)"</item>      <item msgid="8003118270854840095">"४४.१ kHz"</item>      <item msgid="3208896645474529394">"४८.० kHz"</item>      <item msgid="8420261949134022577">"८८.२ kHz"</item>      <item msgid="8887519571067543785">"९६.० kHz"</item>    </string-array>    <string-array name="bluetooth_a2dp_codec_sample_rate_summaries"> -    <item msgid="2284090879080331090">"सिस्टमको छनौट प्रयोग गरियोस् (डिफल्ट)"</item> +    <item msgid="2284090879080331090">"सिस्टमको छनौट प्रयोग गर्नुहोस् (डिफल्ट)"</item>      <item msgid="1872276250541651186">"४४.१ kHz"</item>      <item msgid="8736780630001704004">"४८.० kHz"</item>      <item msgid="7698585706868856888">"८८.२ kHz"</item>      <item msgid="8946330945963372966">"९६.० kHz"</item>    </string-array>    <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles"> -    <item msgid="2574107108483219051">"सिस्टमको छनौट प्रयोग गरियोस् (डिफल्ट)"</item> +    <item msgid="2574107108483219051">"सिस्टमको छनौट प्रयोग गर्नुहोस् (डिफल्ट)"</item>      <item msgid="4671992321419011165">"१६ बिट/नमूना"</item>      <item msgid="1933898806184763940">"२४ बिट/नमूना"</item>      <item msgid="1212577207279552119">"३२ बिट/नमूना"</item>    </string-array>    <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries"> -    <item msgid="9196208128729063711">"सिस्टमको छनौट प्रयोग गरियोस् (डिफल्ट)"</item> +    <item msgid="9196208128729063711">"सिस्टमको छनौट प्रयोग गर्नुहोस् (डिफल्ट)"</item>      <item msgid="1084497364516370912">"१६ बिट/नमूना"</item>      <item msgid="2077889391457961734">"२४ बिट/नमूना"</item>      <item msgid="3836844909491316925">"३२ बिट/नमूना"</item>    </string-array>    <string-array name="bluetooth_a2dp_codec_channel_mode_titles"> -    <item msgid="3014194562841654656">"सिस्टमको छनौट प्रयोग गरियोस् (डिफल्ट)"</item> +    <item msgid="3014194562841654656">"सिस्टमको छनौट प्रयोग गर्नुहोस् (डिफल्ट)"</item>      <item msgid="5982952342181788248">"मोनो"</item>      <item msgid="927546067692441494">"स्टेरियो"</item>    </string-array>    <string-array name="bluetooth_a2dp_codec_channel_mode_summaries"> -    <item msgid="1997302811102880485">"सिस्टमको छनौट प्रयोग गरियोस् (डिफल्ट)"</item> +    <item msgid="1997302811102880485">"सिस्टमको छनौट प्रयोग गर्नुहोस् (डिफल्ट)"</item>      <item msgid="8005696114958453588">"मोनो"</item>      <item msgid="1333279807604675720">"स्टेरियो"</item>    </string-array> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index e2236ccdec19..559278a9c935 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -106,41 +106,30 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"बायाँ मात्र अन छ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"सक्रिय, दायाँ मात्र"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"सक्रिय, बायाँ र दायाँ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"सक्रिय छ (मिडिया मात्र), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ब्याट्री"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"सक्रिय छ (मिडिया मात्र), बायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ब्याट्री, दायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ब्याट्री"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"कनेक्ट गरिएको छ (अडियो सेयर गर्न मिल्छ), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ब्याट्री"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"कनेक्ट गरिएको छ (अडियो सेयर गर्न मिल्छ), बायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ब्याट्री, दायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ब्याट्री"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"कनेक्ट गरिएको छ (अडियो सेयर गर्न मिल्छ), बायाँ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"कनेक्ट गरिएको छ (अडियो सेयर गर्न मिल्छ), दायाँ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"सक्रिय छ (मिडिया मात्र)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"अडियो सेयर गर्न मिल्छ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"सक्रिय छ (मिडिया मात्र), बायाँ मात्र"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"सक्रिय छ (मिडिया मात्र), दायाँ मात्र"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"सक्रिय छ (मिडिया मात्र), बायाँ र दायाँ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"मिडिया अडियो"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"फोन कलहरू"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"फाइल स्थानान्तरण"</string> -    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"इनपुट उपकरण"</string> +    <string name="bluetooth_profile_hid" msgid="2969922922664315866">"इनपुट डिभाइस"</string>      <string name="bluetooth_profile_pan" msgid="1006235139308318188">"इन्टरनेट एक्सेस"</string> -    <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"कन्ट्याक्ट र कल हिस्ट्री एक्सेस गर्ने अनुमति दिइयोस्"</string> +    <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"कन्ट्याक्ट र कल हिस्ट्री एक्सेस गर्ने अनुमति दिनुहोस्"</string>      <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"यो जानकारीको प्रयोग कल आएको जानकारी दिने लगायतका कुराका लागि प्रयोग गरिने छ"</string>      <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"इन्टरनेट जडान साझेदारी गर्दै"</string>      <string name="bluetooth_profile_map" msgid="8907204701162107271">"टेक्स्ट म्यासेजहरू"</string>      <string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM एक्सेस"</string>      <string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD अडियो: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>      <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD अडियो"</string> -    <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"श्रवण यन्त्रहरू"</string> +    <string name="bluetooth_profile_hearing_aid" msgid="2607867572569689732">"हियरिङ डिभाइसहरू"</string>      <string name="bluetooth_profile_le_audio" msgid="1725521360076451751">"LE अडियो"</string>      <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="5757754050938807276">"श्रवण यन्त्रहरूमा जडान गरियो"</string>      <string name="bluetooth_le_audio_profile_summary_connected" msgid="6916226974453480650">"LE अडियोमा कनेक्ट गरिएको छ"</string> @@ -176,7 +165,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_hearing_aids" msgid="3983279945542595479">"श्रवण यन्त्रहरू"</string> +    <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"हियरिङ डिभाइसहरू"</string>      <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ब्लुटुथ"</string>      <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi बन्द।"</string>      <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi जडान विच्छेद भयो।"</string> @@ -256,14 +245,14 @@      <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_summary" msgid="7344391423657093011">"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_pair_method_qrcode_title" msgid="6982904096137468634">"QR कोड प्रयोग गरी डिभाइस कनेक्ट गरियोस्"</string> +    <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"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_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> @@ -284,7 +273,7 @@      <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> -    <string name="bugreport_in_power_summary" msgid="1885529649381831775">"बग रिपोर्ट प्राप्त गर्न पावर मेनुमा बटन देखाइयोस्"</string> +    <string name="bugreport_in_power_summary" msgid="1885529649381831775">"बग रिपोर्ट प्राप्त गर्न पावर मेनुमा बटन देखाउनुहोस्"</string>      <string name="keep_screen_on" msgid="1187161672348797558">"डिस्प्ले अफ नहोस्"</string>      <string name="keep_screen_on_summary" msgid="1510731514101925829">"चार्ज गर्दा स्क्रिन कहिल्यै अफ हुँदैन।"</string>      <string name="bt_hci_snoop_log" msgid="7291287955649081448">"ब्लुटुथ HCI snoop लग अन गर्नुहोस्"</string> @@ -298,14 +287,14 @@      <string name="mock_location_app_set" msgid="4706722469342913843">"नमूना स्थान एप: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="debug_networking_category" msgid="6829757985772659599">"नेटवर्किङ"</string>      <string name="wifi_display_certification" msgid="1805579519992520381">"वायरलेस डिस्प्ले प्रयोग गर्ने वा नगर्ने"</string> -    <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi-Fi भर्बोज लग अन गरियोस्"</string> +    <string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi-Fi भर्बोज लग अन गर्नुहोस्"</string>      <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wi‑Fi स्क्यान थ्रोटलिङ"</string>      <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"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> -    <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"निरपेक्ष भोल्युम अफ गरियोस्"</string> -    <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche अन गरियोस्"</string> +    <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नामकरण नगरिएका ब्लुटुथ डिभाइस देखाउनुहोस्"</string> +    <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"निरपेक्ष भोल्युम अफ गर्नुहोस्"</string> +    <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche अन गर्नुहोस्"</string>      <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लुटुथको AVRCP संस्करण"</string>      <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लुटुथको AVRCP संस्करण चयन गर्नुहोस्"</string>      <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ब्लुटुथको MAP संस्करण"</string> @@ -329,8 +318,8 @@      <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">"Wi-Fi लगिङ लेभल बढाइयोस्, Wi-Fi पिकरमा प्रति SSID RSSI देखाइयोस्"</string> +    <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_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"यो मोड अन गरिएका बेला यो डिभाइस म्याक एड्रेस बदल्ने सुविधा अन गरिएको नेटवर्कमा जति पटक कनेक्ट हुन्छ त्यति नै पटक यस डिभाइसको म्याक एड्रेस पनि परिवर्तन हुन सक्छ।"</string>      <string name="wifi_metered_label" msgid="8737187690304098638">"सशुल्क वाइफाइ"</string> @@ -339,15 +328,15 @@      <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"लग बफर प्रति लगर आकार चयन गर्नुहोस्"</string>      <string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"लगरको निरन्तर भण्डारणलाई खाली गर्ने हो?"</string>      <string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"हामी अब निरन्तर लगर मार्फत अनुगमन गरिरहेका छैनौँ, त्यसैले हामीले तपाईँको डिभाइसमा रहेको लगर सम्बन्धी डेटा मेटाउन आवश्यक छ।"</string> -    <string name="select_logpersist_title" msgid="447071974007104196">"लगरसम्बन्धी डेटा निरन्तर डिभाइसमा भण्डारण गरियोस्"</string> +    <string name="select_logpersist_title" msgid="447071974007104196">"लगरसम्बन्धी डेटा निरन्तर डिभाइसमा भण्डारण गर्नुहोस्"</string>      <string name="select_logpersist_dialog_title" msgid="7745193591195485594">"डिभाइसमा निरन्तर भण्डारण गरिने लग सम्बन्धी बफरहरूलाई चयन गर्नुहोस्"</string>      <string name="select_usb_configuration_title" msgid="6339801314922294586">"USB विन्यास चयन गर्नुहोस्"</string>      <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"USB विन्यास चयन गर्नुहोस्"</string>      <string name="allow_mock_location" msgid="2102650981552527884">"नक्कली स्थानहरूलाई अनुमति दिनुहोस्"</string>      <string name="allow_mock_location_summary" msgid="179780881081354579">"नक्कली स्थानहरूलाई अनुमति दिनुहोस्"</string> -    <string name="debug_view_attributes" msgid="3539609843984208216">"भ्युको एट्रिब्युट हेर्ने सुविधा अन गरियोस्"</string> +    <string name="debug_view_attributes" msgid="3539609843984208216">"भ्युको एट्रिब्युट हेर्ने सुविधा अन गर्नुहोस्"</string>      <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Wi-Fi अन हुँदा पनि मोबाइल डेटा सधैँ अन होस् (द्रुत रूपमा नेटवर्क बदल्न)।"</string> -    <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"उपलब्ध हुँदा टेदरिङ हार्डवेयर एक्सलरेसन प्रयोग गरियोस्"</string> +    <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> @@ -355,11 +344,11 @@      <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> -    <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB मा एपको पुष्टि गरियोस्"</string> -    <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"हानिकारक व्यवहार पत्ता लगाउन ADB/ADT बाट इन्स्टल गरिएका एपको जाँच गरियोस्"</string> +    <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB मा एपको पुष्टि गर्नुहोस्"</string> +    <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"हानिकारक व्यवहार पत्ता लगाउन ADB/ADT बाट इन्स्टल गरिएका एपको जाँच गर्नुहोस्"</string>      <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"नामकरण नगरिएका ब्लुटुथ डिभाइस (म्याक एड्रेस भएका मात्र) देखाइने छ"</string>      <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"यसले रिमोट डिभाइसमा अत्यधिक ठूलो वा अनियन्त्रित भोल्युम बज्नेको जस्ता अवस्थामा ब्लुटुथको निरपेक्ष भोल्युम अफ गर्छ।"</string> -    <string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"ब्लुटुथ Gabeldorsche सुविधाको स्ट्याक अन गरियोस्।"</string> +    <string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"ब्लुटुथ Gabeldorsche सुविधाको स्ट्याक अन गर्नुहोस्।"</string>      <string name="enhanced_connectivity_summary" msgid="1576414159820676330">"यसले परिष्कृत जडानको सुविधा सक्षम पार्छ।"</string>      <string name="enable_terminal_title" msgid="3834790541986303654">"स्थानीय टर्मिनल"</string>      <string name="enable_terminal_summary" msgid="2481074834856064500">"स्थानीय सेल पहुँच प्रदान गर्ने टर्मिनल एप सक्षम गर्नुहोस्"</string> @@ -378,60 +367,60 @@      <string name="debug_hw_drawing_category" msgid="5830815169336975162">"हार्डवेयरले बढाएको रेन्डरिङ"</string>      <string name="media_category" msgid="8122076702526144053">"मिडिया"</string>      <string name="debug_monitoring_category" msgid="1597387133765424994">"अनुगमन गरिँदै छ"</string> -    <string name="strict_mode" msgid="889864762140862437">"स्ट्रिक्ट मोड अन गरियोस्"</string> -    <string name="strict_mode_summary" msgid="1838248687233554654">"एपले मुख्य थ्रेडमा लामा गतिविधि गर्दा स्क्रिन फ्ल्यास गरियोस्"</string> +    <string name="strict_mode" msgid="889864762140862437">"स्ट्रिक्ट मोड अन गर्नुहोस्"</string> +    <string name="strict_mode_summary" msgid="1838248687233554654">"एपले मुख्य थ्रेडमा लामा गतिविधि गर्दा स्क्रिन फ्ल्यास गर्नुहोस्"</string>      <string name="pointer_location" msgid="7516929526199520173">"पोइन्टरको स्थान"</string>      <string name="pointer_location_summary" msgid="957120116989798464">"स्क्रिन ओभरलेले हालको टच डेटा देखाउँदै छ"</string> -    <string name="show_touches" msgid="8437666942161289025">"ट्याप देखाइयोस्"</string> -    <string name="show_touches_summary" msgid="3692861665994502193">"ट्यापका लागि भिजुअल प्रतिक्रिया देखाइयोस्"</string> +    <string name="show_touches" msgid="8437666942161289025">"ट्याप देखाउनुहोस्"</string> +    <string name="show_touches_summary" msgid="3692861665994502193">"ट्यापका लागि भिजुअल प्रतिक्रिया देखाउनुहोस्"</string>      <string name="show_key_presses" msgid="6360141722735900214">"थिचिएका कीहरू देखाइयून्"</string> -    <string name="show_key_presses_summary" msgid="725387457373015024">"थिचिएका भौतिक कीसम्बन्धी भिजुअल प्रतिक्रिया देखाइयोस्"</string> -    <string name="show_screen_updates" msgid="2078782895825535494">"सर्फेस अपडेट देखाइयोस्"</string> -    <string name="show_screen_updates_summary" msgid="2126932969682087406">"अपडेट हुँदा विन्डोका पूरै सतहमा देखाइयोस्"</string> -    <string name="show_hw_screen_updates" msgid="2021286231267747506">"GPU भ्युको अपडेट देखाइयोस्"</string> -    <string name="show_hw_screen_updates_summary" msgid="3539770072741435691">"GPU ले बनाएको भ्यु विन्डोमा फ्ल्यास गरियोस्"</string> -    <string name="show_hw_layers_updates" msgid="5268370750002509767">"हार्डवेयर लेयरको अपडेट देखाइयोस्"</string> +    <string name="show_key_presses_summary" msgid="725387457373015024">"थिचिएका भौतिक कीसम्बन्धी भिजुअल प्रतिक्रिया देखाउनुहोस्"</string> +    <string name="show_screen_updates" msgid="2078782895825535494">"सर्फेस अपडेट देखाउनुहोस्"</string> +    <string name="show_screen_updates_summary" msgid="2126932969682087406">"अपडेट हुँदा विन्डोका पूरै सतहमा देखाउनुहोस्"</string> +    <string name="show_hw_screen_updates" msgid="2021286231267747506">"GPU भ्युको अपडेट देखाउनुहोस्"</string> +    <string name="show_hw_screen_updates_summary" msgid="3539770072741435691">"GPU ले बनाएको भ्यु विन्डोमा फ्ल्यास गर्नुहोस्"</string> +    <string name="show_hw_layers_updates" msgid="5268370750002509767">"हार्डवेयर लेयरको अपडेट देखाउनुहोस्"</string>      <string name="show_hw_layers_updates_summary" msgid="5850955890493054618">"हार्डवेयर लेयर अपडेट हुँदा ती लेयर हरिया देखिऊन्"</string> -    <string name="debug_hw_overdraw" msgid="8944851091008756796">"GPU overdraw डिबग गरियोस्"</string> -    <string name="disable_overlays" msgid="4206590799671557143">"HW ओभरले अफ गरियोस्"</string> -    <string name="disable_overlays_summary" msgid="1954852414363338166">"स्क्रिन कोम्पजिट गर्न लागि सधैँ GPU प्रयोग गरियोस्"</string> -    <string name="simulate_color_space" msgid="1206503300335835151">"कलर स्पेसको नक्कल गरियोस्"</string> +    <string name="debug_hw_overdraw" msgid="8944851091008756796">"GPU overdraw डिबग गर्नुहोस्"</string> +    <string name="disable_overlays" msgid="4206590799671557143">"HW ओभरले अफ गर्नुहोस्"</string> +    <string name="disable_overlays_summary" msgid="1954852414363338166">"स्क्रिन कोम्पजिट गर्न लागि सधैँ GPU प्रयोग गर्नुहोस्"</string> +    <string name="simulate_color_space" msgid="1206503300335835151">"कलर स्पेसको नक्कल गर्नुहोस्"</string>      <string name="enable_opengl_traces_title" msgid="4638773318659125196">"OpenGL ट्रेसहरू सक्षम गर्नुहोस्"</string> -    <string name="usb_audio_disable_routing" msgid="3367656923544254975">"USB अडियो राउटिङ अफ गरियोस्"</string> -    <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"USB अडियोमा स्वत: राउट नगरियोस्"</string> -    <string name="debug_layout" msgid="1659216803043339741">"लेआउटका सीमाहरू देखाइयोस्"</string> -    <string name="debug_layout_summary" msgid="8825829038287321978">"क्लिप सीमा, मार्जिन, इत्यादि देखाइयोस्।"</string> -    <string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"RTL लेआउट बलपूर्वक प्रयोग गरियोस्"</string> -    <string name="force_rtl_layout_all_locales_summary" msgid="6663016859517239880">"सबै लोकेलमा RTLमा स्क्रिन लेआउट बलपूर्वक प्रयोग गरियोस्"</string> +    <string name="usb_audio_disable_routing" msgid="3367656923544254975">"USB अडियो राउटिङ अफ गर्नुहोस्"</string> +    <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"USB अडियोमा स्वत: राउट नगर्नुहोस्"</string> +    <string name="debug_layout" msgid="1659216803043339741">"लेआउटका सीमाहरू देखाउनुहोस्"</string> +    <string name="debug_layout_summary" msgid="8825829038287321978">"क्लिप सीमा, मार्जिन, इत्यादि देखाउनुहोस्।"</string> +    <string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"RTL लेआउट बलपूर्वक प्रयोग गर्नुहोस्"</string> +    <string name="force_rtl_layout_all_locales_summary" msgid="6663016859517239880">"सबै लोकेलमा RTLमा स्क्रिन लेआउट बलपूर्वक प्रयोग गर्नुहोस्"</string>      <string name="transparent_navigation_bar" msgid="1933192171384678484">"पारदर्शी नेभिगेसन बार"</string>      <string name="transparent_navigation_bar_summary" msgid="5454359021817330722">"नेभिगेसन बारको ब्याकग्राउन्डको रङ स्वतः पारदर्शी बनाउनुहोस्"</string> -    <string name="window_blurs" msgid="6831008984828425106">"विन्डो ब्लर गरियोस्"</string> -    <string name="force_msaa" msgid="4081288296137775550">"बलपूर्वक 4x MSAA प्रयोग गरियोस्"</string> -    <string name="force_msaa_summary" msgid="9070437493586769500">"OpenGL ES २.० एपमा ४x MSAA अन गरियोस्"</string> -    <string name="show_non_rect_clip" msgid="7499758654867881817">"गैर आयातकर क्लिप रहेका कार्यहरू डिबग गरियोस्"</string> +    <string name="window_blurs" msgid="6831008984828425106">"विन्डो ब्लर गर्नुहोस्"</string> +    <string name="force_msaa" msgid="4081288296137775550">"बलपूर्वक 4x MSAA प्रयोग गर्नुहोस्"</string> +    <string name="force_msaa_summary" msgid="9070437493586769500">"OpenGL ES २.० एपमा ४x MSAA अन गर्नुहोस्"</string> +    <string name="show_non_rect_clip" msgid="7499758654867881817">"गैर आयातकर क्लिप रहेका कार्यहरू डिबग गर्नुहोस्"</string>      <string name="track_frame_time" msgid="522674651937771106">"प्रोफाइलको HWUI रेन्डरिङ"</string> -    <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU का डिबग लेयर अन गरियोस्"</string> -    <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"डिबग एपका लागि GPU का डिबग लेयर लोड गरियोस्"</string> -    <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"भर्बोज भेन्डर लगिङ अन गरियोस्"</string> -    <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"बग रिपोर्टहरूमा डिभाइस विशेषका विक्रेताका अतिरिक्त लगहरू समावेश गरियोस्। यी लगमा निजी जानकारी समावेश हुन सक्छन्, यिनले ब्याट्रीको खपत बढाउन र/वा थप भण्डारण प्रयोग गर्न सक्छन्।"</string> +    <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"GPU का डिबग लेयर अन गर्नुहोस्"</string> +    <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"डिबग एपका लागि GPU का डिबग लेयर लोड गर्नुहोस्"</string> +    <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"भर्बोज भेन्डर लगिङ अन गर्नुहोस्"</string> +    <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"बग रिपोर्टहरूमा डिभाइस विशेषका विक्रेताका अतिरिक्त लगहरू समावेश गर्नुहोस्। यी लगमा निजी जानकारी समावेश हुन सक्छन्, यिनले ब्याट्रीको खपत बढाउन र/वा थप भण्डारण प्रयोग गर्न सक्छन्।"</string>      <string name="window_animation_scale_title" msgid="5236381298376812508">"विन्डो एनिमेसन स्केल"</string>      <string name="transition_animation_scale_title" msgid="1278477690695439337">"संक्रमण एनिमेसन स्केल"</string>      <string name="animator_duration_scale_title" msgid="7082913931326085176">"एनिमेसनको अवधि मापन"</string> -    <string name="overlay_display_devices_title" msgid="5411894622334469607">"सहायक डिस्प्लेको नक्कल गरियोस्"</string> +    <string name="overlay_display_devices_title" msgid="5411894622334469607">"सहायक डिस्प्लेको नक्कल गर्नुहोस्"</string>      <string name="debug_applications_category" msgid="5394089406638954196">"एपहरू"</string>      <string name="immediately_destroy_activities" msgid="1826287490705167403">"गतिविधि नराखियोस्"</string> -    <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"प्रयोगकर्ता कुनै गतिविधिबाट बाहिरिने बित्तिकै उक्त गतिविधि अन्त्य गरियोस्"</string> +    <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"प्रयोगकर्ता कुनै गतिविधिबाट बाहिरिने बित्तिकै उक्त गतिविधि अन्त्य गर्नुहोस्"</string>      <string name="app_process_limit_title" msgid="8361367869453043007">"ब्याकग्राउन्ड प्रक्रियाको सीमा"</string> -    <string name="show_all_anrs" msgid="9160563836616468726">"ब्याकग्राउन्डमा ANR देखाइयोस्"</string> -    <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="show_all_anrs" msgid="9160563836616468726">"ब्याकग्राउन्डमा ANR देखाउनुहोस्"</string> +    <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="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> -    <string name="force_resizable_activities_summary" msgid="2490382056981583062">"तोकिएको नियमको ख्याल नगरी एपलाई एकभन्दा बढी विन्डोमा रिसाइज गर्न सकिने बनाइयोस्।"</string> -    <string name="enable_freeform_support" msgid="7599125687603914253">"फ्रिफर्म विन्डोहरू अन गरियोस्"</string> -    <string name="enable_freeform_support_summary" msgid="1822862728719276331">"प्रयोगात्मक फ्रिफर्म विन्डोहरू चल्ने बनाइयोस्"</string> +    <string name="force_allow_on_external_summary" msgid="8525425782530728238">"तोकिएको नियमको ख्याल नगरी एपलाई बाह्य भण्डारणमा चल्ने बनाउनुहोस्"</string> +    <string name="force_resizable_activities" msgid="7143612144399959606">"बलपूर्वक एपहरूको आकार मिलाउन मिल्ने बनाउनुहोस्"</string> +    <string name="force_resizable_activities_summary" msgid="2490382056981583062">"तोकिएको नियमको ख्याल नगरी एपलाई एकभन्दा बढी विन्डोमा रिसाइज गर्न सकिने बनाउनुहोस्।"</string> +    <string name="enable_freeform_support" msgid="7599125687603914253">"फ्रिफर्म विन्डोहरू अन गर्नुहोस्"</string> +    <string name="enable_freeform_support_summary" msgid="1822862728719276331">"प्रयोगात्मक फ्रिफर्म विन्डोहरू चल्ने बनाउनुहोस्"</string>      <string name="local_backup_password_title" msgid="4631017948933578709">"डेस्कटप ब्याकअप पासवर्ड"</string>      <string name="local_backup_password_summary_none" msgid="7646898032616361714">"हाल डेस्कटपका सबै ब्याकअप पासवर्ड सुरक्षित छैनन्"</string>      <string name="local_backup_password_summary_change" msgid="1707357670383995567">"डेस्कटप पूर्ण ब्याकअपको लागि पासवर्ड बदल्न वा हटाउन ट्याप गर्नुहोस्"</string> @@ -457,7 +446,7 @@      <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिङसम्बन्धी डिफल्ट सेटिङ परिवर्तन गर्नुहोस्"</string>      <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिङ अन गर्नुहोस्"</string>      <string name="transcode_default" msgid="3784803084573509491">"एपहरूमा आधुनिक फर्म्याट प्रयोग गर्न मिल्छ भनी मान्नुहोस्"</string> -    <string name="transcode_notification" msgid="5560515979793436168">"ट्रान्सकोडिङसम्बन्धी सूचना देखाइयोस्"</string> +    <string name="transcode_notification" msgid="5560515979793436168">"ट्रान्सकोडिङसम्बन्धी सूचना देखाउनुहोस्"</string>      <string name="transcode_disable_cache" msgid="3160069309377467045">"ट्रान्सकोडिङको क्यास अफ गर्नुहोस्"</string>      <string name="runningservices_settings_title" msgid="6460099290493086515">"चलिरहेका सेवाहरू"</string>      <string name="runningservices_settings_summary" msgid="1046080643262665743">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string> @@ -472,7 +461,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="1522101114585266455">"तपाईं रङ सच्याउने सुविधाका सहायताले निम्न कार्य गर्न सक्नुहुन्छ:<br/> <ol> <li>&nbsp;अझ सटीक तरिकाले रङहरू हेर्न</li> <li>&nbsp;फोकस गर्नका लागि रङहरू हटाउन</li> </ol>"</string> +    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"तपाईं कलर करेक्सनका सहायताले निम्न कार्य गर्न सक्नुहुन्छ:<br/> <ol> <li>&nbsp;अझ सटीक तरिकाले रङहरू हेर्न</li> <li>&nbsp;फोकस गर्नका लागि रङहरू हटाउन</li> </ol>"</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_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ब्याट्री जोगाउन चार्जिङ होल्ड गरिएको छ"</string> @@ -534,7 +523,7 @@      <string name="retail_demo_reset_next" msgid="3688129033843885362">"अर्को"</string>      <string name="retail_demo_reset_title" msgid="1866911701095959800">"पासवर्ड आवश्यक छ"</string>      <string name="active_input_method_subtypes" msgid="4232680535471633046">"आगत विधिहरू अन गर्नुहोस्"</string> -    <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"सिष्टममा भएका भाषा प्रयोग गरियोस्"</string> +    <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"सिष्टममा भएका भाषा प्रयोग गर्नुहोस्"</string>      <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>का लागि सेटिङहरू खोल्न विफल भयो।"</string>      <string name="ime_security_warning" msgid="6547562217880551450">"यस इनपुट विधिले तपाईँले टाइप गर्नुहुने सम्पूर्ण पाठ बटु्ल्न सक्छ, व्यक्तिगत डेटा जस्तै पासवर्ड र क्रेडिट कार्ड नम्बर लगायतका। यो <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> अनुप्रयोगबाट आउँदछ। यो इनपुट विधि प्रयोग गर्ने हो?"</string>      <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"नोट: रिबुट गरेपछि तपाईंले आफ्नो फोन अनलक नगरेसम्म यो एप सुरु हुँदैन"</string> @@ -708,8 +697,8 @@      <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"किबोर्ड लेआउट छान्नुहोस्"</string>      <string name="keyboard_layout_default_label" msgid="1997292217218546957">"डिफल्ट"</string>      <string name="turn_screen_on_title" msgid="3266937298097573424">"स्क्रिन अन गर्नुहोस्"</string> -    <string name="allow_turn_screen_on" msgid="6194845766392742639">"स्क्रिन अन गर्ने अनुमति दिइयोस्"</string> -    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"कुनै एपलाई स्क्रिन अन गर्ने अनुमति दिइयोस्। यो अनुमति दिइएका खण्डमा तपाईंले अन गर्न नखोजेका बेलामा पनि एपले जुनसुकै बेला स्क्रिन अन गर्न सक्छ।"</string> +    <string name="allow_turn_screen_on" msgid="6194845766392742639">"स्क्रिन अन गर्ने अनुमति दिनुहोस्"</string> +    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"कुनै एपलाई स्क्रिन अन गर्ने अनुमति दिनुहोस्। यो अनुमति दिइएका खण्डमा तपाईंले अन गर्न नखोजेका बेलामा पनि एपले जुनसुकै बेला स्क्रिन अन गर्न सक्छ।"</string>      <string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> ब्रोडकास्ट गर्न छाड्ने हो?"</string>      <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"तपाईंले <xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुभयो वा आउटपुट परिवर्तन गर्नुभयो भने तपाईंको हालको ब्रोडकास्ट रोकिने छ"</string>      <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ब्रोडकास्ट गर्नुहोस्"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 801c73f8dff2..7007677c4079 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -106,35 +106,24 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Actief, alleen links"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Actief, alleen rechts"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Actief, links en rechts"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Actief (alleen media), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batterij"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Actief (alleen media), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batterij, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batterij"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Verbonden (ondersteunt audio delen), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batterij"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Verbonden (ondersteunt audio delen), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batterij, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batterij"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Verbonden (ondersteunt audio delen), links <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Verbonden (ondersteunt audio delen), rechts <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Actief (alleen media)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Ondersteunt audio delen"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Actief (alleen media), alleen links"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Actief (alleen media), alleen rechts"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Actief (alleen media), links en rechts"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Media-audio"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefoongesprekken"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Bestandsoverdracht"</string>      <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Invoerapparaat"</string>      <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Internettoegang"</string>      <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Toegang geven tot contacten en gespreksgeschiedenis"</string> -    <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"De informatie wordt onder andere gebruikt voor gespreksaankondigingen"</string> +    <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Deze informatie wordt o.a. gebruikt voor gespreksaankondigingen"</string>      <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Internetverbinding delen"</string>      <string name="bluetooth_profile_map" msgid="8907204701162107271">"Sms-berichten"</string>      <string name="bluetooth_profile_sap" msgid="8304170950447934386">"Simtoegang"</string> @@ -472,7 +461,7 @@      <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalie (rood-groen)"</string>      <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalie (blauw-geel)"</string>      <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Kleurcorrectie"</string> -    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Kleurcorrectie kan handig zijn in de volgende situaties:<br/> <ol> <li>&nbsp;Je wilt kleuren nauwkeuriger zien.</li> <li>&nbsp;Je wilt kleuren verwijderen zodat je je beter kunt focussen.</li> </ol>"</string> +    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Kleurcorrectie kan handig zijn in de volgende situaties:<br/> <ol> <li>&nbsp;Je wilt kleuren nauwkeuriger zien.</li> <li>&nbsp;Je wilt kleuren verwijderen zodat je je beter kunt concentreren.</li> </ol>"</string>      <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string>      <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>      <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>: opladen is in de wacht gezet om de batterij te beschermen"</string> @@ -553,7 +542,7 @@      <string name="okay" msgid="949938843324579502">"OK"</string>      <string name="done" msgid="381184316122520313">"Klaar"</string>      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Wekkers en herinneringen"</string> -    <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Wekkers en herinneringen laten instellen"</string> +    <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Instellen van wekkers en herinneringen toestaan"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wekkers en herinneringen"</string>      <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Sta toe dat deze app wekkers zet en tijdgevoelige acties plant. De app kan hierdoor op de achtergrond worden uitgevoerd, waardoor je misschien meer batterijlading verbruikt.\n\nAls dit recht uitstaat, werken door deze app geplande bestaande wekkers en tijdgebaseerde afspraken niet."</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"plannen, schema, wekker, alarm, herinnering, klok"</string> @@ -709,7 +698,7 @@      <string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standaard"</string>      <string name="turn_screen_on_title" msgid="3266937298097573424">"Scherm aanzetten"</string>      <string name="allow_turn_screen_on" msgid="6194845766392742639">"Scherm aanzetten toestaan"</string> -    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Toestaan dat een app het scherm aanzet. Indien toegestaan, kan de app het scherm op elk moment aanzetten zonder jouw expliciete intentie."</string> +    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Sta toe dat een app het scherm aanzet. Indien toegestaan, kan de app het scherm op elk moment aanzetten zonder jouw expliciete intentie."</string>      <string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"Uitzending van <xliff:g id="APP_NAME">%1$s</xliff:g> stopzetten?"</string>      <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Als je <xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzendt of de uitvoer wijzigt, wordt je huidige uitzending gestopt"</string>      <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> uitzenden"</string> diff --git a/packages/SettingsLib/res/values-or/arrays.xml b/packages/SettingsLib/res/values-or/arrays.xml index c7c857b092a9..28a8db6da837 100644 --- a/packages/SettingsLib/res/values-or/arrays.xml +++ b/packages/SettingsLib/res/values-or/arrays.xml @@ -188,7 +188,7 @@      <item msgid="409235464399258501">"ବନ୍ଦ"</item>      <item msgid="4195153527464162486">"64K ପିଛା ଲଗ୍ ବଫର୍"</item>      <item msgid="7464037639415220106">"256K ଲଗ୍ ପ୍ରତି ବଫର୍"</item> -    <item msgid="8539423820514360724">"1M ପ୍ରତି ଲଗ୍ ବଫର୍"</item> +    <item msgid="8539423820514360724">"ପ୍ରତି ଲଗ ବଫର ପାଇଁ 1M"</item>      <item msgid="1984761927103140651">"ଲଗ୍ ବଫର୍ ପ୍ରତି 4M"</item>      <item msgid="2983219471251787208">"ଲଗ୍ ବଫର୍ ପ୍ରତି 8M"</item>    </string-array> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index 3cbbc054e863..360810a7de4d 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ସକ୍ରିୟ, କେବଳ ବାମ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ସକ୍ରିୟ, କେବଳ ଡାହାଣ"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ସକ୍ରିୟ, ବାମ ଏବଂ ଡାହାଣ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ) <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ବେଟେରୀ, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ବେଟେରୀ"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"କନେକ୍ଟ ହୋଇଛି (ଅଡିଓ ସେୟାରିଂକୁ ସମର୍ଥନ କରେ), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"କନେକ୍ଟ ହୋଇଛି (ଅଡିଓ ସେୟାରିଂକୁ ସମର୍ଥନ କରେ), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ବେଟେରୀ, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ବେଟେରୀ"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"କନେକ୍ଟ ହୋଇଛି (ଅଡିଓ ସେୟାରିଂକୁ ସମର୍ଥନ କରେ), ବାମ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"କନେକ୍ଟ ହୋଇଛି (ଅଡିଓ ସେୟାରିଂକୁ ସମର୍ଥନ କରେ), ଡାହାଣ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ଅଡିଓ ସେୟାରିଂକୁ ସମର୍ଥନ କରେ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ), କେବଳ ବାମ"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ), କେବଳ ଡାହାଣ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ), ବାମ ଏବଂ ଡାହାଣ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"ମିଡିଆ ଅଡିଓ"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ଫୋନ୍ କଲ୍ଗୁଡ଼ିକ"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ଫାଇଲ୍ ଟ୍ରାନ୍ସଫର୍"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 2105852951c9..cbfef1e56a53 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ਕਿਰਿਆਸ਼ੀਲ, ਸਿਰਫ਼ ਖੱਬਾ"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ਕਿਰਿਆਸ਼ੀਲ, ਸਿਰਫ਼ ਸੱਜਾ"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ਕਿਰਿਆਸ਼ੀਲ, ਖੱਬਾ ਅਤੇ ਸੱਜਾ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ਬੈਟਰੀ"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ), ਖੱਬਾ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ਬੈਟਰੀ, ਸੱਜਾ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ਬੈਟਰੀ"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"ਕਨੈਕਟ ਕੀਤਾ (ਆਡੀਓ ਸਾਂਝਾਕਰਨ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ਬੈਟਰੀ"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"ਕਨੈਕਟ ਕੀਤਾ (ਆਡੀਓ ਸਾਂਝਾਕਰਨ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ), ਖੱਬਾ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ਬੈਟਰੀ, ਸੱਜਾ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ਬੈਟਰੀ"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"ਕਨੈਕਟ ਕੀਤਾ (ਆਡੀਓ ਸਾਂਝਾਕਰਨ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ), ਖੱਬਾ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"ਕਨੈਕਟ ਕੀਤਾ (ਆਡੀਓ ਸਾਂਝਾਕਰਨ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ), ਸੱਜਾ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ਆਡੀਓ ਸਾਂਝਾਕਰਨ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ), ਸਿਰਫ਼ ਖੱਬਾ"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ), ਸਿਰਫ਼ ਸੱਜਾ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ), ਖੱਬਾ ਅਤੇ ਸੱਜਾ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"ਮੀਡੀਆ  ਆਡੀਓ"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ਫ਼ੋਨ ਕਾਲਾਂ"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ"</string> @@ -506,7 +495,7 @@      <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>      <string name="battery_info_status_discharging" msgid="6962689305413556485">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>      <string name="battery_info_status_not_charging" msgid="1103084691314264664">"ਕਨੈਕਟ ਹੋ ਗਿਆ, ਪਰ ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ ਹੈ"</string> -    <string name="battery_info_status_full" msgid="1339002294876531312">"ਚਾਰਜ ਹੋ ਗਈ"</string> +    <string name="battery_info_status_full" msgid="1339002294876531312">"ਬੈਟਰੀ ਚਾਰਜ ਹੋ ਗਈ"</string>      <string name="battery_info_status_full_charged" msgid="3536054261505567948">"ਪੂਰੀ ਚਾਰਜ ਹੋ ਗਈ ਹੈ"</string>      <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>      <string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਕੰਟਰੋਲ ਕੀਤੀ ਗਈ"</string> @@ -555,7 +544,7 @@      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ"</string>      <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ ਸੈੱਟ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ"</string> -    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"ਇਸ ਐਪ ਨੂੰ ਅਲਾਰਮ ਸੈੱਟ ਕਰਨ ਜਾਂ ਹੋਰ ਸਮਾਂ-ਸੰਵੇਦਨਸ਼ੀਲ ਕਾਰਵਾਈਆਂ ਨੂੰ ਨਿਯਤ ਕਰਨ ਦਿਓ। ਇਸ ਨਾਲ ਐਪ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲਣ ਦੀ ਇਜਾਜ਼ਤ ਮਿਲਦੀ ਹੈ, ਜਿਸ ਨਾਲ ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਵੱਧ ਸਕਦੀ ਹੈ।\n\nਜੇ ਇਹ ਇਜਾਜ਼ਤ ਬੰਦ ਹੈ, ਤਾਂ ਮੌਜੂਦਾ ਅਲਾਰਮ ਅਤੇ ਇਸ ਐਪ ਰਾਹੀਂ ਨਿਯਤ ਕੀਤੇ ਸਮਾਂ-ਆਧਾਰਿਤ ਇਵੈਂਟ ਕੰਮ ਨਹੀਂ ਕਰਨਗੇ।"</string> +    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"ਇਸ ਐਪ ਨੂੰ ਅਲਾਰਮ ਸੈੱਟ ਕਰਨ ਜਾਂ ਹੋਰ ਸਮਾਂ-ਸੰਵੇਦਨਸ਼ੀਲ ਕਾਰਵਾਈਆਂ ਨੂੰ ਨਿਯਤ ਕਰਨ ਦਿਓ। ਇਸ ਨਾਲ ਐਪ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲਣ ਦੀ ਇਜਾਜ਼ਤ ਮਿਲਦੀ ਹੈ, ਜਿਸ ਨਾਲ ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਵੱਧ ਸਕਦੀ ਹੈ।\n\nਜੇ ਇਹ ਇਜਾਜ਼ਤ ਬੰਦ ਹੈ, ਤਾਂ ਇਸ ਐਪ ਰਾਹੀਂ ਨਿਯਤ ਕੀਤੇ ਮੌਜੂਦਾ ਅਲਾਰਮ ਅਤੇ ਸਮਾਂ-ਆਧਾਰਿਤ ਇਵੈਂਟ ਕੰਮ ਨਹੀਂ ਕਰਨਗੇ।"</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ਸਮਾਂ-ਸੂਚੀ, ਅਲਾਰਮ, ਰਿਮਾਈਂਡਰ, ਘੜੀ"</string>      <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ਚਾਲੂ ਕਰੋ"</string>      <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਨੂੰ ਚਾਲੂ ਕਰੋ"</string> @@ -709,7 +698,7 @@      <string name="keyboard_layout_default_label" msgid="1997292217218546957">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>      <string name="turn_screen_on_title" msgid="3266937298097573424">"ਸਕ੍ਰੀਨ ਚਾਲੂ ਕਰੋ"</string>      <string name="allow_turn_screen_on" msgid="6194845766392742639">"ਸਕ੍ਰੀਨ ਚਾਲੂ ਕਰਨ ਦਿਓ"</string> -    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"ਐਪ ਨੂੰ ਸਕ੍ਰੀਨ ਚਾਲੂ ਕਰਨ ਦਿਓ। ਜੇ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ, ਤਾਂ ਐਪ ਕਿਸੇ ਵੀ ਸਮੇਂ ਸਕ੍ਰੀਨ ਨੂੰ ਚਾਲੂ ਕਰ ਸਕਦੀ ਹੈ, ਭਾਵੇਂ ਤੁਹਾਨੂੰ ਇਸਦੀ ਲੋੜ ਨਾ ਹੋਵੇ।"</string> +    <string name="allow_turn_screen_on_description" msgid="43834403291575164">"ਐਪ ਨੂੰ ਸਕ੍ਰੀਨ ਚਾਲੂ ਕਰਨ ਦਿਓ। ਇਜਾਜ਼ਤ ਦਿੱਤੇ ਜਾਣ \'ਤੇ, ਇਹ ਐਪ ਤੁਹਾਡੇ ਇਰਾਦੇ ਦੇ ਬਿਨਾਂ ਕਿਸੇ ਵੇਲੇ ਵੀ ਸਕ੍ਰੀਨ ਨੂੰ ਚਾਲੂ ਕਰ ਸਕਦੀ ਹੈ।"</string>      <string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਦੇ ਪ੍ਰਸਾਰਨ ਨੂੰ ਰੋਕਣਾ ਹੈ?"</string>      <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"ਜੇ ਤੁਸੀਂ <xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰਦੇ ਹੋ ਜਾਂ ਆਊਟਪੁੱਟ ਬਦਲਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ ਮੌਜੂਦਾ ਪ੍ਰਸਾਰਨ ਰੁਕ ਜਾਵੇਗਾ"</string>      <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> ਦਾ ਪ੍ਰਸਾਰਨ ਕਰੋ"</string> diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml index 5358ed8f6061..9c25aaa41b63 100644 --- a/packages/SettingsLib/res/values-pl/arrays.xml +++ b/packages/SettingsLib/res/values-pl/arrays.xml @@ -186,10 +186,10 @@    </string-array>    <string-array name="select_logd_size_summaries">      <item msgid="409235464399258501">"Wył."</item> -    <item msgid="4195153527464162486">"64 KB/bufor dziennika"</item> -    <item msgid="7464037639415220106">"256 KB/bufor dziennika"</item> -    <item msgid="8539423820514360724">"1 MB/bufor dziennika"</item> -    <item msgid="1984761927103140651">"4 MB/bufor dziennika"</item> +    <item msgid="4195153527464162486">"64 KB / bufor dziennika"</item> +    <item msgid="7464037639415220106">"256 KB / bufor dziennika"</item> +    <item msgid="8539423820514360724">"1 MB / bufor dziennika"</item> +    <item msgid="1984761927103140651">"4 MB / bufor dziennika"</item>      <item msgid="2983219471251787208">"8 MB na bufor dziennika"</item>    </string-array>    <string-array name="select_logpersist_titles"> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 93e65afeb768..22015b363394 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -106,35 +106,24 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktywne, tylko lewa strona"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktywne, tylko prawa strona"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktywny, lewa i prawa strona"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktywne (tylko multimedia), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> naładowania baterii"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktywne (tylko multimedia), lewa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> naładowania baterii, prawa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> naładowania baterii"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Połączone (obsługa udostępniania dźwięku), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> naładowania baterii"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Połączone (obsługa udostępniania dźwięku), lewa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> naładowania baterii, prawa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> naładowania baterii"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Połączone (obsługa udostępniania dźwięku), lewa <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Połączone (obsługa udostępniania dźwięku), prawa <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktywne (tylko multimedia)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Obsługa udostępniania dźwięku"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktywne (tylko multimedia), tylko lewa"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktywne (tylko multimedia), tylko prawa"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktywne (tylko multimedia), lewa i prawa"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Dźwięk multimediów"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Połączenia telefoniczne"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Przesyłanie pliku"</string>      <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Urządzenie wejściowe"</string>      <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Dostęp do internetu"</string>      <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Zezwól na dostęp do kontaktów i historii połączeń"</string> -    <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Informacje zostaną wykorzystane do powiadomień i nie tylko"</string> +    <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Informacje zostaną wykorzystane m.in. do powiadomień o połączeniach"</string>      <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Udostępnianie połączenia internetowego"</string>      <string name="bluetooth_profile_map" msgid="8907204701162107271">"SMS-y"</string>      <string name="bluetooth_profile_sap" msgid="8304170950447934386">"Dostęp do karty SIM"</string> @@ -336,7 +325,7 @@      <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> -    <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Wybierz rozmiary Rejestratora/bufor dziennika"</string> +    <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Wybierz rozmiary Rejestratora na bufor dziennika"</string>      <string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"Wyczyścić pamięć trwałych dzienników?"</string>      <string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"Po zakończeniu monitorowania przy użyciu trwale zapisywanych dzienników musimy usunąć ich dane zapisane na urządzeniu."</string>      <string name="select_logpersist_title" msgid="447071974007104196">"Zapisuj trwale dane dzienników na urządzeniu"</string> @@ -505,7 +494,7 @@      <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Ładowanie bezprzewodowe"</string>      <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Ładowanie"</string>      <string name="battery_info_status_discharging" msgid="6962689305413556485">"Nie podłączony"</string> -    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Podłączono, ale nie ładuje się"</string> +    <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Podłączono, brak ładowania"</string>      <string name="battery_info_status_full" msgid="1339002294876531312">"Naładowana"</string>      <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Bateria w pełni naładowana"</string>      <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Ładowanie wstrzymane"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 811c04a0a8fa..d1feae47aaa3 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ativo, apenas o esquerdo"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ativo, apenas o direito"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ativo, esquerdo e direito"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Ativo (apenas mídia), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Ativo (apenas mídia), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Conectado (com suporte ao compartilhamento de áudio), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Conectado (com suporte ao compartilhamento de áudio), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Conectado (com suporte ao compartilhamento de áudio), esquerdo <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Conectado (com suporte ao compartilhamento de áudio), direito <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ativo (apenas mídia)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Com suporte ao compartilhamento de áudio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ativo (apenas mídia), apenas esquerdo"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ativo (apenas mídia), somente direito"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ativo (apenas mídia), esquerdo e direito"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Áudio da mídia"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Chamadas telefônicas"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferência de arquivo"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index 4c88683a6a7e..444ce6696d6c 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -106,35 +106,24 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ativo, apenas esquerdo"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ativo, apenas direito"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ativo, esquerdo e direito"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Ativo (apenas para multimédia), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Ativo (apenas para multimédia), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Ligado (suporta partilha de áudio), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Ligado (suporta partilha de áudio), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Ligado (suporta partilha de áudio), esquerdo <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Ligado (suporta partilha de áudio), direito <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ativo (apenas para multimédia)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Suporta partilha de áudio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ativo (apenas para multimédia), apenas esquerdo"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ativo (apenas para multimédia), apenas direito"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ativo (apenas para multimédia), esquerdo e direito"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Áudio de multimédia"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Chamadas telefónicas"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferência do ficheiro"</string>      <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Dispositivo de entrada"</string>      <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Acesso à internet"</string>      <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Acesso a contactos e histórico de chamadas"</string> -    <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"As informações são usadas para anúncios de chamadas e outros"</string> +    <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"As informações são usadas para anúncios por chamadas e outros"</string>      <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Partilha da ligação à internet"</string>      <string name="bluetooth_profile_map" msgid="8907204701162107271">"Mensagens de texto"</string>      <string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acesso ao SIM"</string> @@ -410,7 +399,7 @@      <string name="force_msaa_summary" msgid="9070437493586769500">"Ativar o 4x MSAA em aplicações OpenGL ES 2.0"</string>      <string name="show_non_rect_clip" msgid="7499758654867881817">"Depurar operações de clipe não retangulares"</string>      <string name="track_frame_time" msgid="522674651937771106">"Renderização HWUI do perfil"</string> -    <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Ativar cam. depuração GPU"</string> +    <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Ativar camadas de depuração GPU"</string>      <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Permite carregamento de camadas de depuração de GPU para apps de depuração"</string>      <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Ativ. registo do fornecedor"</string>      <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Inclua registos adicionais de fornecedores específicos de dispositivos em relatórios de erros, que podem conter informações privadas, utilizar mais bateria e/ou utilizar mais armazenamento."</string> @@ -555,7 +544,7 @@      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmes e lembretes"</string>      <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permitir alarmes e lembretes"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string> -    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permita que esta app defina alarmes e agende outras ações com base no tempo. Esta ação permite que a app seja executada em segundo plano, o que pode utilizar mais bateria.\n\nSe esta autorização estiver desativada, os alarmes existentes e os eventos com base no tempo agendados por esta app não funcionam."</string> +    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permita que a app defina alarmes e agende ações com um horário específico. Esta ação permite que a app seja executada em segundo plano, o que pode usar mais bateria.\n\nSe esta autorização estiver desativada, os alarmes existentes e os eventos com base no tempo agendados por esta app não funcionam."</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"agendar, alarme, lembrete, relógio"</string>      <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ativar"</string>      <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Ativar o modo Não incomodar"</string> @@ -595,7 +584,7 @@      <string name="tv_media_transfer_internal_speakers" msgid="8181494402866565865">"Altifalantes internos"</string>      <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problema ao ligar. Desligue e volte a ligar o dispositivo."</string>      <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Dispositivo de áudio com fios"</string> -    <string name="help_label" msgid="3528360748637781274">"Ajuda e comentários"</string> +    <string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string>      <string name="storage_category" msgid="2287342585424631813">"Armazenamento"</string>      <string name="shared_data_title" msgid="1017034836800864953">"Dados partilhados"</string>      <string name="shared_data_summary" msgid="5516326713822885652">"Ver e modificar dados partilhados"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 811c04a0a8fa..d1feae47aaa3 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Ativo, apenas o esquerdo"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Ativo, apenas o direito"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Ativo, esquerdo e direito"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Ativo (apenas mídia), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Ativo (apenas mídia), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Conectado (com suporte ao compartilhamento de áudio), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Conectado (com suporte ao compartilhamento de áudio), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Conectado (com suporte ao compartilhamento de áudio), esquerdo <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Conectado (com suporte ao compartilhamento de áudio), direito <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ativo (apenas mídia)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Com suporte ao compartilhamento de áudio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ativo (apenas mídia), apenas esquerdo"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ativo (apenas mídia), somente direito"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ativo (apenas mídia), esquerdo e direito"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Áudio da mídia"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Chamadas telefônicas"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferência de arquivo"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 1233afd7a897..06e61ca2d753 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Activ, numai stânga"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Activ, numai dreapta"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Activ, stânga și dreapta"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Activ (numai pentru conținut media), nivelul bateriei: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Activ (numai pentru conținut media): nivelul bateriei din stânga: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, nivelul bateriei din dreapta: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Conectat (acceptă permiterea accesului la audio), nivelul bateriei: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Conectat (acceptă permiterea accesului la audio), nivelul bateriei din stânga: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, nivelul bateriei din dreapta: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Conectat (acceptă permiterea accesului la audio), nivelul bateriei din stânga: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Conectat (acceptă permiterea accesului la audio), nivelul bateriei din dreapta: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Activ (numai pentru conținut media)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Acceptă permiterea accesului la audio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Activ (numai pentru conținut media), numai stânga"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Activ (numai pentru conținut media), numai dreapta"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Activ (numai pentru conținut media), stânga și dreapta"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Conținut media audio"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Apeluri telefonice"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transfer de fișiere"</string> @@ -553,7 +542,7 @@      <string name="okay" msgid="949938843324579502">"OK"</string>      <string name="done" msgid="381184316122520313">"Gata"</string>      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarme și mementouri"</string> -    <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permite setarea pentru alarme și mementouri"</string> +    <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Permite setarea de alarme și mementouri"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarme și mementouri"</string>      <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite acestei aplicații să seteze alarme și să planifice acțiuni care trebuie realizate în timp scurt. Astfel, aplicația poate să ruleze în fundal, ceea ce ar putea crește consumul de baterie.\n\nDacă permisiunea este dezactivată, alarmele și evenimentele dependente de timp planificate de aplicație nu vor funcționa."</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programare, alarmă, memento, ceas"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 43645f411112..8bb5b19aa038 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активен, только левое ухо"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активен, только правое ухо"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активен, оба уха"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Используется (только для медиа), заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Используется (только для медиа), заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (Л), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (П)"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Подключено (поддерживается отправка аудио), заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Подключено (поддерживается отправка аудио), заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (Л), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (П)"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Подключено (поддерживается отправка аудио), заряд левого наушника: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Подключено (поддерживается отправка аудио), заряд правого наушника: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Используется (только для медиа)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Поддерживается отправка аудио"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Используется (только для медиа), левый наушник"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Используется (только для медиа), правый наушник"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Используется (только для медиа), левый и правый наушники"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Профиль A2DP"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Звонки"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Профиль OPP"</string> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index d965b738a735..074028c0e57f 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"සක්රිය, වම පමණි"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"සක්රිය, දකුණ පමණි"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"සක්රිය, වම සහ දකුණ"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"සක්රිය (මාධ්ය පමණි), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> බැටරිය"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"සක්රිය (මාධ්ය පමණි), ව: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> බැටරිය, ද: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> බැටරිය"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"සම්බන්ධයි (ශ්රව්ය බෙදා ගැනීම සහය දක්වයි), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> බැටරිය"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"සම්බන්ධයි (ශ්රව්ය බෙදා ගැනීම සහය දක්වයි), ව: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> බැටරිය, ද: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> බැටරිය"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"සම්බන්ධයි (ශ්රව්ය බෙදා ගැනීම සහය දක්වයි), වම <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"සම්බන්ධයි (ශ්රව්ය බෙදා ගැනීම සහය දක්වයි), දකුණ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"සක්රිය (මාධ්ය පමණි)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ශ්රව්ය බෙදා ගැනීම සහය දක්වයි"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"සක්රිය (මාධ්ය පමණි), වම පමණි"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"සක්රිය (මාධ්ය පමණි), දකුණ පමණි"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"සක්රිය (මාධ්ය පමණි), වම සහ දකුණ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"මාධ්ය ශ්රව්ය"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"දුරකථන ඇමතුම්"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ගොනු හුවමාරුව"</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 77c265e4136f..dab6e97a9fa5 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktívne, iba ľavá strana"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktívne, iba pravá strana"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktívne, ľavá aj pravá strana"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktívne (iba médiá), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batérie"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktívne (iba médiá), Ľ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batérie, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batérie"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Pripojené (podporuje zdieľanie zvuku), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batérie"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Pripojené (podporuje zdieľanie zvuku), Ľ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batérie, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batérie"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Pripojené (podporuje zdieľanie zvuku), ľavá strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Pripojené (podporuje zdieľanie zvuku), pravá strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktívne (iba médiá)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podporuje zdieľanie zvuku"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktívne (iba médiá), iba ľavá strana"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktívne (iba médiá), iba pravá strana"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktívne (iba médiá), ľavá aj pravá strana"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvuk médií"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonické hovory"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Prenos súborov"</string> @@ -555,7 +544,7 @@      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Budíky a pripomenutia"</string>      <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Povoliť nastavovanie budíkov a pripomenutí"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Budíky a pripomenutia"</string> -    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Povoľte tejto aplikácii nastavovať budíky a plánovať akcie s časovým obmedzením. Aplikácii to umožní pracovať na pozadí, čo môže zvýšiť spotrebu batérie.\n\nAk je toto povolenie vypnuté, existujúce budíky a udalosti s časovým obmedzením naplánované touto aplikáciu nebudú fungovať."</string> +    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Povoľte tejto aplikácii nastavovať budíky a plánovať akcie s časovým obmedzením. Aplikácii to umožní pracovať na pozadí, čo môže zvýšiť spotrebu batérie.\n\nAk je toto povolenie vypnuté, existujúce budíky a udalosti s časovým obmedzením naplánované touto aplikáciou nebudú fungovať."</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"plán, budík, pripomenutie, hodiny"</string>      <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Zapnúť"</string>      <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Zapnite režim bez vyrušení"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index abca26f03cbf..b8422038b300 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktivno, samo levo"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktivno, samo desno"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktivno, levo in desno"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktivno (samo predstavnost), napolnjenost baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktivno (samo predstavnost), napolnjenost leve baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, napolnjenost desne baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Povezano (podpira deljenje zvoka), napolnjenost baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Povezano (podpira deljenje zvoka), napolnjenost leve baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, napolnjenost desne baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Povezano (podpira deljenje zvoka), napolnjenost leve baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Povezano (podpira deljenje zvoka), napolnjenost desne baterije: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktivno (samo predstavnost)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podpira deljenje zvoka"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktivno (samo predstavnost), samo levo"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktivno (samo predstavnost), samo desno"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktivno (samo predstavnost), levo in desno"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Zvok predstavnosti"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonski klici"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Prenos datoteke"</string> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index 0f48e42c95e4..54ea2e7b46db 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktive, vetëm majtas"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktive, vetëm djathtas"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktive, majtas dhe djathtas"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktiv (vetëm për media), bateria në <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktiv (vetëm për media), majtas: bateria në <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, djathtas: bateria në <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Lidhur (mbështet ndarjen e audios), bateria në <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Lidhur (mbështet ndarjen e audios), majtas: bateria në <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, djathtas: bateria në <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Lidhur (mbështet ndarjen e audios), majtas <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Lidhur (mbështet ndarjen e audios), djathtas <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiv (vetëm për media)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Mbështet ndarjen e audios"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiv (vetëm për media), vetëm majtas"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiv (vetëm për media), vetëm djathtas"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiv (vetëm për media), majtas dhe djathtas"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audioja e medias"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonatat"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferimi i skedarëve"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index d309036cabdf..3df0824f0cf2 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активно, само с леве стране"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активно, с десне стране"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активно, с леве и десне стране"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Активан (само за медије), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерије"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Активан (само за медије), лево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батерије, десно: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерије"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Повезан (подржава дељење звука), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерије"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Повезан (подржава дељење звука), лево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батерије, десно: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерије"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Повезан (подржава дељење звука), лево <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Повезан (подржава дељење звука), десно <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Активан (само за медије)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Подржава дељење звука"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Активан (само за медије), само лево"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Активан (само за медије), само десно"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Активан (само за медије), лево и десно"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Звук медија"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Телефонски позиви"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Пренос датотеке"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index 363396a02c33..2a57893ceb43 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktiv, bara vänster"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktiv, bara höger"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktiv, vänster och höger"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktiv (endast media), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktiv (endast media), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Ansluten (ljuddelning stöds), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Ansluten (ljuddelning stöds), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Ansluten (ljuddelning stöds), vänster <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Ansluten (ljuddelning stöds), höger <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiv (endast media)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Ljuddelning stöds"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiv (endast media), endast vänster"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiv (endast media), endast höger"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiv (endast media), vänster och höger"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Medialjud"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefonsamtal"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Filöverföring"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index ebff38bbd994..ab518d00b8b4 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Inatumika, kushoto pekee"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Inatumika, kulia pekee"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Inatumika, kushoto na kulia"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Inatumika (maudhui pekee), chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Inatumika (maudhui pekee), Kushoto: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Kulia: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Imeunganishwa (inaweza kutumia kipengele cha kusikiliza pamoja), chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Imeunganishwa (inaweza kutumia kipengele cha kusikiliza pamoja), Kushoto: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Kulia: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Imeunganishwa (inaweza kutumia kipengele cha kusikiliza pamoja), chaji ya betri ya kushoto imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Imeunganishwa (inaweza kutumia kipengele cha kusikiliza pamoja), chaji ya betri ya kulia imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Inatumika (maudhui pekee)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Inaweza kutumia kipengele cha kusikiliza pamoja"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Inatumika (maudhui pekee), kushoto pekee"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Inatumika (maudhui pekee), kulia pekee"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Inatumika (maudhui pekee), kushoto na kulia"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Sauti ya maudhui"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Simu"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Uhamishaji wa faili"</string> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 1648de0dc03a..1462b7368ef7 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"இடது பக்கம் மட்டும் செயலில் உள்ளது"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"வலது பக்கம் மட்டும் செயலில் உள்ளது"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"வலது மற்றும் இடது பக்கம் செயலில் உள்ளது"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"செயலிலுள்ளது (மீடியா மட்டும்), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"செயலிலுள்ளது (மீடியா மட்டும்), இடது: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> பேட்டரி, வலது: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> பேட்டரி"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"இணைக்கப்பட்டுள்ளது (ஆடியோ பகிர்வை ஆதரிக்கிறது), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"இணைக்கப்பட்டுள்ளது (ஆடியோ பகிர்வை ஆதரிக்கிறது), இடது: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> பேட்டரி, வலது: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> பேட்டரி"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"இணைக்கப்பட்டுள்ளது (ஆடியோ பகிர்வை ஆதரிக்கிறது), இடது: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"இணைக்கப்பட்டுள்ளது (ஆடியோ பகிர்வை ஆதரிக்கிறது), வலது: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"செயலிலுள்ளது (மீடியா மட்டும்)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ஆடியோ பகிர்வை ஆதரிக்கிறது"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"செயலிலுள்ளது (மீடியா மட்டும்), இடதுபுறம் மட்டும்"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"செயலிலுள்ளது (மீடியா மட்டும்), வலதுபுறம் மட்டும்"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"செயலிலுள்ளது (மீடியா மட்டும்), இடதுபுறம் மற்றும் வலதுபுறம்"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"மீடியா ஆடியோ"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ஃபோன் அழைப்புகள்"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ஃபைல் இடமாற்றம்"</string> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index 7ee57cf95c75..718442c6ceac 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"యాక్టివ్గా ఉంది, ఎడమవైపు మాత్రమే యాక్టివ్గా ఉంది"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"యాక్టివ్గా ఉంది, కుడివైపు యాక్టివ్గా ఉంది"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"యాక్టివ్గా ఉంది, ఎడమవైపు, కుడివైపు యాక్టివ్గా ఉంది"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"యాక్టివ్ (మీడియా మాత్రమే), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> బ్యాటరీ"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"యాక్టివ్ (మీడియా మాత్రమే), ఎడమ వైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> బ్యాటరీ, కుడివైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> బ్యాటరీ"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"కనెక్ట్ చేయబడింది (ఆడియో షేరింగ్కు సపోర్ట్ చేస్తుంది), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> బ్యాటరీ"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"కనెక్ట్ చేయబడింది (ఆడియో షేరింగ్కు సపోర్ట్ చేస్తుంది), ఎడమ వైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> బ్యాటరీ, కుడివైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> బ్యాటరీ"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"కనెక్ట్ చేయబడింది (ఆడియో షేరింగ్కు సపోర్ట్ చేస్తుంది), ఎడమ వైపు <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"కనెక్ట్ చేయబడింది (ఆడియో షేరింగ్కు సపోర్ట్ చేస్తుంది), కుడివైపు <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"యాక్టివ్ (మీడియా మాత్రమే)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ఆడియో షేరింగ్కు సపోర్ట్ చేస్తుంది"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"యాక్టివ్ (మీడియా మాత్రమే), ఎడమ వైపు మాత్రమే"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"యాక్టివ్ (మీడియా మాత్రమే), కుడివైపు మాత్రమే"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"యాక్టివ్ (మీడియా మాత్రమే), ఎడమ, కుడివైపు మాత్రమే"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"మీడియా ఆడియో"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ఫోన్ కాల్స్"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ఫైల్ బదిలీ"</string> @@ -162,8 +151,8 @@      <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"ఇన్పుట్ కోసం ఉపయోగించండి"</string>      <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="3374057355721486932">"వినికిడి పరికరాల కోసం ఉపయోగించండి"</string>      <string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"LE_AUDIO కోసం ఉపయోగించండి"</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> @@ -201,7 +190,7 @@      <string name="running_process_item_user_label" msgid="3988506293099805796">"యూజర్: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>      <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" msgid="8130616705989351312">"టెక్స్ట్-టు-స్పీచ్ సెట్టింగ్లు"</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> @@ -339,7 +328,7 @@      <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"లాగ్ బఫర్కి లాగర్ పరిమా. ఎంచుకోండి"</string>      <string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"లాగర్ నిరంతర నిల్వలోని డేటాను తీసివేయాలా?"</string>      <string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"మేము నిరంతర లాగర్తో ఇక పర్యవేక్షించనప్పుడు, మీ పరికరంలోని లాగర్ డేటాను మేము తొలగించాల్సి ఉంటుంది."</string> -    <string name="select_logpersist_title" msgid="447071974007104196">"పరికరంలో లాగర్ డేటా నిరంతరం స్టోర్ చేయి"</string> +    <string name="select_logpersist_title" msgid="447071974007104196">"పరికరంలో లాగర్ డేటా నిరంతరం స్టోర్ చేయండి"</string>      <string name="select_logpersist_dialog_title" msgid="7745193591195485594">"పరికరంలో నిరంతరం స్టోరేజ్ చేయాల్సిన లాగ్ బఫర్లను ఎంచుకోండి"</string>      <string name="select_usb_configuration_title" msgid="6339801314922294586">"USB కాన్ఫిగరేషన్ని ఎంచుకోండి"</string>      <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"USB కాన్ఫిగరేషన్ని ఎంచుకోండి"</string> @@ -555,7 +544,7 @@      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"అలారాలు, రిమైండర్లు"</string>      <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"అలారాలు, రిమైండర్లను సెట్ చేయడానికి అనుమతించండి"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"అలారాలు & రిమైండర్లు"</string> -    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"అలారాలను సెట్ చేయడానికి, సమయ-సునిశిత చర్యలను షెడ్యూల్ చేయడానికి ఈ యాప్ను అనుమతించండి. ఇది యాప్ను బ్యాక్గ్రౌండ్లో రన్ అవడానికి అనుమతిస్తుంది, ఇది ఎక్కువ బ్యాటరీని ఉపయోగించవచ్చు.\n\nఈ అనుమతిని ఆఫ్ చేస్తే, ఈ యాప్ ద్వారా షెడ్యూల్ చేసిన ఇప్పటికే ఉన్న అలారాలు, సమయ-ఆధారిత ఈవెంట్లు పనిచేయవు."</string> +    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"అలారాలను సెట్ చేయడానికి, టైమ్-సెన్సిటివ్ చర్యలను షెడ్యూల్ చేయడానికి ఈ యాప్ను అనుమతించండి. ఇది యాప్ను బ్యాక్గ్రౌండ్లో రన్ అవడానికి అనుమతిస్తుంది, ఇది ఎక్కువ బ్యాటరీని ఉపయోగించవచ్చు.\n\nఈ అనుమతిని ఆఫ్ చేస్తే, ఈ యాప్ ద్వారా షెడ్యూల్ చేసినటువంటి ఇప్పటికే ఉన్న అలారాలు, టైమ్-ఆధారిత ఈవెంట్లు పనిచేయవు."</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"షెడ్యూల్, అలారం, రిమైండర్, గడియారం"</string>      <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ఆన్ చేయండి"</string>      <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"అంతరాయం కలిగించవద్దును ఆన్ చేయండి"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index 55b57db0a884..6cbed5a8e5fa 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"ใช้งานอยู่ เฉพาะข้างซ้าย"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"ใช้งานอยู่ เฉพาะข้างขวา"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"ใช้งานอยู่ ข้างซ้ายและขวา"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"ใช้งานอยู่ (สื่อเท่านั้น), แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"ใช้งานอยู่ (สื่อเท่านั้น), L: แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"เชื่อมต่อแล้ว (รองรับการแชร์เสียง), แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"เชื่อมต่อแล้ว (รองรับการแชร์เสียง), L: แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"เชื่อมต่อแล้ว (รองรับการแชร์เสียง), ซ้าย <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"เชื่อมต่อแล้ว (รองรับการแชร์เสียง), ขวา <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ใช้งานอยู่ (สื่อเท่านั้น)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"รองรับการแชร์เสียง"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ใช้งานอยู่ (สื่อเท่านั้น), ซ้ายเท่านั้น"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ใช้งานอยู่ (สื่อเท่านั้น), ขวาเท่านั้น"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ใช้งานอยู่ (สื่อเท่านั้น), ซ้ายและขวา"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"เสียงของสื่อ"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"โทรศัพท์"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"การถ่ายโอนไฟล์"</string> @@ -203,7 +192,7 @@      <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_default_rate_title" msgid="3964187817364304022">"ความเร็วของคำพูด"</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>      <string name="tts_default_pitch_summary" msgid="9132719475281551884">"มีผลต่อโทนเสียงของข้อความสังเคราะห์"</string> @@ -487,7 +476,7 @@      <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_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="8956656616031395152">"เหลือน้อยกว่า <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>      <string name="power_remaining_less_than_duration" msgid="318215464914990578">"เหลือน้อยกว่า <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index c34588d4c49d..db07e7a21a4a 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Aktibo, kaliwa lang"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Aktibo, kanan lang"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Aktibo, kaliwa at kanan"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Aktibo (media lang), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterya"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Aktibo (media lang), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterya, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterya"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Nakakonekta (sinusuportahan ang pag-share ng audio), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterya"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Nakakonekta (sinusuportahan ang pag-share ng audio), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterya, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterya"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Nakakonekta (sinusuportahan ang pag-share ng audio), kaliwa <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Nakakonekta (sinusuportahan ang pag-share ng audio), kanan <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktibo (media lang)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Sinusuportahan ang pag-share ng audio"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktibo (media lang), kaliwa lang"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktibo (media lang), kanan lang"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktibo (media lang), kaliwa at kanan"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Audio ng media"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Mga tawag sa telepono"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Paglilipat ng file"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 4315241763fa..4a6e90395873 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Yalnızca sol tarafta etkin"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Yalnızca sağ tarafta etkin"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Sol ve sağ tarafta etkin"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Etkin (yalnızca medya), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pil seviyesi"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Etkin (yalnızca medya), Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> pil seviyesi, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pil seviyesi"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Bağlı (ses paylaşımını destekler), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pil seviyesi"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Bağlı (ses paylaşımını destekler), Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> pil seviyesi, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pil seviyesi"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Bağlı (ses paylaşımını destekler), sol <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Bağlı (ses paylaşımını destekler), sağ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Etkin (yalnızca medya)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Ses paylaşımını destekler"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Etkin (yalnızca medya), yalnızca sol"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Etkin (yalnızca medya), yalnızca sağ"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Etkin (yalnızca medya), sol ve sağ"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Medya sesi"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefon aramaları"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Dosya aktarımı"</string> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index ac9edc58f057..ec1f7f54e2ed 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Активовано, лише лівий"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Активовано, лише правий"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Активовано, лівий і правий"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Активно (лише для мультимедіа); <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> заряду акумулятора"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Активно (лише для мультимедіа); лівий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> заряду акумулятора, правий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> заряду акумулятора"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Підключено (підтримує надсилання аудіо); <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> заряду акумулятора"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Підключено (підтримує надсилання аудіо); лівий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> заряду акумулятора, правий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> заряду акумулятора"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Підключено (підтримує надсилання аудіо); лівий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Підключено (підтримує надсилання аудіо); правий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Активно (лише для мультимедіа)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Підтримує надсилання аудіо"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Активно (лише для мультимедіа); лише лівий"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Активно (лише для мультимедіа); лише правий"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Активно (лише для мультимедіа); лівий і правий"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Звук медіафайлів"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Телефонні дзвінки"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Передавання файлів"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index d2fc32a44c75..db8c42739f56 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"فعال، صرف بائیں طرف"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"فعال، صرف دائیں طرف"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"فعال، صرف بائیں اور دائیں طرف"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"فعال (صرف میڈیا)، <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"فعال (صرف میڈیا)، L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> بیٹری، R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> بیٹری"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"منسلک ہے (آڈیو کے اشتراک کو سپورٹ کرتا ہے)، <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"منسلک ہے (آڈیو کے اشتراک کو سپورٹ کرتا ہے)، L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> بیٹری، R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> بیٹری"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"منسلک ہے (آڈیو کے اشتراک کو سپورٹ کرتا ہے)، بائیں <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"منسلک ہے (آڈیو کے اشتراک کو سپورٹ کرتا ہے)، دائیں <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"فعال (صرف میڈیا)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"آڈیو کے اشتراک کو سپورٹ کرتا ہے"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"فعال (صرف میڈیا)، صرف بائیں"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"فعال (صرف میڈیا)، صرف دائیں"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"فعال (صرف میڈیا)، بائیں اور دائیں"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"میڈيا آڈیو"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"فون کالز"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"فائل کی منتقلی"</string> @@ -487,7 +476,7 @@      <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_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="8956656616031395152">"<xliff:g id="THRESHOLD">%1$s</xliff:g> سے کم باقی ہے"</string>      <string name="power_remaining_less_than_duration" msgid="318215464914990578">"<xliff:g id="THRESHOLD">%1$s</xliff:g> سے کم باقی ہے (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index 3c8e249a1900..2355fc966acf 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Faol, faqat chap"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Faol, faqat oʻng"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Faol, chap va oʻng"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Faol (faqat media uchun), quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Faol (faqat media uchun), quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (L), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (R)"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Ulangan (audio yuborish mumkin), quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Ulangan (audio yuborish mumkin), quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (L), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (R)"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Ulangan (audio yuborish mumkin), quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (chap)"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Ulangan (audio yuborish mumkin), quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (oʻng)"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Faol (faqat media uchun)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Audio yuborishi mumkin"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Faol (faqat media uchun), faqat chap"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Faol (faqat media uchun), faqat oʻng"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Faol (faqat media uchun), chap va oʻng"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"A2DP profili"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Telefon chaqiruvlari"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Fayl uzatish"</string> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index b3d70cc66500..2427bea4a9fb 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Đang hoạt động, chỉ tai bên trái"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Đang hoạt động, chỉ tai phải"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Đang hoạt động, cả tai phải và tai trái"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Đang hoạt động (chỉ phát nội dung đa phương tiện), pin còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Đang hoạt động (chỉ phát nội dung đa phương tiện), L: pin còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: pin còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Đã kết nối (có hỗ trợ tính năng chia sẻ âm thanh), pin còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Đã kết nối (có hỗ trợ tính năng chia sẻ âm thanh), L: pin còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: pin còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Đã kết nối (có hỗ trợ tính năng chia sẻ âm thanh), tai nghe bên trái còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pin"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Đã kết nối (có hỗ trợ tính năng chia sẻ âm thanh), tai nghe bên phải còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pin"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Đang hoạt động (chỉ phát nội dung đa phương tiện)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Hỗ trợ tính năng chia sẻ âm thanh"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Đang hoạt động (chỉ phát nội dung đa phương tiện), chỉ dùng tai nghe bên trái"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Đang hoạt động (chỉ phát nội dung đa phương tiện), chỉ dùng tai nghe bên phải"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Đang hoạt động (chỉ phát nội dung đa phương tiện), đang dùng cả tai nghe bên trái và phải"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Âm thanh nội dung nghe nhìn"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Cuộc gọi điện thoại"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Chuyển tệp"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 6a9a18caeca4..c3e9e20826b4 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"使用中,仅左耳助听器"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"使用中,仅右耳助听器"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"使用中,左右耳助听器"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"使用中(仅限媒体),电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"使用中(仅限媒体),左侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"已连接(支持音频分享),电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"已连接(支持音频分享),左侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"已连接(支持音频分享),左侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"已连接(支持音频分享),右侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"使用中(仅限媒体)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"支持音频分享"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"使用中(仅限媒体),仅左侧"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"使用中(仅限媒体),仅右侧"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"使用中(仅限媒体),左侧和右侧"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"媒体音频"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"通话"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"文件传输"</string> @@ -472,7 +461,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="1522101114585266455">"“色彩校正”功能适用于以下情况:<br/> <ol> <li>您想更准确地查看颜色</li> <li>您想移除颜色以提高专注程度</li> </ol>"</string> +    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"“色彩校正”功能适用于以下情况:<br/> <ol> <li>您想更准确地查看颜色</li> <li>您想移除颜色以提高专注度</li> </ol>"</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_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 为保护电池,已暂停充电"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index ecdfa62b3acc..cc1dc11ddcb2 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"使用中,僅左耳"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"使用中,僅右耳"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"使用中,左右耳"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"啟用 (只限媒體),<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 電量"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"啟用 (只限媒體),左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> 電量,右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> 電量"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"已連線 (支援音訊分享功能),<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 電量"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"已連線 (支援音訊分享功能),左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> 電量,右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> 電量"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"已連線 (支援音訊分享功能),左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"已連線 (支援音訊分享功能),右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"啟用 (只限媒體)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"支援音訊分享功能"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"左側啟用 (只限媒體)"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"右側啟用 (只限媒體)"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"右側同時啟用 (只限媒體)"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"媒體音效"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"通話"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"檔案傳輸"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 99fe41eebd99..26b79076aa1d 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"使用中,僅左耳"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"使用中,僅右耳"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"使用中,左右耳"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"啟用 (僅限媒體),<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 剩餘電力"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"啟用 (僅限媒體),左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> 剩餘電力,右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> 剩餘電力"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"已連線 (支援音訊分享),<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 剩餘電力"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"已連線 (支援音訊分享),左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> 剩餘電力,右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> 剩餘電力"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"已連線 (支援音訊分享),左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"已連線 (支援音訊分享),右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"啟用 (僅限媒體)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"支援音訊分享"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"左側啟用 (僅限媒體)"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"右側啟用 (僅限媒體)"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"左右側同時啟用 (僅限媒體)"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"媒體音訊"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"通話"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"檔案傳輸"</string> @@ -555,7 +544,7 @@      <string name="alarms_and_reminders_label" msgid="6918395649731424294">"鬧鐘與提醒"</string>      <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"允許設定鬧鐘和提醒"</string>      <string name="alarms_and_reminders_title" msgid="8819933264635406032">"鬧鐘和提醒"</string> -    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"允許這個應用程式設定鬧鐘及安排有時效性的動作。這麼做會讓用程式在背景執行,可能比較耗電。\n\n如果關閉這項權限,這個應用程式設定的現有鬧鐘將不會響起,而且應用程式也無法在預定的時間發出活動提醒。"</string> +    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"允許這個應用程式設定鬧鐘及安排有時效性的動作。之後應用程式可以在背景執行,並可能耗用較多電量。\n\n如果關閉這項權限,這個應用程式設定的現有鬧鐘將不會響起,系統也無法在預定的時間發出活動提醒。"</string>      <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"時間表, 鬧鐘, 提醒, 時鐘"</string>      <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"開啟"</string>      <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"開啟「零打擾」模式"</string> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index 6f06e1ffb391..d42202db2b73 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -106,28 +106,17 @@      <string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Iyasebenza, ngakwesokunxele kuphela"</string>      <string name="bluetooth_hearing_aid_right_active" msgid="8574683234077567230">"Iyasebenza, ngakwesokudla kuphela"</string>      <string name="bluetooth_hearing_aid_left_and_right_active" msgid="407704460573163973">"Iyasebenza, ngakwesokunxele nakwesokudla"</string> -    <!-- no translation found for bluetooth_active_media_only_battery_level (1164678961213251365) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_battery_level_untethered (1345174295097854560) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_lea_support (8580950145907305436) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_lea_support (8534816721698743015) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_left_lea_support (6605320955858788855) --> -    <skip /> -    <!-- no translation found for bluetooth_battery_level_untethered_right_lea_support (5717356160322149355) --> -    <skip /> -    <!-- no translation found for bluetooth_active_media_only_no_battery_level (71106861912593126) --> -    <skip /> -    <!-- no translation found for bluetooth_saved_device_lea_support (7231323139968285768) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_active (1632152540901488645) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_right_active (3854140683042617230) --> -    <skip /> -    <!-- no translation found for bluetooth_hearing_aid_media_only_left_and_right_active (1299913413062528417) --> -    <skip /> +    <string name="bluetooth_active_media_only_battery_level" msgid="1164678961213251365">"Ibhethri (imidiya kuphela), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> liyasebenza"</string> +    <string name="bluetooth_active_media_only_battery_level_untethered" msgid="1345174295097854560">"Liyasebenza (imidiya kuphela), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ibhethri, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ibhethri"</string> +    <string name="bluetooth_battery_level_lea_support" msgid="8580950145907305436">"Ixhunyiwe (isekela ukwabelana ngokuqoshiwe), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> webhethri"</string> +    <string name="bluetooth_battery_level_untethered_lea_support" msgid="8534816721698743015">"Ixhunyiwe (isekela ukwabelana ngokuqoshiwe), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> webhethri, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> webhethri"</string> +    <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="6605320955858788855">"Ixhunyiwe (isekela ukwabelana ngokuqoshiwe), ngakwesokunxele ngu-<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="5717356160322149355">"Ixhunyiwe (isekela ukwabelana ngokuqoshiwe), ngakwesokudla ngu-<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> +    <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Kuyasebenza (imidiya kuphela)"</string> +    <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Isekela ukwabelana ngokuqoshiwe"</string> +    <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Iyasebenza (imidiya kuphela), ngakwesokunxele kuphela"</string> +    <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Kuyasebenza (imidiya kuphela), ngakwesokudla kuphela"</string> +    <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Kuyasebenza (imidiya kuphela), ngakwesokunxele nakwesokudla"</string>      <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"Umsindo wemidiya"</string>      <string name="bluetooth_profile_headset" msgid="5395952236133499331">"Amakholi efoni"</string>      <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Dlulisa ifayela"</string> diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml index 2bd4d023cd72..ab049042b5f9 100644 --- a/packages/SettingsLib/res/values/dimens.xml +++ b/packages/SettingsLib/res/values/dimens.xml @@ -82,7 +82,6 @@      <dimen name="add_a_photo_circled_padding">6dp</dimen>      <dimen name="user_photo_size_in_user_info_dialog">112dp</dimen>      <dimen name="add_a_photo_icon_size_in_user_info_dialog">32dp</dimen> -    <dimen name="user_name_height_in_user_info_dialog">48sp</dimen>      <!-- Minimum increment between density scales. -->      <fraction name="display_density_min_scale_interval">9%</fraction> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 7e6b004be9b8..fbbed921de1d 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1148,6 +1148,16 @@      <!-- [CHAR_LIMIT=80] Label for battery charging future pause -->      <string name="power_charging_future_paused"><xliff:g id="level">%1$s</xliff:g> - Charging</string> +    <!-- [CHAR_LIMIT=40] Label for battery level when fast charging with duration. --> +    <string name="power_fast_charging_duration_v2"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="status">%2$s</xliff:g> - Full by <xliff:g id="time">%3$s</xliff:g></string> +    <!-- [CHAR_LIMIT=40] Label for battery level when non-fast charging with duration. --> +    <string name="power_charging_duration_v2"><xliff:g id="level">%1$s</xliff:g> - Fully charged by <xliff:g id="time">%2$s</xliff:g></string> + +    <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging. --> +    <string name="power_remaining_charging_duration_only_v2">Fully charged by <xliff:g id="time">%1$s</xliff:g></string> +    <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging. --> +    <string name="power_remaining_fast_charging_duration_only_v2">Full by <xliff:g id="time">%1$s</xliff:g></string> +      <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->      <string name="battery_info_status_unknown">Unknown</string>      <!-- [CHAR_LIMIT=20] Battery use screen.  Battery status shown in chart label when charging from an unknown source.  --> @@ -1171,6 +1181,11 @@      <!-- [CHAR_LIMIT=None] Battery Info screen. Value for a status item. A state which device charging on hold -->      <string name="battery_info_status_charging_on_hold">Charging on hold</string> +    <!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging isn't fast. --> +    <string name="battery_info_status_charging_v2">Charging</string> +    <!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging speed is fast. --> +    <string name="battery_info_status_charging_fast_v2">Fast charging</string> +      <!-- Summary for settings preference disabled by administrator [CHAR LIMIT=50] -->      <string name="disabled_by_admin_summary_text">Controlled by admin</string> @@ -1658,6 +1673,8 @@      <string name="accessibility_phone_two_bars">Phone two bars.</string>      <!-- Content description of the phone signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->      <string name="accessibility_phone_three_bars">Phone three bars.</string> +    <!-- Content description of the phone signal when it is four bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> +    <string name="accessibility_phone_four_bars">Phone four bars.</string>      <!-- Content description of the phone signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->      <string name="accessibility_phone_signal_full">Phone signal full.</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java b/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java index ce466dfbf19c..9073d281c4a9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java +++ b/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java @@ -33,6 +33,59 @@ public class AccessibilityContentDescriptions {          R.string.accessibility_phone_signal_full      }; +    /** +     * @param level int in range [0-4] that describes the signal level +     * @return the appropriate content description for that signal strength, or 0 if the param is +     *         invalid +     */ +    public static int getDescriptionForLevel(int level) { +        if (level > 4 || level < 0) { +            return 0; +        } + +        return PHONE_SIGNAL_STRENGTH[level]; +    } + +    public static final int[] PHONE_SIGNAL_STRENGTH_INFLATED = { +            PHONE_SIGNAL_STRENGTH_NONE, +            R.string.accessibility_phone_one_bar, +            R.string.accessibility_phone_two_bars, +            R.string.accessibility_phone_three_bars, +            R.string.accessibility_phone_four_bars, +            R.string.accessibility_phone_signal_full +    }; + +    /** +     * @param level int in range [0-5] that describes the inflated signal level +     * @return the appropriate content description for that signal strength, or 0 if the param is +     *         invalid +     */ +    public static int getDescriptionForInflatedLevel(int level) { +        if (level > 5 || level < 0) { +            return 0; +        } + +        return PHONE_SIGNAL_STRENGTH_INFLATED[level]; +    } + +    /** +     * @param level int in range [0-5] that describes the inflated signal level +     * @param numberOfLevels one of (4, 5) that describes the default number of levels, or the +     *                       inflated number of levels. The level param should be relative to the +     *                       number of levels. This won't do any inflation. +     * @return the appropriate content description for that signal strength, or 0 if the param is +     *         invalid +     */ +    public static int getDescriptionForLevel(int level, int numberOfLevels) { +        if (numberOfLevels == 5) { +            return getDescriptionForLevel(level); +        } else if (numberOfLevels == 6) { +            return getDescriptionForInflatedLevel(level); +        } else { +            return 0; +        } +    } +      public static final int[] DATA_CONNECTION_STRENGTH = {          R.string.accessibility_no_data,          R.string.accessibility_data_one_bar, diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index e95a506376fd..563f02d95f3c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -65,6 +65,7 @@ import com.android.launcher3.icons.IconFactory;  import com.android.launcher3.util.UserIconInfo;  import com.android.settingslib.drawable.UserIconDrawable;  import com.android.settingslib.fuelgauge.BatteryStatus; +import com.android.settingslib.fuelgauge.BatteryUtils;  import com.android.settingslib.utils.BuildCompatUtils;  import java.util.List; @@ -246,25 +247,23 @@ public class Utils {          } else {              if (status == BatteryManager.BATTERY_STATUS_CHARGING) {                  if (compactStatus) { -                    statusString = res.getString(R.string.battery_info_status_charging); +                    statusString = getRegularChargingStatusString(res);                  } else if (batteryStatus.isPluggedInWired()) {                      switch (batteryStatus.getChargingSpeed(context)) {                          case BatteryStatus.CHARGING_FAST: -                            statusString = -                                    res.getString(R.string.battery_info_status_charging_fast); +                            statusString = getFastChargingStatusString(res);                              break;                          case BatteryStatus.CHARGING_SLOWLY: -                            statusString = -                                    res.getString(R.string.battery_info_status_charging_slow); +                            statusString = getSlowChargingStatusString(res);                              break;                          default: -                            statusString = res.getString(R.string.battery_info_status_charging); +                            statusString = getRegularChargingStatusString(res);                              break;                      }                  } else if (batteryStatus.isPluggedInDock()) { -                    statusString = res.getString(R.string.battery_info_status_charging_dock); +                    statusString = getDockChargingStatusString(res);                  } else { -                    statusString = res.getString(R.string.battery_info_status_charging_wireless); +                    statusString = getWirelessChargingStatusString(res);                  }              } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {                  statusString = res.getString(R.string.battery_info_status_discharging); @@ -276,6 +275,41 @@ public class Utils {          return statusString;      } +    private static String getFastChargingStatusString(Resources res) { +        return res.getString( +                BatteryUtils.isChargingStringV2Enabled() +                        ? R.string.battery_info_status_charging_fast_v2 +                        : R.string.battery_info_status_charging_fast); +    } + +    private static String getSlowChargingStatusString(Resources res) { +        return res.getString( +                BatteryUtils.isChargingStringV2Enabled() +                        ? R.string.battery_info_status_charging_v2 +                        : R.string.battery_info_status_charging_slow); +    } + +    private static String getRegularChargingStatusString(Resources res) { +        return res.getString( +                BatteryUtils.isChargingStringV2Enabled() +                        ? R.string.battery_info_status_charging_v2 +                        : R.string.battery_info_status_charging); +    } + +    private static String getWirelessChargingStatusString(Resources res) { +        return res.getString( +                BatteryUtils.isChargingStringV2Enabled() +                        ? R.string.battery_info_status_charging_v2 +                        : R.string.battery_info_status_charging_wireless); +    } + +    private static String getDockChargingStatusString(Resources res) { +        return res.getString( +                BatteryUtils.isChargingStringV2Enabled() +                        ? R.string.battery_info_status_charging_v2 +                        : R.string.battery_info_status_charging_dock); +    } +      public static ColorStateList getColorAccent(Context context) {          return getColorAttr(context, android.R.attr.colorAccent);      } diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index 56118dae3f96..06c41cb7cbc7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -1993,6 +1993,40 @@ public class ApplicationsState {      };      /** +     * Displays a combined list with "downloaded" and "visible in launcher" apps which belong to a +     * user which is either not in quiet mode or allows showing apps even when in quiet mode. +     */ +    public static final AppFilter FILTER_DOWNLOADED_AND_LAUNCHER_NOT_QUIET = new AppFilter() { +        @Override +        public void init() { +        } + +        @Override +        public boolean filterApp(@NonNull AppEntry entry) { +            if (entry.hideInQuietMode) { +                return false; +            } +            if (AppUtils.isInstant(entry.info)) { +                return false; +            } else if (hasFlag(entry.info.flags, ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) { +                return true; +            } else if (!hasFlag(entry.info.flags, ApplicationInfo.FLAG_SYSTEM)) { +                return true; +            } else if (entry.hasLauncherEntry) { +                return true; +            } else if (hasFlag(entry.info.flags, ApplicationInfo.FLAG_SYSTEM) && entry.isHomeApp) { +                return true; +            } +            return false; +        } + +        @Override +        public void refreshAppEntryOnRebuild(@NonNull AppEntry appEntry, boolean hideInQuietMode) { +            appEntry.hideInQuietMode = hideInQuietMode; +        } +    }; + +    /**       * Displays a combined list with "downloaded" and "visible in launcher" apps only.       */      public static final AppFilter FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT = new AppFilter() { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java index 0996d52b0e30..e926b1684348 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java @@ -57,6 +57,7 @@ public class BluetoothEventManager {      private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);      private final LocalBluetoothAdapter mLocalAdapter; +    private final LocalBluetoothManager mBtManager;      private final CachedBluetoothDeviceManager mDeviceManager;      private final IntentFilter mAdapterIntentFilter, mProfileIntentFilter;      private final Map<String, Handler> mHandlerMap; @@ -80,10 +81,15 @@ public class BluetoothEventManager {       * userHandle passed in is {@code null}, we register event receiver for the       * {@code context.getUser()} handle.       */ -    BluetoothEventManager(LocalBluetoothAdapter adapter, -            CachedBluetoothDeviceManager deviceManager, Context context, -            android.os.Handler handler, @Nullable UserHandle userHandle) { +    BluetoothEventManager( +            LocalBluetoothAdapter adapter, +            LocalBluetoothManager btManager, +            CachedBluetoothDeviceManager deviceManager, +            Context context, +            android.os.Handler handler, +            @Nullable UserHandle userHandle) {          mLocalAdapter = adapter; +        mBtManager = btManager;          mDeviceManager = deviceManager;          mAdapterIntentFilter = new IntentFilter();          mProfileIntentFilter = new IntentFilter(); @@ -210,11 +216,27 @@ public class BluetoothEventManager {          }      } -    void dispatchProfileConnectionStateChanged(@NonNull CachedBluetoothDevice device, int state, -            int bluetoothProfile) { +    void dispatchProfileConnectionStateChanged( +            @NonNull CachedBluetoothDevice device, int state, int bluetoothProfile) {          for (BluetoothCallback callback : mCallbacks) {              callback.onProfileConnectionStateChanged(device, state, bluetoothProfile);          } + +        // Trigger updateFallbackActiveDeviceIfNeeded when ASSISTANT profile disconnected when +        // audio sharing is enabled. +        if (bluetoothProfile == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT +                && state == BluetoothAdapter.STATE_DISCONNECTED +                && BluetoothUtils.isAudioSharingEnabled()) { +            LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager(); +            if (profileManager != null +                    && profileManager.getLeAudioBroadcastProfile() != null +                    && profileManager.getLeAudioBroadcastProfile().isProfileReady() +                    && profileManager.getLeAudioBroadcastAssistantProfile() != null +                    && profileManager.getLeAudioBroadcastAssistantProfile().isProfileReady()) { +                Log.d(TAG, "updateFallbackActiveDeviceIfNeeded, ASSISTANT profile disconnected"); +                profileManager.getLeAudioBroadcastProfile().updateFallbackActiveDeviceIfNeeded(); +            } +        }      }      private void dispatchConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { @@ -536,7 +558,6 @@ public class BluetoothEventManager {                  default:                      Log.w(TAG, "ActiveDeviceChangedHandler: unknown action " + action);                      return; -              }              dispatchAclStateChanged(activeDevice, state);          } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 4777b0de0732..04516eba250e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -16,6 +16,8 @@  package com.android.settingslib.bluetooth; +import static com.android.settingslib.flags.Flags.enableSetPreferredTransportForLeAudioDevice; +  import android.annotation.CallbackExecutor;  import android.bluetooth.BluetoothAdapter;  import android.bluetooth.BluetoothClass; @@ -288,6 +290,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>                          mLocalNapRoleConnected = true;                      }                  } +                if (enableSetPreferredTransportForLeAudioDevice() +                        && profile instanceof HidProfile) { +                    updatePreferredTransport(); +                }              } else if (profile instanceof MapProfile                      && newProfileState == BluetoothProfile.STATE_DISCONNECTED) {                  profile.setEnabled(mDevice, false); @@ -300,12 +306,34 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>                  mLocalNapRoleConnected = false;              } +            if (enableSetPreferredTransportForLeAudioDevice() +                    && profile instanceof LeAudioProfile) { +                updatePreferredTransport(); +            } +              HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, this, profile, newProfileState);          }          fetchActiveDevices();      } +    private void updatePreferredTransport() { +        if (mProfiles.stream().noneMatch(p -> p instanceof LeAudioProfile) +                || mProfiles.stream().noneMatch(p -> p instanceof HidProfile)) { +            return; +        } +        // Both LeAudioProfile and HidProfile are connectable. +        if (!mProfileManager +                .getHidProfile() +                .setPreferredTransport( +                        mDevice, +                        mProfileManager.getLeAudioProfile().isEnabled(mDevice) +                                ? BluetoothDevice.TRANSPORT_LE +                                : BluetoothDevice.TRANSPORT_BREDR)) { +            Log.w(TAG, "Fail to set preferred transport"); +        } +    } +      @VisibleForTesting      void setProfileConnectedStatus(int profileId, boolean isFailed) {          switch (profileId) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java index 5b91ac9d3dab..b849d44622b2 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java @@ -27,6 +27,8 @@ import android.bluetooth.BluetoothProfile;  import android.content.Context;  import android.util.Log; +import androidx.annotation.NonNull; +  import com.android.settingslib.R;  import java.util.List; @@ -187,6 +189,14 @@ public class HidProfile implements LocalBluetoothProfile {          }      } +    /** Set preferred transport for the device */ +    public boolean setPreferredTransport(@NonNull BluetoothDevice device, int transport) { +        if (mService != null) { +            mService.setPreferredTransport(device, transport); +        } +        return false; +    } +      protected void finalize() {          Log.d(TAG, "finalize()");          if (mService != null) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java index 6c12cb7f1512..9df23aa2fe29 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java @@ -42,6 +42,7 @@ import android.net.Uri;  import android.os.Build;  import android.os.Handler;  import android.os.Looper; +import android.os.UserManager;  import android.provider.Settings;  import android.text.TextUtils;  import android.util.Log; @@ -336,7 +337,6 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {                                          + ", sourceId = "                                          + sourceId);                      } -                    updateFallbackActiveDeviceIfNeeded();                  }                  @Override @@ -468,6 +468,15 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {          mServiceBroadcast.startBroadcast(settings);      } +    /** Checks if the broadcast is playing. */ +    public boolean isPlaying(int broadcastId) { +        if (mServiceBroadcast == null) { +            Log.d(TAG, "check isPlaying failed, the BluetoothLeBroadcast is null."); +            return false; +        } +        return mServiceBroadcast.isPlaying(broadcastId); +    } +      private BluetoothLeBroadcastSettings buildBroadcastSettings(              boolean isPublic,              @Nullable String broadcastName, @@ -1025,6 +1034,16 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {      /** Update fallback active device if needed. */      public void updateFallbackActiveDeviceIfNeeded() { +        if (mServiceBroadcast == null) { +            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to broadcast profile is null"); +            return; +        } +        List<BluetoothLeBroadcastMetadata> sources = mServiceBroadcast.getAllBroadcastMetadata(); +        if (sources.stream() +                .noneMatch(source -> mServiceBroadcast.isPlaying(source.getBroadcastId()))) { +            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to no broadcast ongoing"); +            return; +        }          if (mServiceBroadcastAssistant == null) {              Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to assistant profile is null");              return; @@ -1117,10 +1136,19 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {              Log.d(TAG, "Skip notifyBroadcastStateChange, not triggered by Settings.");              return;          } +        if (isWorkProfile(mContext)) { +            Log.d(TAG, "Skip notifyBroadcastStateChange, not triggered for work profile."); +            return; +        }          Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);          intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, state);          intent.setPackage(mContext.getPackageName());          Log.e(TAG, "notifyBroadcastStateChange for state = " + state);          mContext.sendBroadcast(intent);      } + +    private boolean isWorkProfile(Context context) { +        UserManager userManager = context.getSystemService(UserManager.class); +        return userManager != null && userManager.isManagedProfile(); +    }  } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java index 53c6075ccff4..c4300d214c0c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java @@ -21,11 +21,11 @@ import android.os.Handler;  import android.os.UserHandle;  import android.util.Log; -import java.lang.ref.WeakReference; -  import androidx.annotation.Nullable;  import androidx.annotation.RequiresPermission; +import java.lang.ref.WeakReference; +  /**   * LocalBluetoothManager provides a simplified interface on top of a subset of   * the Bluetooth API. Note that {@link #getInstance} will return null @@ -111,10 +111,17 @@ public class LocalBluetoothManager {          mContext = context.getApplicationContext();          mLocalAdapter = adapter;          mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, this); -        mEventManager = new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, mContext, -                handler, userHandle); -        mProfileManager = new LocalBluetoothProfileManager(mContext, -                mLocalAdapter, mCachedDeviceManager, mEventManager); +        mEventManager = +                new BluetoothEventManager( +                        mLocalAdapter, +                        this, +                        mCachedDeviceManager, +                        mContext, +                        handler, +                        userHandle); +        mProfileManager = +                new LocalBluetoothProfileManager( +                        mContext, mLocalAdapter, mCachedDeviceManager, mEventManager);          mProfileManager.updateLocalProfiles();          mEventManager.readPairedDevices(); diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index 79e4c374667e..4055986e8a57 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -572,8 +572,7 @@ public class LocalBluetoothProfileManager {          return mSapProfile;      } -    @VisibleForTesting -    HidProfile getHidProfile() { +    public HidProfile getHidProfile() {          return mHidProfile;      } diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java index 92db50878a70..327e470e7d22 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java @@ -21,11 +21,14 @@ import android.content.ComponentName;  import android.content.Context;  import android.content.Intent;  import android.content.IntentFilter; -import android.provider.Settings; +import android.os.SystemProperties;  import android.os.UserManager; +import android.provider.Settings;  import android.util.ArraySet;  import android.view.accessibility.AccessibilityManager; +import androidx.annotation.VisibleForTesting; +  import java.util.List;  public final class BatteryUtils { @@ -33,6 +36,9 @@ public final class BatteryUtils {      /** The key to get the time to full from Settings.Global */      public static final String GLOBAL_TIME_TO_FULL_MILLIS = "time_to_full_millis"; +    /** The system property key to check whether the charging string v2 is enabled or not. */ +    public static final String PROPERTY_CHARGING_STRING_V2_KEY = "charging_string.apply_v2"; +      /** Gets the latest sticky battery intent from the Android system. */      public static Intent getBatteryIntent(Context context) {          return context.registerReceiver( @@ -75,4 +81,25 @@ public final class BatteryUtils {          final UserManager userManager = context.getSystemService(UserManager.class);          return userManager.isManagedProfile() && !userManager.isSystemUser();      } + +    private static Boolean sChargingStringV2Enabled = null; + +    /** Returns {@code true} if the charging string v2 is enabled. */ +    public static boolean isChargingStringV2Enabled() { +        if (sChargingStringV2Enabled == null) { +            sChargingStringV2Enabled = +                    SystemProperties.getBoolean(PROPERTY_CHARGING_STRING_V2_KEY, false); +        } +        return sChargingStringV2Enabled; +    } + + +    /** Used to override the system property to enable or reset for charging string V2. */ +    @VisibleForTesting +    public static void setChargingStringV2Enabled(Boolean enabled) { +        SystemProperties.set( +                BatteryUtils.PROPERTY_CHARGING_STRING_V2_KEY, +                enabled == null ? "" : String.valueOf(enabled)); +        BatteryUtils.sChargingStringV2Enabled = enabled; +    }  } diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java index b015b2bce60a..46f229035839 100644 --- a/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java +++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java @@ -184,7 +184,7 @@ public class EditUserInfoController {          dialogHelper                  .setTitle(R.string.user_info_settings_title)                  .addCustomView(content) -                .setPositiveButton(android.R.string.ok, view -> { +                .setPositiveButton(R.string.okay, view -> {                      Drawable newUserIcon = mEditUserPhotoController != null                              ? mEditUserPhotoController.getNewUserPhotoDrawable()                              : null; @@ -201,7 +201,7 @@ public class EditUserInfoController {                      }                      dialogHelper.getDialog().dismiss();                  }) -                .setBackButton(android.R.string.cancel, view -> { +                .setBackButton(R.string.cancel, view -> {                      clear();                      if (cancelCallback != null) {                          cancelCallback.run(); diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java index 22726549ce05..5ed59996bee3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java @@ -33,7 +33,7 @@ import java.util.Date;  import java.util.Locale;  import java.util.concurrent.TimeUnit; -/** Utility class for keeping power related strings consistent**/ +/** Utility class for keeping power related strings consistent. **/  public class PowerUtil {      private static final long SEVEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(7); @@ -221,4 +221,19 @@ public class PowerUtil {              return time - remainder + multiple;          }      } + +    /** Gets the rounded target time string in a short format. */ +    public static String getTargetTimeShortString( +            Context context, long targetTimeOffsetMs, long currentTimeMs) { +        final long roundedTimeOfDayMs = +                roundTimeToNearestThreshold( +                        currentTimeMs + targetTimeOffsetMs, FIFTEEN_MINUTES_MILLIS); + +        // convert the time to a properly formatted string. +        String skeleton = android.text.format.DateFormat.getTimeFormatString(context); +        DateFormat fmt = DateFormat.getInstanceForSkeleton(skeleton); +        Date date = Date.from(Instant.ofEpochMilli(roundedTimeOfDayMs)); +        return fmt.format(date); +    }  } + diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java index b9748883b25d..fef05612a8cb 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java @@ -240,6 +240,56 @@ public class ApplicationsStateTest {      }      @Test +    public void testDownloadAndLauncherNotInQuietAcceptsCorrectApps() { +        mEntry.isHomeApp = false; +        mEntry.hasLauncherEntry = false; + +        // should include updated system apps +        when(mEntry.info.isInstantApp()).thenReturn(false); +        mEntry.info.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; +        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_NOT_QUIET.filterApp(mEntry)) +                .isTrue(); + +        // should not include system apps other than the home app +        mEntry.info.flags = ApplicationInfo.FLAG_SYSTEM; +        mEntry.isHomeApp = false; +        mEntry.hasLauncherEntry = false; +        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_NOT_QUIET.filterApp(mEntry)) +                .isFalse(); + +        // should include the home app +        mEntry.isHomeApp = true; +        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_NOT_QUIET.filterApp(mEntry)) +                .isTrue(); + +        // should include any System app with a launcher entry +        mEntry.isHomeApp = false; +        mEntry.hasLauncherEntry = true; +        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_NOT_QUIET.filterApp(mEntry)) +                .isTrue(); + +        // should not include updated system apps when in quiet mode +        when(mEntry.info.isInstantApp()).thenReturn(false); +        mEntry.info.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; +        mEntry.hideInQuietMode = true; +        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_NOT_QUIET.filterApp(mEntry)) +                .isFalse(); + +        // should not include the home app when in quiet mode +        mEntry.isHomeApp = true; +        mEntry.hideInQuietMode = true; +        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_NOT_QUIET.filterApp(mEntry)) +                .isFalse(); + +        // should not include any System app with a launcher entry when in quiet mode +        mEntry.isHomeApp = false; +        mEntry.hasLauncherEntry = true; +        mEntry.hideInQuietMode = true; +        assertThat(ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_NOT_QUIET.filterApp(mEntry)) +                .isFalse(); +    } + +    @Test      public void testOtherAppsRejectsLegacyGame() {          mEntry.info.flags = ApplicationInfo.FLAG_IS_GAME; diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java index 50f5b9d81000..69f6305fa1b2 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/bluetooth/BluetoothEventManagerIntegTest.java @@ -20,6 +20,8 @@ import static org.junit.Assert.assertTrue;  import static org.junit.Assert.fail;  import static org.mockito.Mockito.mock; +import static java.util.concurrent.TimeUnit.SECONDS; +  import android.app.ActivityManager;  import android.content.Context;  import android.content.Intent; @@ -37,13 +39,11 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith; -import static java.util.concurrent.TimeUnit.SECONDS; -  import java.util.concurrent.CountDownLatch;  /** - * Test that verifies that BluetoothEventManager can receive broadcasts for non-current - * users for all bluetooth events. + * Test that verifies that BluetoothEventManager can receive broadcasts for non-current users for + * all bluetooth events.   *   * <p>Creation and deletion of users takes a long time, so marking this as a LargeTest.   */ @@ -64,9 +64,14 @@ public class BluetoothEventManagerIntegTest {          mContext = InstrumentationRegistry.getTargetContext();          mUserManager = UserManager.get(mContext); -        mBluetoothEventManager = new BluetoothEventManager( -                mock(LocalBluetoothAdapter.class), mock(CachedBluetoothDeviceManager.class), -                mContext, /* handler= */ null, UserHandle.ALL); +        mBluetoothEventManager = +                new BluetoothEventManager( +                        mock(LocalBluetoothAdapter.class), +                        mock(LocalBluetoothManager.class), +                        mock(CachedBluetoothDeviceManager.class), +                        mContext, +                        /* handler= */ null, +                        UserHandle.ALL);          // Create and start another user in the background.          mOtherUser = mUserManager.createUser("TestUser", /* flags= */ 0); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java index 48bbf4ea6a65..b1489be943e6 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java @@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.anyInt;  import static org.mockito.ArgumentMatchers.eq;  import static org.mockito.Mockito.mock;  import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times;  import static org.mockito.Mockito.verify;  import static org.mockito.Mockito.when; @@ -29,35 +30,47 @@ import android.bluetooth.BluetoothAdapter;  import android.bluetooth.BluetoothDevice;  import android.bluetooth.BluetoothHeadset;  import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothStatusCodes;  import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.Intent;  import android.content.IntentFilter;  import android.os.UserHandle; +import android.platform.test.flag.junit.SetFlagsRule;  import android.telephony.TelephonyManager;  import com.android.settingslib.R; +import com.android.settingslib.flags.Flags; +import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;  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;  import org.robolectric.RobolectricTestRunner;  import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow;  import java.util.ArrayList;  import java.util.Collections;  import java.util.List;  @RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothAdapter.class})  public class BluetoothEventManagerTest { +    @Rule +    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();      private static final String DEVICE_NAME = "test_device_name";      @Mock      private LocalBluetoothAdapter mLocalAdapter;      @Mock +    private LocalBluetoothManager mBtManager; +    @Mock      private CachedBluetoothDeviceManager mCachedDeviceManager;      @Mock      private BluetoothCallback mBluetoothCallback; @@ -96,8 +109,15 @@ public class BluetoothEventManagerTest {          MockitoAnnotations.initMocks(this);          mContext = RuntimeEnvironment.application; -        mBluetoothEventManager = new BluetoothEventManager(mLocalAdapter, -                mCachedDeviceManager, mContext, /* handler= */ null, /* userHandle= */ null); +        mBluetoothEventManager = +                new BluetoothEventManager( +                        mLocalAdapter, +                        mBtManager, +                        mCachedDeviceManager, +                        mContext, +                        /* handler= */ null, +                        /* userHandle= */ null); +        when(mBtManager.getProfileManager()).thenReturn(mLocalProfileManager);          when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);          when(mHfpProfile.isProfileReady()).thenReturn(true);          when(mA2dpProfile.isProfileReady()).thenReturn(true); @@ -113,8 +133,13 @@ public class BluetoothEventManagerTest {      public void ifUserHandleIsNull_registerReceiverIsCalled() {          Context mockContext = mock(Context.class);          BluetoothEventManager eventManager = -                new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, mockContext, -                        /* handler= */ null, /* userHandle= */ null); +                new BluetoothEventManager( +                        mLocalAdapter, +                        mBtManager, +                        mCachedDeviceManager, +                        mockContext, +                        /* handler= */ null, +                        /* userHandle= */ null);          verify(mockContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class),                  eq(null), eq(null), eq(Context.RECEIVER_EXPORTED)); @@ -124,8 +149,13 @@ public class BluetoothEventManagerTest {      public void ifUserHandleSpecified_registerReceiverAsUserIsCalled() {          Context mockContext = mock(Context.class);          BluetoothEventManager eventManager = -                new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, mockContext, -                        /* handler= */ null, UserHandle.ALL); +                new BluetoothEventManager( +                        mLocalAdapter, +                        mBtManager, +                        mCachedDeviceManager, +                        mockContext, +                        /* handler= */ null, +                        UserHandle.ALL);          verify(mockContext).registerReceiverAsUser(any(BroadcastReceiver.class), eq(UserHandle.ALL),                  any(IntentFilter.class), eq(null), eq(null), eq(Context.RECEIVER_EXPORTED)); @@ -172,6 +202,160 @@ public class BluetoothEventManagerTest {                  BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP);      } +    /** +     * dispatchProfileConnectionStateChanged should not call {@link +     * LocalBluetoothLeBroadcast}#updateFallbackActiveDeviceIfNeeded when audio sharing flag is off. +     */ +    @Test +    public void dispatchProfileConnectionStateChanged_flagOff_noUpdateFallbackDevice() { +        ShadowBluetoothAdapter shadowBluetoothAdapter = +                Shadow.extract(BluetoothAdapter.getDefaultAdapter()); +        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported( +                BluetoothStatusCodes.FEATURE_SUPPORTED); +        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported( +                BluetoothStatusCodes.FEATURE_SUPPORTED); +        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); +        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class); +        when(broadcast.isProfileReady()).thenReturn(true); +        LocalBluetoothLeBroadcastAssistant assistant = +                mock(LocalBluetoothLeBroadcastAssistant.class); +        when(assistant.isProfileReady()).thenReturn(true); +        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class); +        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast); +        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant); +        when(mBtManager.getProfileManager()).thenReturn(profileManager); +        mBluetoothEventManager.dispatchProfileConnectionStateChanged( +                mCachedBluetoothDevice, +                BluetoothProfile.STATE_DISCONNECTED, +                BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT); + +        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded(); +    } + +    /** +     * dispatchProfileConnectionStateChanged should not call {@link +     * LocalBluetoothLeBroadcast}#updateFallbackActiveDeviceIfNeeded when the device does not +     * support audio sharing. +     */ +    @Test +    public void dispatchProfileConnectionStateChanged_notSupport_noUpdateFallbackDevice() { +        ShadowBluetoothAdapter shadowBluetoothAdapter = +                Shadow.extract(BluetoothAdapter.getDefaultAdapter()); +        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported( +                BluetoothStatusCodes.FEATURE_NOT_SUPPORTED); +        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported( +                BluetoothStatusCodes.FEATURE_SUPPORTED); +        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); +        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class); +        when(broadcast.isProfileReady()).thenReturn(true); +        LocalBluetoothLeBroadcastAssistant assistant = +                mock(LocalBluetoothLeBroadcastAssistant.class); +        when(assistant.isProfileReady()).thenReturn(true); +        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class); +        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast); +        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant); +        when(mBtManager.getProfileManager()).thenReturn(profileManager); +        mBluetoothEventManager.dispatchProfileConnectionStateChanged( +                mCachedBluetoothDevice, +                BluetoothProfile.STATE_DISCONNECTED, +                BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT); + +        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded(); +    } + +    /** +     * dispatchProfileConnectionStateChanged should not call {@link +     * LocalBluetoothLeBroadcast}#updateFallbackActiveDeviceIfNeeded when audio sharing profile is +     * not ready. +     */ +    @Test +    public void dispatchProfileConnectionStateChanged_profileNotReady_noUpdateFallbackDevice() { +        ShadowBluetoothAdapter shadowBluetoothAdapter = +                Shadow.extract(BluetoothAdapter.getDefaultAdapter()); +        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported( +                BluetoothStatusCodes.FEATURE_SUPPORTED); +        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported( +                BluetoothStatusCodes.FEATURE_SUPPORTED); +        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); +        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class); +        when(broadcast.isProfileReady()).thenReturn(false); +        LocalBluetoothLeBroadcastAssistant assistant = +                mock(LocalBluetoothLeBroadcastAssistant.class); +        when(assistant.isProfileReady()).thenReturn(true); +        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class); +        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast); +        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant); +        when(mBtManager.getProfileManager()).thenReturn(profileManager); +        mBluetoothEventManager.dispatchProfileConnectionStateChanged( +                mCachedBluetoothDevice, +                BluetoothProfile.STATE_DISCONNECTED, +                BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT); + +        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded(); +    } + +    /** +     * dispatchProfileConnectionStateChanged should not call {@link +     * LocalBluetoothLeBroadcast}#updateFallbackActiveDeviceIfNeeded when triggered for profile +     * other than LE_AUDIO_BROADCAST_ASSISTANT or state other than STATE_DISCONNECTED. +     */ +    @Test +    public void dispatchProfileConnectionStateChanged_notAssistantProfile_noUpdateFallbackDevice() { +        ShadowBluetoothAdapter shadowBluetoothAdapter = +                Shadow.extract(BluetoothAdapter.getDefaultAdapter()); +        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported( +                BluetoothStatusCodes.FEATURE_SUPPORTED); +        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported( +                BluetoothStatusCodes.FEATURE_SUPPORTED); +        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); +        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class); +        when(broadcast.isProfileReady()).thenReturn(true); +        LocalBluetoothLeBroadcastAssistant assistant = +                mock(LocalBluetoothLeBroadcastAssistant.class); +        when(assistant.isProfileReady()).thenReturn(true); +        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class); +        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast); +        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant); +        when(mBtManager.getProfileManager()).thenReturn(profileManager); +        mBluetoothEventManager.dispatchProfileConnectionStateChanged( +                mCachedBluetoothDevice, +                BluetoothProfile.STATE_DISCONNECTED, +                BluetoothProfile.LE_AUDIO); + +        verify(broadcast, times(0)).updateFallbackActiveDeviceIfNeeded(); +    } + +    /** +     * dispatchProfileConnectionStateChanged should call {@link +     * LocalBluetoothLeBroadcast}#updateFallbackActiveDeviceIfNeeded when assistant profile is +     * disconnected and audio sharing is enabled. +     */ +    @Test +    public void dispatchProfileConnectionStateChanged_audioSharing_updateFallbackDevice() { +        ShadowBluetoothAdapter shadowBluetoothAdapter = +                Shadow.extract(BluetoothAdapter.getDefaultAdapter()); +        shadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported( +                BluetoothStatusCodes.FEATURE_SUPPORTED); +        shadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported( +                BluetoothStatusCodes.FEATURE_SUPPORTED); +        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); +        LocalBluetoothLeBroadcast broadcast = mock(LocalBluetoothLeBroadcast.class); +        when(broadcast.isProfileReady()).thenReturn(true); +        LocalBluetoothLeBroadcastAssistant assistant = +                mock(LocalBluetoothLeBroadcastAssistant.class); +        when(assistant.isProfileReady()).thenReturn(true); +        LocalBluetoothProfileManager profileManager = mock(LocalBluetoothProfileManager.class); +        when(profileManager.getLeAudioBroadcastProfile()).thenReturn(broadcast); +        when(profileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(assistant); +        when(mBtManager.getProfileManager()).thenReturn(profileManager); +        mBluetoothEventManager.dispatchProfileConnectionStateChanged( +                mCachedBluetoothDevice, +                BluetoothProfile.STATE_DISCONNECTED, +                BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT); + +        verify(broadcast).updateFallbackActiveDeviceIfNeeded(); +    } +      @Test      public void dispatchAclConnectionStateChanged_aclDisconnected_shouldDispatchCallback() {          mBluetoothEventManager.registerCallback(mBluetoothCallback); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java index 5996dbb322fc..646e9ebd4f09 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java @@ -15,6 +15,8 @@   */  package com.android.settingslib.bluetooth; +import static com.android.settingslib.flags.Flags.FLAG_ENABLE_SET_PREFERRED_TRANSPORT_FOR_LE_AUDIO_DEVICE; +  import static com.google.common.truth.Truth.assertThat;  import static org.mockito.ArgumentMatchers.any; @@ -86,6 +88,9 @@ public class CachedBluetoothDeviceTest {      private HapClientProfile mHapClientProfile;      @Mock      private LeAudioProfile mLeAudioProfile; + +    @Mock +    private HidProfile mHidProfile;      @Mock      private BluetoothDevice mDevice;      @Mock @@ -104,6 +109,7 @@ public class CachedBluetoothDeviceTest {      public void setUp() {          MockitoAnnotations.initMocks(this);          mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TV_MEDIA_OUTPUT_DIALOG); +        mSetFlagsRule.enableFlags(FLAG_ENABLE_SET_PREFERRED_TRANSPORT_FOR_LE_AUDIO_DEVICE);          mContext = RuntimeEnvironment.application;          mAudioManager = mContext.getSystemService(AudioManager.class);          mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); @@ -118,6 +124,8 @@ public class CachedBluetoothDeviceTest {          when(mHearingAidProfile.getProfileId()).thenReturn(BluetoothProfile.HEARING_AID);          when(mLeAudioProfile.isProfileReady()).thenReturn(true);          when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO); +        when(mHidProfile.isProfileReady()).thenReturn(true); +        when(mHidProfile.getProfileId()).thenReturn(BluetoothProfile.HID_HOST);          mCachedDevice = spy(new CachedBluetoothDevice(mContext, mProfileManager, mDevice));          mSubCachedDevice = spy(new CachedBluetoothDevice(mContext, mProfileManager, mSubDevice));          doAnswer((invocation) -> mBatteryLevel).when(mCachedDevice).getBatteryLevel(); @@ -1819,6 +1827,32 @@ public class CachedBluetoothDeviceTest {          assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse();      } +    @Test +    public void leAudioHidDevice_leAudioEnabled_setPreferredTransportToLE() { + +        when(mProfileManager.getHidProfile()).thenReturn(mHidProfile); +        when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile); +        when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true); + +        updateProfileStatus(mHidProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED); + +        verify(mHidProfile).setPreferredTransport(mDevice, BluetoothDevice.TRANSPORT_LE); +    } + +    @Test +    public void leAudioHidDevice_leAudioDisabled_setPreferredTransportToBredr() { +        when(mProfileManager.getHidProfile()).thenReturn(mHidProfile); +        when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile); +        when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(false); + +        updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED); +        updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_DISCONNECTED); +        updateProfileStatus(mHidProfile, BluetoothProfile.STATE_CONNECTED); + +        verify(mHidProfile).setPreferredTransport(mDevice, BluetoothDevice.TRANSPORT_BREDR); +    } +      private HearingAidInfo getLeftAshaHearingAidInfo() {          return new HearingAidInfo.Builder()                  .setAshaDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT) diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java index 4f8fa2fdb96e..cef083584744 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java @@ -56,7 +56,8 @@ import java.util.List;  @Config(shadows = {ShadowBluetoothAdapter.class})  public class LocalBluetoothProfileManagerTest {      private final static long HISYNCID = 10; - +    @Mock +    private LocalBluetoothManager mBtManager;      @Mock      private CachedBluetoothDeviceManager mDeviceManager;      @Mock @@ -77,13 +78,21 @@ public class LocalBluetoothProfileManagerTest {          MockitoAnnotations.initMocks(this);          mContext = spy(RuntimeEnvironment.application);          mLocalBluetoothAdapter = LocalBluetoothAdapter.getInstance(); -        mEventManager = spy(new BluetoothEventManager(mLocalBluetoothAdapter, mDeviceManager, -                mContext, /* handler= */ null, /* userHandle= */ null)); +        mEventManager = +                spy( +                        new BluetoothEventManager( +                                mLocalBluetoothAdapter, +                                mBtManager, +                                mDeviceManager, +                                mContext, +                                /* handler= */ null, +                                /* userHandle= */ null));          mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());          when(mDeviceManager.findDevice(mDevice)).thenReturn(mCachedBluetoothDevice);          when(mCachedBluetoothDevice.getDevice()).thenReturn(mDevice); -        mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, -                mDeviceManager, mEventManager); +        mProfileManager = +                new LocalBluetoothProfileManager( +                        mContext, mLocalBluetoothAdapter, mDeviceManager, mEventManager);      }      /** diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java index 2e7905f2e1e4..cbc382b6b920 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java @@ -20,30 +20,24 @@ import static com.google.common.truth.Truth.assertThat;  import static org.mockito.Mockito.spy; +import android.app.AlarmManager;  import android.content.Context; +import androidx.test.core.app.ApplicationProvider; +  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.mockito.MockitoAnnotations;  import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment;  import java.time.Duration; +import java.time.Instant; +import java.util.Locale;  import java.util.regex.Pattern;  @RunWith(RobolectricTestRunner.class)  public class PowerUtilTest { -    private static final String TEST_BATTERY_LEVEL_10 = "10%"; -    private static final long TEN_SEC_MILLIS = Duration.ofSeconds(10).toMillis(); -    private static final long SEVENTEEN_MIN_MILLIS = Duration.ofMinutes(17).toMillis(); -    private static final long FIVE_MINUTES_MILLIS = Duration.ofMinutes(5).toMillis(); -    private static final long TEN_MINUTES_MILLIS = Duration.ofMinutes(10).toMillis(); -    private static final long THREE_DAYS_MILLIS = Duration.ofDays(3).toMillis(); -    private static final long TEN_HOURS_MILLIS = Duration.ofHours(10).toMillis(); -    private static final long THIRTY_HOURS_MILLIS = Duration.ofHours(30).toMillis(); -    private static final String NORMAL_CASE_EXPECTED_PREFIX = "Should last until about"; -    private static final String ENHANCED_SUFFIX = " based on your usage";      private static final String BATTERY_RUN_OUT_PREFIX = "Battery may run out by";      // matches a time (ex: '1:15 PM', '2 AM', '23:00')      private static final String TIME_OF_DAY_REGEX = " (\\d)+:?(\\d)* ((AM)*)|((PM)*)"; @@ -55,29 +49,31 @@ public class PowerUtilTest {      @Before      public void setup() {          MockitoAnnotations.initMocks(this); -        mContext = spy(RuntimeEnvironment.application); +        mContext = spy(ApplicationProvider.getApplicationContext());      }      @Test      public void getBatteryTipStringFormatted_moreThanOneDay_usesCorrectString() { -        String info = PowerUtil.getBatteryTipStringFormatted(mContext, -                THREE_DAYS_MILLIS); +        var threeDayMillis = Duration.ofDays(3).toMillis(); + +        String batteryTipString = PowerUtil.getBatteryTipStringFormatted(mContext, threeDayMillis); -        assertThat(info).isEqualTo("More than 3 days left"); +        assertThat(batteryTipString).isEqualTo("More than 3 days left");      }      @Test      public void getBatteryTipStringFormatted_lessThanOneDay_usesCorrectString() { -        String info = PowerUtil.getBatteryTipStringFormatted(mContext, -                SEVENTEEN_MIN_MILLIS); +        var drainTimeMs = Duration.ofMinutes(17).toMillis(); + +        String batteryTipString = PowerUtil.getBatteryTipStringFormatted(mContext, drainTimeMs);          // ex: Battery may run out by 1:15 PM -        assertThat(info).containsMatch(Pattern.compile( -                BATTERY_RUN_OUT_PREFIX + TIME_OF_DAY_REGEX)); +        assertThat(batteryTipString) +                .containsMatch(Pattern.compile(BATTERY_RUN_OUT_PREFIX + TIME_OF_DAY_REGEX));      }      @Test -    public void testRoundToNearestThreshold_roundsCorrectly() { +    public void roundTimeToNearestThreshold_roundsCorrectly() {          // test some pretty normal values          assertThat(PowerUtil.roundTimeToNearestThreshold(1200, 1000)).isEqualTo(1000);          assertThat(PowerUtil.roundTimeToNearestThreshold(800, 1000)).isEqualTo(1000); @@ -89,4 +85,17 @@ public class PowerUtilTest {          assertThat(PowerUtil.roundTimeToNearestThreshold(-120, 100)).isEqualTo(100);          assertThat(PowerUtil.roundTimeToNearestThreshold(-200, -75)).isEqualTo(225);      } + +    @Test +    public void getTargetTimeShortString_returnsTimeShortString() { +        mContext.getSystemService(AlarmManager.class).setTimeZone("UTC"); +        mContext.getResources().getConfiguration().setLocale(Locale.US); +        var currentTimeMs = Instant.parse("2024-06-06T15:00:00Z").toEpochMilli(); +        var remainingTimeMs = Duration.ofMinutes(30).toMillis(); + +        var actualTimeString = +                PowerUtil.getTargetTimeShortString(mContext, remainingTimeMs, currentTimeMs); + +        assertThat(actualTimeString).isEqualTo("3:30 PM"); +    }  } diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java index c7e96bcdb856..00e47729a796 100644 --- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java +++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowBluetoothAdapter.java @@ -38,6 +38,8 @@ public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBlueto      private List<BluetoothDevice> mMostRecentlyConnectedDevices;      private BluetoothProfile.ServiceListener mServiceListener;      private ParcelUuid[] mParcelUuids; +    private int mIsLeAudioBroadcastSourceSupported; +    private int mIsLeAudioBroadcastAssistantSupported;      @Implementation      protected boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, @@ -97,4 +99,22 @@ public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBlueto      public void setUuids(ParcelUuid[] uuids) {          mParcelUuids = uuids;      } + +    @Implementation +    protected int isLeAudioBroadcastSourceSupported() { +        return mIsLeAudioBroadcastSourceSupported; +    } + +    public void setIsLeAudioBroadcastSourceSupported(int isSupported) { +        mIsLeAudioBroadcastSourceSupported = isSupported; +    } + +    @Implementation +    protected int isLeAudioBroadcastAssistantSupported() { +        return mIsLeAudioBroadcastAssistantSupported; +    } + +    public void setIsLeAudioBroadcastAssistantSupported(int isSupported) { +        mIsLeAudioBroadcastAssistantSupported = isSupported; +    }  } diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 17d9f1b87fac..097840ead0d3 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -338,4 +338,7 @@      <!-- Value to use as default scale for fonts -->      <item name="def_device_font_scale" format="float" type="dimen">1.0</item> + +    <!-- The default ringer mode. See `AudioManager` for list of valid values. --> +    <integer name="def_ringer_mode">2</integer>  </resources> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 1ead14ab6f4c..096cccc1f94a 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -3943,8 +3943,10 @@ public class SettingsProvider extends ContentProvider {                          globalSettings.updateSettingLocked(Settings.Global.ZEN_MODE,                                  Integer.toString(Settings.Global.ZEN_MODE_OFF), null,                                  true, SettingsState.SYSTEM_PACKAGE_NAME); +                        final int defaultRingerMode = +                                getContext().getResources().getInteger(R.integer.def_ringer_mode);                          globalSettings.updateSettingLocked(Settings.Global.MODE_RINGER, -                                Integer.toString(AudioManager.RINGER_MODE_NORMAL), null, +                                Integer.toString(defaultRingerMode), null,                                  true, SettingsState.SYSTEM_PACKAGE_NAME);                      }                      currentVersion = 119; diff --git a/packages/Shell/res/values-af/strings.xml b/packages/Shell/res/values-af/strings.xml index b52a83c2fd54..90f0962867f7 100644 --- a/packages/Shell/res/values-af/strings.xml +++ b/packages/Shell/res/values-af/strings.xml @@ -35,7 +35,7 @@      <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Kon nie foutverslagbesonderhede by ZIP-lêer voeg nie"</string>      <string name="bugreport_unnamed" msgid="2800582406842092709">"naamloos"</string>      <string name="bugreport_info_action" msgid="2158204228510576227">"Besonderhede"</string> -    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skermkiekie"</string> +    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skermskoot"</string>      <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Skermkiekie is suksesvol geneem."</string>      <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kon nie skermkiekie neem nie."</string>      <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Foutverslag <xliff:g id="ID">#%d</xliff:g> se besonderhede"</string> diff --git a/packages/SimAppDialog/res/values-pt-rBR/strings.xml b/packages/SimAppDialog/res/values-pt-rBR/strings.xml index abf8dbd27ecc..fe31aa0d8b37 100644 --- a/packages/SimAppDialog/res/values-pt-rBR/strings.xml +++ b/packages/SimAppDialog/res/values-pt-rBR/strings.xml @@ -22,5 +22,5 @@      <string name="install_carrier_app_description" msgid="4014303558674923797">"Para que o novo chip funcione corretamente, instale o app <xliff:g id="ID_1">%1$s</xliff:g>"</string>      <string name="install_carrier_app_description_default" msgid="7356830245205847840">"Para que o novo chip funcione corretamente, instale o app da operadora"</string>      <string name="install_carrier_app_defer_action" msgid="2558576736886876209">"Agora não"</string> -    <string name="install_carrier_app_download_action" msgid="7859229305958538064">"Fazer o download do app"</string> +    <string name="install_carrier_app_download_action" msgid="7859229305958538064">"Baixar o app"</string>  </resources> diff --git a/packages/SimAppDialog/res/values-pt/strings.xml b/packages/SimAppDialog/res/values-pt/strings.xml index abf8dbd27ecc..fe31aa0d8b37 100644 --- a/packages/SimAppDialog/res/values-pt/strings.xml +++ b/packages/SimAppDialog/res/values-pt/strings.xml @@ -22,5 +22,5 @@      <string name="install_carrier_app_description" msgid="4014303558674923797">"Para que o novo chip funcione corretamente, instale o app <xliff:g id="ID_1">%1$s</xliff:g>"</string>      <string name="install_carrier_app_description_default" msgid="7356830245205847840">"Para que o novo chip funcione corretamente, instale o app da operadora"</string>      <string name="install_carrier_app_defer_action" msgid="2558576736886876209">"Agora não"</string> -    <string name="install_carrier_app_download_action" msgid="7859229305958538064">"Fazer o download do app"</string> +    <string name="install_carrier_app_download_action" msgid="7859229305958538064">"Baixar o app"</string>  </resources> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-af/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-af/strings.xml index cbb5ad732b2b..56fd06c71366 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-af/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-af/strings.xml @@ -12,7 +12,7 @@      <string name="lockscreen_label" msgid="648347953557887087">"Sluitskerm"</string>      <string name="quick_settings_label" msgid="2999117381487601865">"Kitsinstellings"</string>      <string name="notifications_label" msgid="6829741046963013567">"Kennisgewings"</string> -    <string name="screenshot_label" msgid="863978141223970162">"Skermkiekie"</string> +    <string name="screenshot_label" msgid="863978141223970162">"Skermskoot"</string>      <string name="screenshot_utterance" msgid="1430760563401895074">"Neem skermkiekie"</string>      <string name="volume_up_label" msgid="8592766918780362870">"Volume harder"</string>      <string name="volume_down_label" msgid="8574981863656447346">"Volume sagter"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fi/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fi/strings.xml index 5e317394cb31..8f2abaccbdd7 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-fi/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-fi/strings.xml @@ -21,7 +21,7 @@      <string name="previous_button_content_description" msgid="840869171117765966">"Siirry edelliselle näytöllä"</string>      <string name="next_button_content_description" msgid="6810058269847364406">"Siirry seuraavalle näytölle"</string>      <string name="accessibility_menu_description" msgid="4458354794093858297">"Saavutettavuusvalikko on suuri näyttövalikko, josta voit ohjata laitettasi. Voit esimerkiksi lukita laitteen, säätää äänenvoimakkuutta ja kirkkautta sekä ottaa kuvakaappauksia."</string> -    <string name="accessibility_menu_summary" msgid="340071398148208130">"Ohjaa laitetta suurella valikolla"</string> +    <string name="accessibility_menu_summary" msgid="340071398148208130">"Ohjaa laitetta suuren valikon avulla"</string>      <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Saavutettavuusvalikon asetukset"</string>      <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Suuret painikkeet"</string>      <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Suurenna saavutettavuusvalikon painikkeita"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml index 1cb9b5e3a73d..3d59c0b62ac4 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-hi/strings.xml @@ -2,7 +2,7 @@  <resources xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">      <string name="accessibility_menu_service_name" msgid="730136711554740131">"सुलभता मेन्यू"</string> -    <string name="accessibility_menu_intro" msgid="3164193281544042394">"सुलभता मेन्यू, स्क्रीन पर दिखने वाला एक बड़ा मेन्यू होता है. इसकी मदद से, अपने डिवाइस को कंट्रोल किया जा सकता है. इस मेन्यू में जाकर, अपना डिवाइस लॉक करने, स्क्रीनशॉट लेने, स्क्रीन की रोशनी और आवाज़ कंट्रोल करने जैसे कई दूसरे काम किए जा सकते हैं."</string> +    <string name="accessibility_menu_intro" msgid="3164193281544042394">"सुलभता मेन्यू, डिवाइस की स्क्रीन पर दिखने वाला एक बड़ा मेन्यू होता है. इस मेन्यू में जाकर, डिवाइस को लॉक करने, स्क्रीनशॉट लेने, स्क्रीन की रोशनी और आवाज़ को कंट्रोल करने जैसे कई काम किए जा सकते हैं."</string>      <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string>      <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string>      <string name="a11y_settings_label" msgid="3977714687248445050">"सुलभता सेटिंग"</string> @@ -20,7 +20,7 @@      <string name="brightness_down_label" msgid="7115662941913272072">"स्क्रीन की रोशनी कम करें"</string>      <string name="previous_button_content_description" msgid="840869171117765966">"पिछली स्क्रीन पर जाएं"</string>      <string name="next_button_content_description" msgid="6810058269847364406">"अगली स्क्रीन पर जाएं"</string> -    <string name="accessibility_menu_description" msgid="4458354794093858297">"सुलभता मेन्यू, स्क्रीन पर दिखने वाला एक बड़ा मेन्यू होता है. इसकी मदद से, अपने डिवाइस को कंट्रोल किया जा सकता है. इस मेन्यू में जाकर, अपना डिवाइस लॉक करने, स्क्रीनशॉट लेने, स्क्रीन की रोशनी और आवाज़ कंट्रोल करने जैसे कई दूसरे काम किए जा सकते हैं."</string> +    <string name="accessibility_menu_description" msgid="4458354794093858297">"सुलभता मेन्यू, डिवाइस की स्क्रीन पर दिखने वाला एक बड़ा मेन्यू होता है. इस मेन्यू में जाकर, डिवाइस को लॉक करने, स्क्रीनशॉट लेने, स्क्रीन की रोशनी और आवाज़ को कंट्रोल करने जैसे कई काम किए जा सकते हैं."</string>      <string name="accessibility_menu_summary" msgid="340071398148208130">"बड़े मेन्यू की मदद से डिवाइस को कंट्रोल करें"</string>      <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"सुलभता मेन्यू सेटिंग"</string>      <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"बड़े बटन"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ky/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ky/strings.xml index fa8b587e62c7..98c91ed65056 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ky/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ky/strings.xml @@ -21,7 +21,7 @@      <string name="previous_button_content_description" msgid="840869171117765966">"Мурунку экранга өтүү"</string>      <string name="next_button_content_description" msgid="6810058269847364406">"Кийинки экранга өтүү"</string>      <string name="accessibility_menu_description" msgid="4458354794093858297">"Атайын мүмкүнчүлүктөр менюсу — бул түзмөгүңүздү көзөмөлдөөнү жеңилдетүүгө ылайыкташтырылган экрандагы чоң меню. Түзмөгүңүздү кулпулап, үнүнүн катуулугун жана экрандын жарыктыгын көзөмөлдөп, скриншотторду тартып жана башка аракеттерди аткара аласыз."</string> -    <string name="accessibility_menu_summary" msgid="340071398148208130">"Түзмөктү чоң менюдан башкаруу"</string> +    <string name="accessibility_menu_summary" msgid="340071398148208130">"Түзмөктү чоң менюдан башкарасыз"</string>      <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Атайын мүмкүнчүлүктөр менюсунун параметрлери"</string>      <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Чоң баскычтар"</string>      <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Атайын мүмкүнчүлүктөр менюсундагы баскычтардын өлчөмүн чоңойтот"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ms/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ms/strings.xml index 9c1ea75d90f3..fd347324d05b 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ms/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ms/strings.xml @@ -2,14 +2,14 @@  <resources xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">      <string name="accessibility_menu_service_name" msgid="730136711554740131">"Menu Kebolehaksesan"</string> -    <string name="accessibility_menu_intro" msgid="3164193281544042394">"Menu Kebolehaksesan menyediakan menu pada skrin yang besar untuk mengawal peranti anda. Anda boleh mengunci peranti anda, mengawal kelantangan dan kecerahan, mengambil tangkapan skrin dan banyak lagi."</string> +    <string name="accessibility_menu_intro" msgid="3164193281544042394">"Menu Kebolehaksesan menyediakan menu yang besar pada skrin untuk mengawal peranti anda. Anda boleh mengunci peranti, mengawal kelantangan dan kecerahan, mengambil tangkapan skrin dan banyak lagi."</string>      <string name="assistant_label" msgid="6796392082252272356">"Assistant"</string>      <string name="assistant_utterance" msgid="65509599221141377">"Assistant"</string>      <string name="a11y_settings_label" msgid="3977714687248445050">"Tetapan Kebolehaksesan"</string>      <string name="power_label" msgid="7699720321491287839">"Kuasa"</string>      <string name="power_utterance" msgid="7444296686402104807">"Pilihan kuasa"</string>      <string name="recent_apps_label" msgid="6583276995616385847">"Apl terbaharu"</string> -    <string name="lockscreen_label" msgid="648347953557887087">"Kunci skrin"</string> +    <string name="lockscreen_label" msgid="648347953557887087">"Skrin kunci"</string>      <string name="quick_settings_label" msgid="2999117381487601865">"Tetapan Pantas"</string>      <string name="notifications_label" msgid="6829741046963013567">"Pemberitahuan"</string>      <string name="screenshot_label" msgid="863978141223970162">"Tangkapan skrin"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml index a8d6a0bc090c..3f72d955cc99 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml @@ -2,7 +2,7 @@  <resources xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">      <string name="accessibility_menu_service_name" msgid="730136711554740131">"Toegankelijkheidsmenu"</string> -    <string name="accessibility_menu_intro" msgid="3164193281544042394">"Het toegankelijkheidsmenu is een groot menu op het scherm waarmee je je apparaat kunt bedienen. Je kunt onder meer je apparaat vergrendelen, het volume en de helderheid beheren en screenshots maken."</string> +    <string name="accessibility_menu_intro" msgid="3164193281544042394">"Het toegankelijkheidsmenu is een groot menu op het scherm waarmee je je apparaat kunt bedienen. Je kunt onder meer je apparaat vergrendelen, het volume en de helderheid aanpassen en screenshots maken."</string>      <string name="assistant_label" msgid="6796392082252272356">"Assistent"</string>      <string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string>      <string name="a11y_settings_label" msgid="3977714687248445050">"Instellingen voor toegankelijkheid"</string> @@ -21,7 +21,7 @@      <string name="previous_button_content_description" msgid="840869171117765966">"Ga naar vorig scherm"</string>      <string name="next_button_content_description" msgid="6810058269847364406">"Ga naar volgend scherm"</string>      <string name="accessibility_menu_description" msgid="4458354794093858297">"Het toegankelijkheidsmenu is een groot menu op het scherm waarmee je je apparaat kunt bedienen. Je kunt onder meer je apparaat vergrendelen, het volume en de helderheid aanpassen en screenshots maken."</string> -    <string name="accessibility_menu_summary" msgid="340071398148208130">"Bedien apparaat via groot menu"</string> +    <string name="accessibility_menu_summary" msgid="340071398148208130">"Bedien het apparaat via een groot menu"</string>      <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Instellingen toegankelijkheidsmenu"</string>      <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Grote knoppen"</string>      <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Vergroot knoppen in het toegankelijkheidsmenu"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rPT/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rPT/strings.xml index 44aff75d1021..0cc2f58e13b5 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rPT/strings.xml @@ -21,7 +21,7 @@      <string name="previous_button_content_description" msgid="840869171117765966">"Ir para o ecrã anterior"</string>      <string name="next_button_content_description" msgid="6810058269847364406">"Ir para o ecrã seguinte"</string>      <string name="accessibility_menu_description" msgid="4458354794093858297">"O menu Acessibilidade disponibiliza um menu grande no ecrã para controlar o dispositivo. Pode bloquear o dispositivo, controlar o volume e o brilho, fazer capturas de ecrã e muito mais."</string> -    <string name="accessibility_menu_summary" msgid="340071398148208130">"Controle o dispositivo através do menu grande"</string> +    <string name="accessibility_menu_summary" msgid="340071398148208130">"Controlar dispositivo através do menu grande"</string>      <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Definições do menu Acessibilidade"</string>      <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Botões grandes"</string>      <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Aumentar o tamanho dos botões do menu Acessibilidade"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml index 264749814e6c..62f63a8739d4 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-sk/strings.xml @@ -2,7 +2,7 @@  <resources xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">      <string name="accessibility_menu_service_name" msgid="730136711554740131">"Ponuka Dostupnosť"</string> -    <string name="accessibility_menu_intro" msgid="3164193281544042394">"Ponukou dostupnosti sa rozumie veľká ponuka na obrazovke, pomocou ktorej môžete ovládať zariadenie. Môžete ho uzamknúť, ovládať hlasitosť a jas, vytvárať snímky obrazovky a mnoho ďalšieho."</string> +    <string name="accessibility_menu_intro" msgid="3164193281544042394">"Ponukou Dostupnosť sa rozumie veľká ponuka na obrazovke, pomocou ktorej môžete ovládať zariadenie. Môžete ho uzamknúť, ovládať hlasitosť a jas, vytvárať snímky obrazovky a mnoho ďalšieho."</string>      <string name="assistant_label" msgid="6796392082252272356">"Asistent"</string>      <string name="assistant_utterance" msgid="65509599221141377">"Asistent"</string>      <string name="a11y_settings_label" msgid="3977714687248445050">"Nastavenia dostupnosti"</string> @@ -21,7 +21,7 @@      <string name="previous_button_content_description" msgid="840869171117765966">"Prejsť na predchádzajúcu obrazovku"</string>      <string name="next_button_content_description" msgid="6810058269847364406">"Prejsť na ďalšiu obrazovku"</string>      <string name="accessibility_menu_description" msgid="4458354794093858297">"Ponuka dostupnosti spustí na obrazovke telefónu veľkú ponuku, pomocou ktorej môžete ovládať svoje zariadenie. Môžete ho uzamknúť, ovládať hlasitosť a jas, vytvárať snímky obrazovky a mnoho ďalšieho."</string> -    <string name="accessibility_menu_summary" msgid="340071398148208130">"Ovládať zariadenie pomocou veľkej ponuky"</string> +    <string name="accessibility_menu_summary" msgid="340071398148208130">"Ovládanie zariadenia pomocou veľkej ponuky"</string>      <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Nastavenia ponuky dostupnosti"</string>      <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Veľké tlačidlá"</string>      <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Zväčšiť tlačidlá ponuky dostupnosti"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java index 5f3d1eafb4fb..0ab99fac9ba3 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java +++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java @@ -30,8 +30,6 @@ import static com.android.systemui.accessibility.accessibilitymenu.Accessibility  import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_TOGGLE_MENU;  import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.PACKAGE_NAME; -import static com.google.common.truth.Truth.assertThat; -  import android.accessibilityservice.AccessibilityServiceInfo;  import android.app.Instrumentation;  import android.app.KeyguardManager; @@ -449,7 +447,10 @@ public class AccessibilityMenuServiceTest {          closeScreen();          wakeUpScreen(); -        assertThat(isMenuVisible()).isFalse(); +        TestUtils.waitUntil("Menu did not close.", +                TIMEOUT_UI_CHANGE_S, +                () -> !isMenuVisible() +        );      }      @Test diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig index 8137e408ba39..14ebc3907c04 100644 --- a/packages/SystemUI/aconfig/accessibility.aconfig +++ b/packages/SystemUI/aconfig/accessibility.aconfig @@ -32,6 +32,16 @@ flag {  }  flag { +    name: "floating_menu_narrow_target_content_observer" +    namespace: "accessibility" +    description: "stops the FAB from monitoring enabled services to trigger target content changes." +    bug: "331740049" +    metadata { +      purpose: PURPOSE_BUGFIX +    } +} + +flag {      name: "floating_menu_overlaps_nav_bars_flag"      namespace: "accessibility"      description: "Adjusts bounds to allow the floating menu to render on top of navigation bars." diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 6810aac92925..c979d053617a 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -148,6 +148,16 @@ flag {  }  flag { +   name: "pss_app_selector_recents_split_screen" +   namespace: "systemui" +   description: "Allows recent apps selected for partial screenshare to be launched in split screen mode" +   bug: "320449039" +   metadata { +        purpose: PURPOSE_BUGFIX +   } +} + +flag {      name: "notifications_background_icons"      namespace: "systemui"      description: "Moves part of the notification icon updates to the background." @@ -328,6 +338,16 @@ flag {  }  flag { +    name: "status_bar_monochrome_icons_fix" +    namespace: "systemui" +    description: "Fixes the status bar icon size when drawing InsetDrawables (ie. monochrome icons)" +    bug: "329091967" +    metadata { +        purpose: PURPOSE_BUGFIX +    } +} + +flag {      name: "compose_bouncer"      namespace: "systemui"      description: "Use the new compose bouncer in SystemUI" @@ -457,10 +477,13 @@ flag {  }  flag { -    name: "screenshot_private_profile" +    name: "screenshot_private_profile_behavior_fix"      namespace: "systemui"      description: "Private profile support for screenshots"      bug: "327613051" +    metadata { +        purpose: PURPOSE_BUGFIX +    }  }  flag { @@ -726,8 +749,38 @@ flag {  }  flag { +  name: "remove_dream_overlay_hide_on_touch" +  namespace: "systemui" +  description: "Removes logic to hide the dream overlay on user interaction, as it conflicts with various transitions" +  bug: "329091030" +  metadata { +    purpose: PURPOSE_BUGFIX +  } +} + +flag {      name: "keyboard_docking_indicator"      namespace: "systemui"      description: "Glow bar indicator reveals upon keyboard docking."      bug: "324600132"  } + +flag { +  name: "dream_overlay_bouncer_swipe_direction_filtering" +  namespace: "systemui" +  description: "do not initiate bouncer swipe when the direction is opposite of the expansion" +  bug: "333632464" +  metadata { +    purpose: PURPOSE_BUGFIX +  } +} + +flag { +    name: "dream_input_session_pilfer_once" +    namespace: "systemui" +    description: "Pilfer at most once per input session" +    bug: "324600132" +    metadata { +      purpose: PURPOSE_BUGFIX +    } +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java index e20425d4b98c..94f884673fbd 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java @@ -36,6 +36,7 @@ import android.view.WindowManager;  import android.view.WindowManager.TransitionOldType;  import android.window.IRemoteTransition;  import android.window.IRemoteTransitionFinishedCallback; +import android.window.RemoteTransitionStub;  import android.window.TransitionInfo;  import com.android.wm.shell.shared.CounterRotator; @@ -69,8 +70,8 @@ public abstract class RemoteAnimationRunnerCompat extends IRemoteAnimationRunner      }      /** Wraps a remote animation runner in a remote-transition. */ -    public static IRemoteTransition.Stub wrap(IRemoteAnimationRunner runner) { -        return new IRemoteTransition.Stub() { +    public static RemoteTransitionStub wrap(IRemoteAnimationRunner runner) { +        return new RemoteTransitionStub() {              final ArrayMap<IBinder, Runnable> mFinishRunnables = new ArrayMap<>();              @Override @@ -233,11 +234,6 @@ public abstract class RemoteAnimationRunnerCompat extends IRemoteAnimationRunner                  runner.onAnimationCancelled();                  finishRunnable.run();              } - -            @Override -            public void onTransitionConsumed(IBinder iBinder, boolean aborted) -                    throws RemoteException { -            }          };      }  } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt index 4d327e1d8beb..6c982a045084 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt @@ -41,9 +41,9 @@ fun BackAnimationSpec.Companion.createFloatingSurfaceAnimationSpec(      maxMarginXdp: Float,      maxMarginYdp: Float,      minScale: Float, -    translateXEasing: Interpolator = Interpolators.STANDARD_DECELERATE, +    translateXEasing: Interpolator = Interpolators.BACK_GESTURE,      translateYEasing: Interpolator = Interpolators.LINEAR, -    scaleEasing: Interpolator = Interpolators.STANDARD_DECELERATE, +    scaleEasing: Interpolator = Interpolators.BACK_GESTURE,  ): BackAnimationSpec {      return BackAnimationSpec { backEvent, progressY, result ->          val displayMetrics = displayMetricsProvider() diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/PaintDrawCallback.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/PaintDrawCallback.kt new file mode 100644 index 000000000000..d50979ccd01d --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/PaintDrawCallback.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.surfaceeffects + +import android.graphics.Paint +import android.graphics.RenderEffect + +/** + * A callback with a [Paint] object that contains shader info, which is triggered every frame while + * animation is playing. Note that the [Paint] object here is always the same instance. + * + * This approach is more performant than other ones because [RenderEffect] forces an intermediate + * render pass of the View to a texture to feed into it. + * + * The usage of this callback is as follows: + * <pre>{@code + *     private var paint: Paint? = null + *     // Override [View.onDraw]. + *     override fun onDraw(canvas: Canvas) { + *         // RuntimeShader requires hardwareAcceleration. + *         if (!canvas.isHardwareAccelerated) return + * + *         paint?.let { canvas.drawPaint(it) } + *     } + * + *     // Given that this is called [PaintDrawCallback.onDraw] + *     fun draw(paint: Paint) { + *         this.paint = paint + * + *         // Must call invalidate to trigger View#onDraw + *         invalidate() + *     } + * }</pre> + * + * Please refer to [RenderEffectDrawCallback] for alternative approach. + */ +interface PaintDrawCallback { +    fun onDraw(paint: Paint) +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/RenderEffectDrawCallback.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/RenderEffectDrawCallback.kt new file mode 100644 index 000000000000..db7ee58090a9 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/RenderEffectDrawCallback.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.surfaceeffects + +import android.graphics.RenderEffect + +/** + * A callback with a [RenderEffect] object that contains shader info, which is triggered every frame + * while animation is playing. Note that the [RenderEffect] instance is different each time to + * update shader uniforms. + * + * The usage of this callback is as follows: + * <pre>{@code + *     private val xEffectDrawingCallback = RenderEffectDrawCallback() { + *         val myOtherRenderEffect = createOtherRenderEffect() + *         val chainEffect = RenderEffect.createChainEffect(renderEffect, myOtherRenderEffect) + *         myView.setRenderEffect(chainEffect) + *     } + * + *     private val xEffect = XEffect(config, xEffectDrawingCallback) + * }</pre> + */ +interface RenderEffectDrawCallback { +    fun onDraw(renderEffect: RenderEffect) +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffect.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffect.kt index 1c763e8c6108..211b84f25369 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffect.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffect.kt @@ -22,6 +22,8 @@ import android.animation.ValueAnimator  import android.graphics.Paint  import android.graphics.RenderEffect  import android.view.View +import com.android.systemui.surfaceeffects.PaintDrawCallback +import com.android.systemui.surfaceeffects.RenderEffectDrawCallback  import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseAnimationConfig  import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseShader @@ -334,52 +336,31 @@ private constructor(          )      } -    companion object { +    /** +     * States of the loading effect animation. +     * +     * <p>The state is designed to be follow the order below: [AnimationState.EASE_IN], +     * [AnimationState.MAIN], [AnimationState.EASE_OUT]. Note that ease in and out don't necessarily +     * mean the acceleration and deceleration in the animation curve. They simply mean each stage of +     * the animation. (i.e. Intro, core, and rest) +     */ +    enum class AnimationState { +        EASE_IN, +        MAIN, +        EASE_OUT, +        NOT_PLAYING +    } + +    /** Optional callback that is triggered when the animation state changes. */ +    interface AnimationStateChangedCallback {          /** -         * States of the loading effect animation. -         * -         * <p>The state is designed to be follow the order below: [AnimationState.EASE_IN], -         * [AnimationState.MAIN], [AnimationState.EASE_OUT]. Note that ease in and out don't -         * necessarily mean the acceleration and deceleration in the animation curve. They simply -         * mean each stage of the animation. (i.e. Intro, core, and rest) +         * A callback that's triggered when the [AnimationState] changes. Example usage is +         * performing a cleanup when [AnimationState] becomes [NOT_PLAYING].           */ -        enum class AnimationState { -            EASE_IN, -            MAIN, -            EASE_OUT, -            NOT_PLAYING -        } - -        /** Client must implement one of the draw callbacks. */ -        interface PaintDrawCallback { -            /** -             * A callback with a [Paint] object that contains shader info, which is triggered every -             * frame while animation is playing. Note that the [Paint] object here is always the -             * same instance. -             */ -            fun onDraw(loadingPaint: Paint) -        } - -        interface RenderEffectDrawCallback { -            /** -             * A callback with a [RenderEffect] object that contains shader info, which is triggered -             * every frame while animation is playing. Note that the [RenderEffect] instance is -             * different each time to update shader uniforms. -             */ -            fun onDraw(loadingRenderEffect: RenderEffect) -        } - -        /** Optional callback that is triggered when the animation state changes. */ -        interface AnimationStateChangedCallback { -            /** -             * A callback that's triggered when the [AnimationState] changes. Example usage is -             * performing a cleanup when [AnimationState] becomes [NOT_PLAYING]. -             */ -            fun onStateChanged(oldState: AnimationState, newState: AnimationState) {} -        } +        fun onStateChanged(oldState: AnimationState, newState: AnimationState) {} +    } +    private companion object {          private const val MS_TO_SEC = 0.001f - -        private val TAG = LoadingEffect::class.java.simpleName      }  } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt index 4a89e31bcea8..36e6909a15cf 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt @@ -25,7 +25,6 @@ import androidx.compose.foundation.Canvas  import androidx.compose.foundation.background  import androidx.compose.foundation.interaction.DragInteraction  import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.isSystemInDarkTheme  import androidx.compose.foundation.layout.Box  import androidx.compose.foundation.layout.Spacer  import androidx.compose.foundation.layout.fillMaxSize @@ -63,7 +62,6 @@ import androidx.compose.ui.layout.Placeable  import androidx.compose.ui.layout.layoutId  import androidx.compose.ui.platform.LocalDensity  import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.res.colorResource  import androidx.compose.ui.unit.Constraints  import androidx.compose.ui.unit.Dp  import androidx.compose.ui.unit.IntOffset @@ -458,40 +456,19 @@ object PlatformSliderDefaults {      @Composable      fun defaultPlatformSliderColors(): PlatformSliderColors = -        if (isSystemInDarkTheme()) darkThemePlatformSliderColors() -        else lightThemePlatformSliderColors() +        PlatformSliderColors( +            trackColor = MaterialTheme.colorScheme.secondaryContainer, +            indicatorColor = MaterialTheme.colorScheme.primary, +            iconColor = MaterialTheme.colorScheme.onPrimary, +            labelColorOnIndicator = MaterialTheme.colorScheme.onPrimary, +            labelColorOnTrack = MaterialTheme.colorScheme.onSecondaryContainer, +            disabledTrackColor = MaterialTheme.colorScheme.surfaceContainerHighest, +            disabledIndicatorColor = MaterialTheme.colorScheme.surfaceContainerHighest, +            disabledIconColor = MaterialTheme.colorScheme.outline, +            disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant, +        )  } -/** [PlatformSliderColors] for the light theme */ -@Composable -private fun lightThemePlatformSliderColors() = -    PlatformSliderColors( -        trackColor = colorResource(android.R.color.system_accent3_200), -        indicatorColor = MaterialTheme.colorScheme.tertiary, -        iconColor = MaterialTheme.colorScheme.onTertiary, -        labelColorOnIndicator = MaterialTheme.colorScheme.onTertiary, -        labelColorOnTrack = MaterialTheme.colorScheme.onTertiaryContainer, -        disabledTrackColor = MaterialTheme.colorScheme.surfaceContainerHighest, -        disabledIndicatorColor = MaterialTheme.colorScheme.surfaceContainerHighest, -        disabledIconColor = MaterialTheme.colorScheme.outline, -        disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant, -    ) - -/** [PlatformSliderColors] for the dark theme */ -@Composable -private fun darkThemePlatformSliderColors() = -    PlatformSliderColors( -        trackColor = colorResource(android.R.color.system_accent3_600), -        indicatorColor = MaterialTheme.colorScheme.tertiary, -        iconColor = MaterialTheme.colorScheme.onTertiary, -        labelColorOnIndicator = MaterialTheme.colorScheme.onTertiary, -        labelColorOnTrack = colorResource(android.R.color.system_accent3_900), -        disabledTrackColor = MaterialTheme.colorScheme.surfaceContainerHighest, -        disabledIndicatorColor = MaterialTheme.colorScheme.surfaceContainerHighest, -        disabledIconColor = MaterialTheme.colorScheme.outline, -        disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant, -    ) -  private fun PlatformSliderColors.getTrackColor(isEnabled: Boolean): Color =      if (isEnabled) trackColor else disabledTrackColor diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt index 0f3d3dc2847f..d55d4e494980 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt @@ -160,7 +160,9 @@ private fun StandardLayout(      FoldAware(          modifier =              modifier.padding( +                start = 32.dp,                  top = 92.dp, +                end = 32.dp,                  bottom = 48.dp,              ),          viewModel = viewModel, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt index 3ec5508c81b3..d59f1f5bbe25 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt @@ -22,11 +22,8 @@ import androidx.compose.foundation.layout.fillMaxSize  import androidx.compose.material3.MaterialTheme  import androidx.compose.runtime.Composable  import androidx.compose.ui.Modifier -import com.android.compose.animation.scene.Back  import com.android.compose.animation.scene.ElementKey  import com.android.compose.animation.scene.SceneScope -import com.android.compose.animation.scene.Swipe -import com.android.compose.animation.scene.SwipeDirection  import com.android.compose.animation.scene.UserAction  import com.android.compose.animation.scene.UserActionResult  import com.android.systemui.bouncer.ui.BouncerDialogFactory @@ -35,9 +32,7 @@ import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.scene.shared.model.Scenes  import com.android.systemui.scene.ui.composable.ComposableScene  import javax.inject.Inject -import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow  object Bouncer {      object Elements { @@ -57,13 +52,7 @@ constructor(      override val key = Scenes.Bouncer      override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = -        MutableStateFlow( -                mapOf( -                    Back to UserActionResult(Scenes.Lockscreen), -                    Swipe(SwipeDirection.Down) to UserActionResult(Scenes.Lockscreen), -                ) -            ) -            .asStateFlow() +        viewModel.destinationScenes      @Composable      override fun SceneScope.Content( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt index a78c2c0d16c6..07c2d3c95e01 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt @@ -432,12 +432,12 @@ private fun offset(      }  } -private const val DOT_DIAMETER_DP = 16 -private const val SELECTED_DOT_DIAMETER_DP = 24 +private const val DOT_DIAMETER_DP = 14 +private const val SELECTED_DOT_DIAMETER_DP = (DOT_DIAMETER_DP * 1.5).toInt()  private const val SELECTED_DOT_REACTION_ANIMATION_DURATION_MS = 83  private const val SELECTED_DOT_RETRACT_ANIMATION_DURATION_MS = 750 -private const val LINE_STROKE_WIDTH_DP = 16 -private const val FAILURE_ANIMATION_DOT_DIAMETER_DP = 13 +private const val LINE_STROKE_WIDTH_DP = DOT_DIAMETER_DP +private const val FAILURE_ANIMATION_DOT_DIAMETER_DP = (DOT_DIAMETER_DP * 0.81f).toInt()  private const val FAILURE_ANIMATION_DOT_SHRINK_ANIMATION_DURATION_MS = 50  private const val FAILURE_ANIMATION_DOT_SHRINK_STAGGER_DELAY_MS = 33  private const val FAILURE_ANIMATION_DOT_REVERT_ANIMATION_DURATION = 617 diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt index bdd888f45182..4533f58c1c37 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt @@ -26,6 +26,7 @@ import com.android.compose.animation.scene.observableTransitionState  import com.android.compose.animation.scene.transitions  import com.android.compose.theme.LocalAndroidColorScheme  import com.android.systemui.communal.shared.model.CommunalScenes +import com.android.systemui.communal.shared.model.CommunalTransitionKeys  import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel  import com.android.systemui.communal.ui.viewmodel.CommunalViewModel  import com.android.systemui.res.R @@ -41,6 +42,11 @@ object Communal {  }  val sceneTransitions = transitions { +    to(CommunalScenes.Communal, key = CommunalTransitionKeys.SimpleFade) { +        spec = tween(durationMillis = 250) +        fade(Communal.Elements.Scrim) +        fade(Communal.Elements.Content) +    }      to(CommunalScenes.Communal) {          spec = tween(durationMillis = 1000)          translate(Communal.Elements.Content, Edge.Right) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt index 55f7f69a08d6..52cbffbc0177 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt @@ -19,8 +19,6 @@ package com.android.systemui.keyguard.ui.composable  import com.android.systemui.keyguard.ui.composable.blueprint.CommunalBlueprintModule  import com.android.systemui.keyguard.ui.composable.blueprint.DefaultBlueprintModule  import com.android.systemui.keyguard.ui.composable.blueprint.ShortcutsBesideUdfpsBlueprintModule -import com.android.systemui.keyguard.ui.composable.blueprint.SplitShadeWeatherClockBlueprintModule -import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockBlueprintModule  import com.android.systemui.keyguard.ui.composable.section.OptionalSectionModule  import dagger.Module @@ -31,8 +29,6 @@ import dagger.Module              DefaultBlueprintModule::class,              OptionalSectionModule::class,              ShortcutsBesideUdfpsBlueprintModule::class, -            SplitShadeWeatherClockBlueprintModule::class, -            WeatherClockBlueprintModule::class,          ],  )  interface LockscreenSceneBlueprintModule diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt index acd9e3dc83cb..c6fe81af59b7 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ClockTransition.kt @@ -25,6 +25,9 @@ import com.android.compose.animation.scene.transitions  import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.largeClockElementKey  import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.smallClockElementKey  import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.smartspaceElementKey +import com.android.systemui.keyguard.ui.composable.blueprint.ClockTransition.transitioningToLargeClock +import com.android.systemui.keyguard.ui.composable.blueprint.ClockTransition.transitioningToSmallClock +import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockElementKeys.largeWeatherClockElementKeyList  import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.ClockFaceInTransition.Companion.CLOCK_IN_MILLIS  import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.ClockFaceInTransition.Companion.CLOCK_IN_START_DELAY_MILLIS  import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.ClockFaceOutTransition.Companion.CLOCK_OUT_MILLIS @@ -34,30 +37,45 @@ import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSi  object ClockTransition {      val defaultClockTransitions = transitions {          from(ClockScenes.smallClockScene, to = ClockScenes.largeClockScene) { -            transitioningToLargeClock() +            transitioningToLargeClock(largeClockElements = listOf(largeClockElementKey))          }          from(ClockScenes.largeClockScene, to = ClockScenes.smallClockScene) { -            transitioningToSmallClock() +            transitioningToSmallClock(largeClockElements = listOf(largeClockElementKey))          }          from(ClockScenes.splitShadeLargeClockScene, to = ClockScenes.largeClockScene) { -            spec = tween(1000, easing = LinearEasing) +            spec = tween(300, easing = LinearEasing) +        } + +        from(WeatherClockScenes.largeClockScene, to = ClockScenes.smallClockScene) { +            transitioningToSmallClock(largeClockElements = largeWeatherClockElementKeyList) +        } + +        from(ClockScenes.smallClockScene, to = WeatherClockScenes.largeClockScene) { +            transitioningToLargeClock(largeClockElements = largeWeatherClockElementKeyList) +        } + +        from( +            WeatherClockScenes.largeClockScene, +            to = WeatherClockScenes.splitShadeLargeClockScene +        ) { +            spec = tween(300, easing = LinearEasing)          }      } -    private fun TransitionBuilder.transitioningToLargeClock() { +    private fun TransitionBuilder.transitioningToLargeClock(largeClockElements: List<ElementKey>) {          spec = tween(durationMillis = STATUS_AREA_MOVE_UP_MILLIS.toInt())          timestampRange(              startMillis = CLOCK_IN_START_DELAY_MILLIS.toInt(),              endMillis = (CLOCK_IN_START_DELAY_MILLIS + CLOCK_IN_MILLIS).toInt()          ) { -            fade(largeClockElementKey) +            largeClockElements.forEach { fade(it) }          }          timestampRange(endMillis = CLOCK_OUT_MILLIS.toInt()) { fade(smallClockElementKey) }          anchoredTranslate(smallClockElementKey, smartspaceElementKey)      } -    private fun TransitionBuilder.transitioningToSmallClock() { +    private fun TransitionBuilder.transitioningToSmallClock(largeClockElements: List<ElementKey>) {          spec = tween(durationMillis = STATUS_AREA_MOVE_DOWN_MILLIS.toInt())          timestampRange(              startMillis = CLOCK_IN_START_DELAY_MILLIS.toInt(), @@ -66,7 +84,9 @@ object ClockTransition {              fade(smallClockElementKey)          } -        timestampRange(endMillis = CLOCK_OUT_MILLIS.toInt()) { fade(largeClockElementKey) } +        timestampRange(endMillis = CLOCK_OUT_MILLIS.toInt()) { +            largeClockElements.forEach { fade(it) } +        }          anchoredTranslate(smallClockElementKey, smartspaceElementKey)      }  } @@ -81,14 +101,26 @@ object ClockScenes {  object ClockElementKeys {      val largeClockElementKey = ElementKey("large-clock")      val smallClockElementKey = ElementKey("small-clock") -    val weatherSmallClockElementKey = ElementKey("weather-small-clock")      val smartspaceElementKey = ElementKey("smart-space")  } +object WeatherClockScenes { +    val largeClockScene = SceneKey("large-weather-clock-scene") +    val splitShadeLargeClockScene = SceneKey("split-shade-large-weather-clock-scene") +} +  object WeatherClockElementKeys {      val timeElementKey = ElementKey("weather-large-clock-time")      val dateElementKey = ElementKey("weather-large-clock-date")      val weatherIconElementKey = ElementKey("weather-large-clock-weather-icon")      val temperatureElementKey = ElementKey("weather-large-clock-temperature")      val dndAlarmElementKey = ElementKey("weather-large-clock-dnd-alarm") +    val largeWeatherClockElementKeyList = +        listOf( +            timeElementKey, +            dateElementKey, +            weatherIconElementKey, +            temperatureElementKey, +            dndAlarmElementKey +        )  } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt deleted file mode 100644 index cba54531713b..000000000000 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.keyguard.ui.composable.blueprint - -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.Layout -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.IntRect -import androidx.compose.ui.unit.dp -import com.android.compose.animation.scene.SceneScope -import com.android.compose.modifiers.padding -import com.android.keyguard.KeyguardClockSwitch.LARGE -import com.android.systemui.Flags -import com.android.systemui.customization.R as customizationR -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID -import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor -import com.android.systemui.keyguard.ui.composable.LockscreenLongPress -import com.android.systemui.keyguard.ui.composable.modifier.onTopPlacementChanged -import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection -import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection -import com.android.systemui.keyguard.ui.composable.section.LockSection -import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection -import com.android.systemui.keyguard.ui.composable.section.NotificationSection -import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection -import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection -import com.android.systemui.keyguard.ui.composable.section.StatusBarSection -import com.android.systemui.keyguard.ui.composable.section.WeatherClockSection -import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel -import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel -import com.android.systemui.res.R -import com.android.systemui.shade.LargeScreenHeaderHelper -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoSet -import java.util.Optional -import javax.inject.Inject - -class WeatherClockBlueprint -@Inject -constructor( -    private val viewModel: LockscreenContentViewModel, -    private val statusBarSection: StatusBarSection, -    private val weatherClockSection: WeatherClockSection, -    private val smartSpaceSection: SmartSpaceSection, -    private val notificationSection: NotificationSection, -    private val lockSection: LockSection, -    private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>, -    private val bottomAreaSection: BottomAreaSection, -    private val settingsMenuSection: SettingsMenuSection, -    private val clockInteractor: KeyguardClockInteractor, -    private val mediaCarouselSection: MediaCarouselSection, -    private val clockViewModel: KeyguardClockViewModel, -) : ComposableLockscreenSceneBlueprint { - -    override val id: String = WEATHER_CLOCK_BLUEPRINT_ID -    @Composable -    override fun SceneScope.Content(modifier: Modifier) { -        val isUdfpsVisible = viewModel.isUdfpsVisible -        val burnIn = rememberBurnIn(clockInteractor) -        val resources = LocalContext.current.resources -        val currentClockState = clockViewModel.currentClock.collectAsState() -        val areNotificationsVisible by viewModel.areNotificationsVisible.collectAsState() -        LockscreenLongPress( -            viewModel = viewModel.longPress, -            modifier = modifier, -        ) { onSettingsMenuPlaced -> -            Layout( -                content = { -                    // Constrained to above the lock icon. -                    Column( -                        modifier = Modifier.fillMaxWidth(), -                    ) { -                        with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } -                        val currentClock = currentClockState.value -                        val clockSize by clockViewModel.clockSize.collectAsState() -                        with(weatherClockSection) { -                            if (currentClock == null) { -                                return@with -                            } - -                            if (clockSize == LARGE) { -                                Time( -                                    clock = currentClock, -                                    modifier = -                                        Modifier.padding( -                                            start = -                                                dimensionResource( -                                                    customizationR.dimen.clock_padding_start -                                                ) -                                        ) -                                ) -                            } else { -                                SmallClock( -                                    burnInParams = burnIn.parameters, -                                    modifier = -                                        Modifier.align(Alignment.Start) -                                            .onTopPlacementChanged(burnIn.onSmallClockTopChanged), -                                    clock = currentClock -                                ) -                            } -                        } -                        with(smartSpaceSection) { -                            SmartSpace( -                                burnInParams = burnIn.parameters, -                                onTopChanged = burnIn.onSmartspaceTopChanged, -                                modifier = -                                    Modifier.fillMaxWidth() -                                        .padding( -                                            top = { viewModel.getSmartSpacePaddingTop(resources) }, -                                        ) -                                        .padding( -                                            bottom = -                                                dimensionResource( -                                                    R.dimen.keyguard_status_view_bottom_margin -                                                ), -                                        ), -                            ) -                        } - -                        with(mediaCarouselSection) { MediaCarousel() } - -                        if (areNotificationsVisible) { -                            with(notificationSection) { -                                Notifications( -                                    burnInParams = burnIn.parameters, -                                    modifier = Modifier.fillMaxWidth().weight(weight = 1f) -                                ) -                            } -                        } -                        with(weatherClockSection) { -                            if (currentClock == null || clockSize != LARGE) { -                                return@with -                            } -                            LargeClockSectionBelowSmartspace(clock = currentClock) -                        } - -                        if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { -                            with(ambientIndicationSectionOptional.get()) { -                                AmbientIndication(modifier = Modifier.fillMaxWidth()) -                            } -                        } -                    } - -                    with(lockSection) { LockIcon() } - -                    // Aligned to bottom and constrained to below the lock icon. -                    Column(modifier = Modifier.fillMaxWidth()) { -                        if (isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { -                            with(ambientIndicationSectionOptional.get()) { -                                AmbientIndication(modifier = Modifier.fillMaxWidth()) -                            } -                        } - -                        with(bottomAreaSection) { -                            IndicationArea(modifier = Modifier.fillMaxWidth()) -                        } -                    } - -                    // Aligned to bottom and NOT constrained by the lock icon. -                    with(bottomAreaSection) { -                        Shortcut(isStart = true, applyPadding = true) -                        Shortcut(isStart = false, applyPadding = true) -                    } -                    with(settingsMenuSection) { SettingsMenu(onSettingsMenuPlaced) } -                }, -                modifier = Modifier.fillMaxSize(), -            ) { measurables, constraints -> -                check(measurables.size == 6) -                val aboveLockIconMeasurable = measurables[0] -                val lockIconMeasurable = measurables[1] -                val belowLockIconMeasurable = measurables[2] -                val startShortcutMeasurable = measurables[3] -                val endShortcutMeasurable = measurables[4] -                val settingsMenuMeasurable = measurables[5] - -                val noMinConstraints = -                    constraints.copy( -                        minWidth = 0, -                        minHeight = 0, -                    ) -                val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints) -                val lockIconBounds = -                    IntRect( -                        left = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Left], -                        top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top], -                        right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right], -                        bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom], -                    ) - -                val aboveLockIconPlaceable = -                    aboveLockIconMeasurable.measure( -                        noMinConstraints.copy(maxHeight = lockIconBounds.top) -                    ) -                val belowLockIconPlaceable = -                    belowLockIconMeasurable.measure( -                        noMinConstraints.copy( -                            maxHeight = -                                (constraints.maxHeight - lockIconBounds.bottom).coerceAtLeast(0) -                        ) -                    ) -                val startShortcutPleaceable = startShortcutMeasurable.measure(noMinConstraints) -                val endShortcutPleaceable = endShortcutMeasurable.measure(noMinConstraints) -                val settingsMenuPlaceable = settingsMenuMeasurable.measure(noMinConstraints) - -                layout(constraints.maxWidth, constraints.maxHeight) { -                    aboveLockIconPlaceable.place( -                        x = 0, -                        y = 0, -                    ) -                    lockIconPlaceable.place( -                        x = lockIconBounds.left, -                        y = lockIconBounds.top, -                    ) -                    belowLockIconPlaceable.place( -                        x = 0, -                        y = constraints.maxHeight - belowLockIconPlaceable.height, -                    ) -                    startShortcutPleaceable.place( -                        x = 0, -                        y = constraints.maxHeight - startShortcutPleaceable.height, -                    ) -                    endShortcutPleaceable.place( -                        x = constraints.maxWidth - endShortcutPleaceable.width, -                        y = constraints.maxHeight - endShortcutPleaceable.height, -                    ) -                    settingsMenuPlaceable.place( -                        x = (constraints.maxWidth - settingsMenuPlaceable.width) / 2, -                        y = constraints.maxHeight - settingsMenuPlaceable.height, -                    ) -                } -            } -        } -    } -} - -class SplitShadeWeatherClockBlueprint -@Inject -constructor( -    private val viewModel: LockscreenContentViewModel, -    private val statusBarSection: StatusBarSection, -    private val smartSpaceSection: SmartSpaceSection, -    private val notificationSection: NotificationSection, -    private val lockSection: LockSection, -    private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>, -    private val bottomAreaSection: BottomAreaSection, -    private val settingsMenuSection: SettingsMenuSection, -    private val clockInteractor: KeyguardClockInteractor, -    private val largeScreenHeaderHelper: LargeScreenHeaderHelper, -    private val weatherClockSection: WeatherClockSection, -    private val mediaCarouselSection: MediaCarouselSection, -    private val clockViewModel: KeyguardClockViewModel, -) : ComposableLockscreenSceneBlueprint { -    override val id: String = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID - -    @Composable -    override fun SceneScope.Content(modifier: Modifier) { -        val isUdfpsVisible = viewModel.isUdfpsVisible -        val burnIn = rememberBurnIn(clockInteractor) -        val resources = LocalContext.current.resources -        val currentClockState = clockViewModel.currentClock.collectAsState() -        LockscreenLongPress( -            viewModel = viewModel.longPress, -            modifier = modifier, -        ) { onSettingsMenuPlaced -> -            Layout( -                content = { -                    // Constrained to above the lock icon. -                    Column( -                        modifier = Modifier.fillMaxSize(), -                    ) { -                        with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } -                        Row( -                            modifier = Modifier.fillMaxSize(), -                        ) { -                            Column( -                                modifier = Modifier.fillMaxHeight().weight(weight = 1f), -                                horizontalAlignment = Alignment.CenterHorizontally, -                            ) { -                                val currentClock = currentClockState.value -                                val clockSize by clockViewModel.clockSize.collectAsState() -                                with(weatherClockSection) { -                                    if (currentClock == null) { -                                        return@with -                                    } - -                                    if (clockSize == LARGE) { -                                        Time( -                                            clock = currentClock, -                                            modifier = -                                                Modifier.align(Alignment.Start) -                                                    .padding( -                                                        start = -                                                            dimensionResource( -                                                                customizationR.dimen -                                                                    .clock_padding_start -                                                            ) -                                                    ) -                                        ) -                                    } else { -                                        SmallClock( -                                            burnInParams = burnIn.parameters, -                                            modifier = -                                                Modifier.align(Alignment.Start) -                                                    .onTopPlacementChanged( -                                                        burnIn.onSmallClockTopChanged -                                                    ), -                                            clock = currentClock, -                                        ) -                                    } -                                } -                                with(smartSpaceSection) { -                                    SmartSpace( -                                        burnInParams = burnIn.parameters, -                                        onTopChanged = burnIn.onSmartspaceTopChanged, -                                        modifier = -                                            Modifier.fillMaxWidth() -                                                .padding( -                                                    top = { -                                                        viewModel.getSmartSpacePaddingTop(resources) -                                                    }, -                                                ) -                                                .padding( -                                                    bottom = -                                                        dimensionResource( -                                                            R.dimen -                                                                .keyguard_status_view_bottom_margin -                                                        ) -                                                ), -                                    ) -                                } - -                                with(mediaCarouselSection) { MediaCarousel() } - -                                with(weatherClockSection) { -                                    if (currentClock == null || clockSize != LARGE) { -                                        return@with -                                    } - -                                    LargeClockSectionBelowSmartspace(currentClock) -                                } -                            } -                            with(notificationSection) { -                                val splitShadeTopMargin: Dp = -                                    if (Flags.centralizedStatusBarHeightFix()) { -                                        largeScreenHeaderHelper.getLargeScreenHeaderHeight().dp -                                    } else { -                                        dimensionResource( -                                            id = R.dimen.large_screen_shade_header_height -                                        ) -                                    } -                                Notifications( -                                    burnInParams = burnIn.parameters, -                                    modifier = -                                        Modifier.fillMaxHeight() -                                            .weight(weight = 1f) -                                            .padding(top = splitShadeTopMargin) -                                ) -                            } -                        } - -                        if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { -                            with(ambientIndicationSectionOptional.get()) { -                                AmbientIndication(modifier = Modifier.fillMaxWidth()) -                            } -                        } -                    } - -                    with(lockSection) { LockIcon() } - -                    // Aligned to bottom and constrained to below the lock icon. -                    Column(modifier = Modifier.fillMaxWidth()) { -                        if (isUdfpsVisible && ambientIndicationSectionOptional.isPresent) { -                            with(ambientIndicationSectionOptional.get()) { -                                AmbientIndication(modifier = Modifier.fillMaxWidth()) -                            } -                        } - -                        with(bottomAreaSection) { -                            IndicationArea(modifier = Modifier.fillMaxWidth()) -                        } -                    } - -                    // Aligned to bottom and NOT constrained by the lock icon. -                    with(bottomAreaSection) { -                        Shortcut(isStart = true, applyPadding = true) -                        Shortcut(isStart = false, applyPadding = true) -                    } -                    with(settingsMenuSection) { SettingsMenu(onSettingsMenuPlaced) } -                }, -                modifier = Modifier.fillMaxSize(), -            ) { measurables, constraints -> -                check(measurables.size == 6) -                val aboveLockIconMeasurable = measurables[0] -                val lockIconMeasurable = measurables[1] -                val belowLockIconMeasurable = measurables[2] -                val startShortcutMeasurable = measurables[3] -                val endShortcutMeasurable = measurables[4] -                val settingsMenuMeasurable = measurables[5] - -                val noMinConstraints = -                    constraints.copy( -                        minWidth = 0, -                        minHeight = 0, -                    ) -                val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints) -                val lockIconBounds = -                    IntRect( -                        left = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Left], -                        top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top], -                        right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right], -                        bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom], -                    ) - -                val aboveLockIconPlaceable = -                    aboveLockIconMeasurable.measure( -                        noMinConstraints.copy(maxHeight = lockIconBounds.top) -                    ) -                val belowLockIconPlaceable = -                    belowLockIconMeasurable.measure( -                        noMinConstraints.copy( -                            maxHeight = -                                (constraints.maxHeight - lockIconBounds.bottom).coerceAtLeast(0) -                        ) -                    ) -                val startShortcutPleaceable = startShortcutMeasurable.measure(noMinConstraints) -                val endShortcutPleaceable = endShortcutMeasurable.measure(noMinConstraints) -                val settingsMenuPlaceable = settingsMenuMeasurable.measure(noMinConstraints) - -                layout(constraints.maxWidth, constraints.maxHeight) { -                    aboveLockIconPlaceable.place( -                        x = 0, -                        y = 0, -                    ) -                    lockIconPlaceable.place( -                        x = lockIconBounds.left, -                        y = lockIconBounds.top, -                    ) -                    belowLockIconPlaceable.place( -                        x = 0, -                        y = constraints.maxHeight - belowLockIconPlaceable.height, -                    ) -                    startShortcutPleaceable.place( -                        x = 0, -                        y = constraints.maxHeight - startShortcutPleaceable.height, -                    ) -                    endShortcutPleaceable.place( -                        x = constraints.maxWidth - endShortcutPleaceable.width, -                        y = constraints.maxHeight - endShortcutPleaceable.height, -                    ) -                    settingsMenuPlaceable.place( -                        x = (constraints.maxWidth - settingsMenuPlaceable.width) / 2, -                        y = constraints.maxHeight - settingsMenuPlaceable.height, -                    ) -                } -            } -        } -    } -} - -@Module -interface WeatherClockBlueprintModule { -    @Binds -    @IntoSet -    fun blueprint(blueprint: WeatherClockBlueprint): ComposableLockscreenSceneBlueprint -} - -@Module -interface SplitShadeWeatherClockBlueprintModule { -    @Binds -    @IntoSet -    fun blueprint(blueprint: SplitShadeWeatherClockBlueprint): ComposableLockscreenSceneBlueprint -} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt index 467dbca759c8..97d5b41000de 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/BottomAreaSection.kt @@ -32,7 +32,6 @@ import androidx.core.content.res.ResourcesCompat  import com.android.compose.animation.scene.ElementKey  import com.android.compose.animation.scene.SceneScope  import com.android.systemui.animation.view.LaunchableImageView -import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder  import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder  import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea @@ -44,7 +43,6 @@ import com.android.systemui.res.R  import com.android.systemui.statusbar.KeyguardIndicationController  import com.android.systemui.statusbar.VibratorHelper  import javax.inject.Inject -import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.DisposableHandle  import kotlinx.coroutines.flow.Flow @@ -56,7 +54,6 @@ constructor(      private val vibratorHelper: VibratorHelper,      private val indicationController: KeyguardIndicationController,      private val indicationAreaViewModel: KeyguardIndicationAreaViewModel, -    @Main private val mainImmediateDispatcher: CoroutineDispatcher,  ) {      /**       * Renders a single lockscreen shortcut. @@ -164,7 +161,6 @@ constructor(                          transitionAlpha,                          falsingManager,                          vibratorHelper, -                        mainImmediateDispatcher,                      ) {                          indicationController.showTransientIndication(it)                      } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt index 48684a02bd19..9f02201f1d81 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt @@ -34,7 +34,6 @@ import com.android.keyguard.LockIconView  import com.android.keyguard.LockIconViewController  import com.android.systemui.biometrics.AuthController  import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor  import com.android.systemui.flags.FeatureFlagsClassic  import com.android.systemui.flags.Flags @@ -51,14 +50,12 @@ import com.android.systemui.shade.NotificationPanelView  import com.android.systemui.statusbar.VibratorHelper  import dagger.Lazy  import javax.inject.Inject -import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.CoroutineScope  class LockSection  @Inject  constructor(      @Application private val applicationScope: CoroutineScope, -    @Main private val mainImmediateDispatcher: CoroutineDispatcher,      private val windowManager: WindowManager,      private val authController: AuthController,      private val featureFlags: FeatureFlagsClassic, @@ -96,7 +93,6 @@ constructor(                                  deviceEntryBackgroundViewModel.get(),                                  falsingManager.get(),                                  vibratorHelper.get(), -                                mainImmediateDispatcher,                              )                          }                      } else { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt index f8e63411ed52..0934b20562b4 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt @@ -16,9 +16,11 @@  package com.android.systemui.keyguard.ui.composable.section +import android.content.Context  import androidx.compose.foundation.layout.Column  import androidx.compose.foundation.layout.fillMaxSize  import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn  import androidx.compose.foundation.layout.offset  import androidx.compose.foundation.layout.wrapContentSize  import androidx.compose.runtime.Composable @@ -26,6 +28,10 @@ import androidx.compose.runtime.LaunchedEffect  import androidx.compose.runtime.collectAsState  import androidx.compose.runtime.getValue  import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.Dp  import androidx.compose.ui.unit.IntOffset  import com.android.compose.animation.scene.SceneScope  import com.android.compose.animation.scene.SceneTransitionLayout @@ -36,6 +42,7 @@ import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.smallCl  import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.splitShadeLargeClockScene  import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.splitShadeSmallClockScene  import com.android.systemui.keyguard.ui.composable.blueprint.ClockTransition +import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockScenes  import com.android.systemui.keyguard.ui.composable.blueprint.rememberBurnIn  import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel  import javax.inject.Inject @@ -47,6 +54,7 @@ constructor(      private val smartSpaceSection: SmartSpaceSection,      private val mediaCarouselSection: MediaCarouselSection,      private val clockSection: DefaultClockSection, +    private val weatherClockSection: WeatherClockSection,      private val clockInteractor: KeyguardClockInteractor,  ) {      @Composable @@ -64,6 +72,10 @@ constructor(                      splitShadeSmallClockScene                  KeyguardClockViewModel.ClockLayout.LARGE_CLOCK -> largeClockScene                  KeyguardClockViewModel.ClockLayout.SMALL_CLOCK -> smallClockScene +                KeyguardClockViewModel.ClockLayout.WEATHER_LARGE_CLOCK -> +                    WeatherClockScenes.largeClockScene +                KeyguardClockViewModel.ClockLayout.SPLIT_SHADE_WEATHER_LARGE_CLOCK -> +                    WeatherClockScenes.splitShadeLargeClockScene              }          SceneTransitionLayout( @@ -86,6 +98,12 @@ constructor(              scene(smallClockScene) { SmallClockWithSmartSpace() }              scene(largeClockScene) { LargeClockWithSmartSpace() } + +            scene(WeatherClockScenes.largeClockScene) { WeatherLargeClockWithSmartSpace() } + +            scene(WeatherClockScenes.splitShadeLargeClockScene) { +                WeatherLargeClockWithSmartSpace(modifier = Modifier.fillMaxWidth(0.5f)) +            }          }      } @@ -146,4 +164,50 @@ constructor(              }          }      } + +    @Composable +    private fun SceneScope.WeatherLargeClockWithSmartSpace(modifier: Modifier = Modifier) { +        val burnIn = rememberBurnIn(clockInteractor) +        val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsState() +        val currentClockState = clockViewModel.currentClock.collectAsState() + +        LaunchedEffect(isLargeClockVisible) { +            if (isLargeClockVisible) { +                burnIn.onSmallClockTopChanged(null) +            } +        } + +        Column(modifier = modifier) { +            val currentClock = currentClockState.value ?: return@Column +            with(weatherClockSection) { Time(clock = currentClock, modifier = Modifier) } +            val density = LocalDensity.current +            val context = LocalContext.current + +            with(smartSpaceSection) { +                SmartSpace( +                    burnInParams = burnIn.parameters, +                    onTopChanged = burnIn.onSmartspaceTopChanged, +                    modifier = +                        Modifier.heightIn( +                            min = getDimen(context, "enhanced_smartspace_height", density) +                        ) +                ) +            } +            with(weatherClockSection) { LargeClockSectionBelowSmartspace(clock = currentClock) } +        } +    } + +    /* +     * Use this function to access dimen which cannot be access by R.dimen directly +     * Currently use to access dimen from BcSmartspace +     * @param name Name of resources +     * @param density Density required to convert dimen from Int To Dp +     */ +    private fun getDimen(context: Context, name: String, density: Density): Dp { +        val res = context.packageManager.getResourcesForApplication(context.packageName) +        val id = res.getIdentifier(name, "dimen", context.packageName) +        var dimen: Dp +        with(density) { dimen = (if (id == 0) 0 else res.getDimensionPixelSize(id)).toDp() } +        return dimen +    }  } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt index d3584539b3fa..a7bb308ada5c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt @@ -16,6 +16,7 @@  package com.android.systemui.keyguard.ui.composable.section +import android.view.View  import android.view.ViewGroup  import androidx.compose.foundation.layout.Box  import androidx.compose.foundation.layout.IntrinsicSize @@ -27,18 +28,14 @@ import androidx.compose.foundation.layout.wrapContentSize  import androidx.compose.runtime.Composable  import androidx.compose.ui.Alignment  import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext  import androidx.compose.ui.res.dimensionResource  import androidx.compose.ui.viewinterop.AndroidView  import com.android.compose.animation.scene.ElementKey  import com.android.compose.animation.scene.SceneScope  import com.android.compose.modifiers.padding -import com.android.systemui.customization.R -import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.weatherSmallClockElementKey +import com.android.systemui.customization.R as customizationR  import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockElementKeys -import com.android.systemui.keyguard.ui.composable.modifier.burnInAware  import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel -import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters  import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel  import com.android.systemui.plugins.clocks.ClockController  import javax.inject.Inject @@ -55,12 +52,19 @@ constructor(          clock: ClockController,          modifier: Modifier = Modifier,      ) { -        WeatherElement( -            weatherClockElementViewId = R.id.weather_clock_time, -            clock = clock, -            elementKey = WeatherClockElementKeys.timeElementKey, -            modifier = modifier.wrapContentSize(), -        ) +        Row( +            modifier = +                Modifier.padding( +                    horizontal = dimensionResource(customizationR.dimen.clock_padding_start) +                ) +        ) { +            WeatherElement( +                weatherClockElementViewId = customizationR.id.weather_clock_time, +                clock = clock, +                elementKey = WeatherClockElementKeys.timeElementKey, +                modifier = modifier, +            ) +        }      }      @Composable @@ -69,7 +73,7 @@ constructor(          modifier: Modifier = Modifier,      ) {          WeatherElement( -            weatherClockElementViewId = R.id.weather_clock_date, +            weatherClockElementViewId = customizationR.id.weather_clock_date,              clock = clock,              elementKey = WeatherClockElementKeys.dateElementKey,              modifier = modifier, @@ -82,7 +86,7 @@ constructor(          modifier: Modifier = Modifier,      ) {          WeatherElement( -            weatherClockElementViewId = R.id.weather_clock_weather_icon, +            weatherClockElementViewId = customizationR.id.weather_clock_weather_icon,              clock = clock,              elementKey = WeatherClockElementKeys.weatherIconElementKey,              modifier = modifier.wrapContentSize(), @@ -95,7 +99,7 @@ constructor(          modifier: Modifier = Modifier,      ) {          WeatherElement( -            weatherClockElementViewId = R.id.weather_clock_alarm_dnd, +            weatherClockElementViewId = customizationR.id.weather_clock_alarm_dnd,              clock = clock,              elementKey = WeatherClockElementKeys.dndAlarmElementKey,              modifier = modifier.wrapContentSize(), @@ -108,7 +112,7 @@ constructor(          modifier: Modifier = Modifier,      ) {          WeatherElement( -            weatherClockElementViewId = R.id.weather_clock_temperature, +            weatherClockElementViewId = customizationR.id.weather_clock_temperature,              clock = clock,              elementKey = WeatherClockElementKeys.temperatureElementKey,              modifier = modifier.wrapContentSize(), @@ -126,12 +130,16 @@ constructor(              content {                  AndroidView(                      factory = { -                        val view = -                            clock.largeClock.layout.views.first { -                                it.id == weatherClockElementViewId -                            } -                        (view.parent as? ViewGroup)?.removeView(view) -                        view +                        try { +                            val view = +                                clock.largeClock.layout.views.first { +                                    it.id == weatherClockElementViewId +                                } +                            (view.parent as? ViewGroup)?.removeView(view) +                            view +                        } catch (e: NoSuchElementException) { +                            View(it) +                        }                      },                      update = {},                      modifier = modifier @@ -147,46 +155,22 @@ constructor(          Row(              modifier =                  Modifier.height(IntrinsicSize.Max) -                    .padding(horizontal = dimensionResource(R.dimen.clock_padding_start)) +                    .padding( +                        horizontal = dimensionResource(customizationR.dimen.clock_padding_start) +                    )          ) {              Date(clock = clock, modifier = Modifier.wrapContentSize()) -            Box(modifier = Modifier.fillMaxSize()) { +            Box( +                modifier = +                    Modifier.fillMaxSize() +                        .padding( +                            start = dimensionResource(customizationR.dimen.clock_padding_start) +                        ) +            ) {                  Weather(clock = clock, modifier = Modifier.align(Alignment.TopStart))                  Temperature(clock = clock, modifier = Modifier.align(Alignment.BottomEnd))                  DndAlarmStatus(clock = clock, modifier = Modifier.align(Alignment.TopEnd))              }          }      } - -    @Composable -    fun SceneScope.SmallClock( -        burnInParams: BurnInParameters, -        modifier: Modifier = Modifier, -        clock: ClockController, -    ) { -        val localContext = LocalContext.current -        MovableElement(key = weatherSmallClockElementKey, modifier) { -            content { -                AndroidView( -                    factory = { -                        val view = clock.smallClock.view -                        if (view.parent != null) { -                            (view.parent as? ViewGroup)?.removeView(view) -                        } -                        view -                    }, -                    modifier = -                        modifier -                            .height(dimensionResource(R.dimen.small_clock_height)) -                            .padding(start = dimensionResource(R.dimen.clock_padding_start)) -                            .padding(top = { viewModel.getSmallClockTopMargin(localContext) }) -                            .burnInAware( -                                viewModel = aodBurnInViewModel, -                                params = burnInParams, -                            ), -                    update = {}, -                ) -            } -        } -    }  } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/AncModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/AncModule.kt index ccb5d367c357..fa052e8e3035 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/AncModule.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/AncModule.kt @@ -17,15 +17,12 @@  package com.android.systemui.volume.panel.component.anc  import com.android.systemui.volume.panel.component.anc.domain.AncAvailabilityCriteria -import com.android.systemui.volume.panel.component.anc.ui.composable.AncPopup -import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel -import com.android.systemui.volume.panel.component.button.ui.composable.ButtonComponent +import com.android.systemui.volume.panel.component.anc.ui.composable.AncButtonComponent  import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents  import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria  import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent  import dagger.Binds  import dagger.Module -import dagger.Provides  import dagger.multibindings.IntoMap  import dagger.multibindings.StringKey @@ -40,14 +37,8 @@ interface AncModule {          criteria: AncAvailabilityCriteria      ): ComponentAvailabilityCriteria -    companion object { - -        @Provides -        @IntoMap -        @StringKey(VolumePanelComponents.ANC) -        fun provideVolumePanelUiComponent( -            viewModel: AncViewModel, -            popup: AncPopup, -        ): VolumePanelUiComponent = ButtonComponent(viewModel.button, popup::show) -    } +    @Binds +    @IntoMap +    @StringKey(VolumePanelComponents.ANC) +    fun bindVolumePanelUiComponent(component: AncButtonComponent): VolumePanelUiComponent  } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt new file mode 100644 index 000000000000..00225fc3577a --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.volume.panel.component.anc.ui.composable + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import com.android.systemui.res.R +import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel +import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent +import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope +import javax.inject.Inject + +class AncButtonComponent +@Inject +constructor( +    private val viewModel: AncViewModel, +    private val ancPopup: AncPopup, +) : ComposeVolumePanelUiComponent { + +    @Composable +    override fun VolumePanelComposeScope.Content(modifier: Modifier) { +        val slice by viewModel.buttonSlice.collectAsState() +        val label = stringResource(R.string.volume_panel_noise_control_title) +        Column( +            modifier = modifier, +            verticalArrangement = Arrangement.spacedBy(12.dp), +            horizontalAlignment = Alignment.CenterHorizontally, +        ) { +            SliceAndroidView( +                modifier = +                    Modifier.height(64.dp) +                        .fillMaxWidth() +                        .semantics { +                            role = Role.Button +                            contentDescription = label +                        } +                        .clip(RoundedCornerShape(28.dp)), +                slice = slice, +                onWidthChanged = viewModel::onButtonSliceWidthChanged, +                onClick = { ancPopup.show(null) } +            ) +            Text( +                modifier = Modifier.clearAndSetSemantics {}, +                text = label, +                style = MaterialTheme.typography.labelMedium, +                maxLines = 1, +                overflow = TextOverflow.Ellipsis, +            ) +        } +    } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt index 9f0da004730d..e1ee01e78566 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt @@ -16,9 +16,6 @@  package com.android.systemui.volume.panel.component.anc.ui.composable -import android.content.Context -import android.view.ContextThemeWrapper -import android.view.View  import androidx.compose.foundation.basicMarquee  import androidx.compose.foundation.layout.fillMaxWidth  import androidx.compose.material3.MaterialTheme @@ -30,14 +27,14 @@ import androidx.compose.runtime.getValue  import androidx.compose.ui.Modifier  import androidx.compose.ui.res.stringResource  import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.viewinterop.AndroidView  import androidx.slice.Slice -import androidx.slice.widget.SliceView +import com.android.internal.logging.UiEventLogger  import com.android.systemui.animation.Expandable  import com.android.systemui.res.R  import com.android.systemui.statusbar.phone.SystemUIDialog  import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel  import com.android.systemui.volume.panel.component.popup.ui.composable.VolumePanelPopup +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent  import javax.inject.Inject  /** ANC popup up displaying ANC control [Slice]. */ @@ -46,10 +43,12 @@ class AncPopup  constructor(      private val volumePanelPopup: VolumePanelPopup,      private val viewModel: AncViewModel, +    private val uiEventLogger: UiEventLogger,  ) {      /** Shows a popup with the [expandable] animation. */ -    fun show(expandable: Expandable) { +    fun show(expandable: Expandable?) { +        uiEventLogger.log(VolumePanelUiEvent.VOLUME_PANEL_ANC_POPUP_SHOWN)          volumePanelPopup.show(expandable, { Title() }, { Content(it) })      } @@ -66,49 +65,18 @@ constructor(      @Composable      private fun Content(dialog: SystemUIDialog) { -        val slice: Slice? by viewModel.slice.collectAsState() +        val isAvailable by viewModel.isAvailable.collectAsState(true) -        if (slice == null) { +        if (!isAvailable) {              SideEffect { dialog.dismiss() }              return          } -        AndroidView<SliceView>( +        val slice by viewModel.popupSlice.collectAsState() +        SliceAndroidView(              modifier = Modifier.fillMaxWidth(), -            factory = { context: Context -> -                SliceView(ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel)) -                    .apply { -                        mode = SliceView.MODE_LARGE -                        isScrollable = false -                        importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO -                        setShowTitleItems(true) -                        addOnLayoutChangeListener( -                            OnWidthChangedLayoutListener(viewModel::changeSliceWidth) -                        ) -                    } -            }, -            update = { sliceView: SliceView -> sliceView.slice = slice } +            slice = slice, +            onWidthChanged = viewModel::onPopupSliceWidthChanged          )      } - -    private class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) : -        View.OnLayoutChangeListener { -        override fun onLayoutChange( -            v: View?, -            left: Int, -            top: Int, -            right: Int, -            bottom: Int, -            oldLeft: Int, -            oldTop: Int, -            oldRight: Int, -            oldBottom: Int -        ) { -            val newWidth = right - left -            val oldWidth = oldRight - oldLeft -            if (oldWidth != newWidth) { -                widthChanged(newWidth) -            } -        } -    }  } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt new file mode 100644 index 000000000000..f354b80692f5 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/SliceAndroidView.kt @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.volume.panel.component.anc.ui.composable + +import android.annotation.SuppressLint +import android.content.Context +import android.view.ContextThemeWrapper +import android.view.MotionEvent +import android.view.View +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.viewinterop.AndroidView +import androidx.slice.Slice +import androidx.slice.widget.SliceView +import com.android.systemui.res.R + +@Composable +fun SliceAndroidView( +    slice: Slice?, +    modifier: Modifier = Modifier, +    onWidthChanged: ((Int) -> Unit)? = null, +    onClick: (() -> Unit)? = null, +) { +    AndroidView( +        modifier = modifier, +        factory = { context: Context -> +            ClickableSliceView( +                    ContextThemeWrapper(context, R.style.Widget_SliceView_VolumePanel), +                    onClick, +                ) +                .apply { +                    mode = SliceView.MODE_LARGE +                    isScrollable = false +                    importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO +                    setShowTitleItems(true) +                    if (onWidthChanged != null) { +                        addOnLayoutChangeListener(OnWidthChangedLayoutListener(onWidthChanged)) +                    } +                    if (onClick != null) { +                        setOnClickListener { onClick() } +                    } +                } +        }, +        update = { sliceView: SliceView -> sliceView.slice = slice } +    ) +} + +class OnWidthChangedLayoutListener(private val widthChanged: (Int) -> Unit) : +    View.OnLayoutChangeListener { + +    override fun onLayoutChange( +        v: View?, +        left: Int, +        top: Int, +        right: Int, +        bottom: Int, +        oldLeft: Int, +        oldTop: Int, +        oldRight: Int, +        oldBottom: Int +    ) { +        val newWidth = right - left +        val oldWidth = oldRight - oldLeft +        if (oldWidth != newWidth) { +            widthChanged(newWidth) +        } +    } +} + +/** + * [SliceView] that prioritises [onClick] when its clicked instead of passing the event to the slice + * first. + */ +@SuppressLint("ViewConstructor") // only used in this class +private class ClickableSliceView( +    context: Context, +    private val onClick: (() -> Unit)?, +) : SliceView(context) { + +    init { +        if (onClick != null) { +            setOnClickListener {} +        } +    } + +    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { +        return onClick != null || super.onInterceptTouchEvent(ev) +    } + +    override fun onClick(v: View?) { +        onClick?.let { it() } ?: super.onClick(v) +    } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt index fc511e12ec54..e15d315f9a0a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt @@ -69,9 +69,9 @@ class ButtonComponent(                              role = Role.Button                              contentDescription = label                          }, -                    color = MaterialTheme.colorScheme.primaryContainer, +                    color = MaterialTheme.colorScheme.tertiaryContainer,                      shape = RoundedCornerShape(28.dp), -                    contentColor = MaterialTheme.colorScheme.onPrimaryContainer, +                    contentColor = MaterialTheme.colorScheme.onTertiaryContainer,                      onClick = onClick,                  ) {                      Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt index 780e3f2de4c8..b2351c492fc1 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt @@ -66,8 +66,8 @@ class ToggleButtonComponent(                  val colors =                      if (viewModel.isChecked) {                          ButtonDefaults.buttonColors( -                            containerColor = MaterialTheme.colorScheme.primaryContainer, -                            contentColor = MaterialTheme.colorScheme.onPrimaryContainer, +                            containerColor = MaterialTheme.colorScheme.tertiaryContainer, +                            contentColor = MaterialTheme.colorScheme.onTertiaryContainer,                          )                      } else {                          ButtonDefaults.buttonColors( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt index 9f9bc623a6b3..b489dfc2e39b 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt @@ -59,7 +59,7 @@ constructor(       * @param content is the popup body       */      fun show( -        expandable: Expandable, +        expandable: Expandable?,          title: @Composable (SystemUIDialog) -> Unit,          content: @Composable (SystemUIDialog) -> Unit,      ) { @@ -70,7 +70,7 @@ constructor(              ) {                  PopupComposable(it, title, content)              } -        val controller = expandable.dialogTransitionController() +        val controller = expandable?.dialogTransitionController()          if (controller == null) {              dialog.show()          } else { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt index c74331477229..51e206470389 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/selector/ui/composable/VolumePanelRadioButtons.kt @@ -30,9 +30,11 @@ import androidx.compose.foundation.layout.offset  import androidx.compose.foundation.layout.padding  import androidx.compose.foundation.shape.CornerSize  import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.LocalContentColor  import androidx.compose.material3.MaterialTheme  import androidx.compose.material3.TextButton  import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider  import androidx.compose.runtime.remember  import androidx.compose.runtime.rememberCoroutineScope  import androidx.compose.ui.Alignment @@ -119,6 +121,7 @@ fun VolumePanelRadioButtonBar(              ) {                  for (itemIndex in items.indices) {                      val item = items[itemIndex] +                    val isSelected = itemIndex == scope.selectedIndex                      Row(                          modifier =                              Modifier.height(48.dp) @@ -126,7 +129,7 @@ fun VolumePanelRadioButtonBar(                                  .semantics {                                      item.contentDescription?.let { contentDescription = it }                                      role = Role.Switch -                                    selected = itemIndex == scope.selectedIndex +                                    selected = isSelected                                  }                                  .clickable(                                      interactionSource = null, @@ -137,7 +140,11 @@ fun VolumePanelRadioButtonBar(                          verticalAlignment = Alignment.CenterVertically,                      ) {                          if (item.icon !== Empty) { -                            with(items[itemIndex]) { icon() } +                            CompositionLocalProvider( +                                LocalContentColor provides colors.getIconColor(isSelected) +                            ) { +                                with(items[itemIndex]) { icon() } +                            }                          }                      }                  } @@ -163,7 +170,10 @@ fun VolumePanelRadioButtonBar(                      ) {                          val item = items[itemIndex]                          if (item.icon !== Empty) { -                            with(items[itemIndex]) { label() } +                            val textColor = colors.getLabelColor(itemIndex == scope.selectedIndex) +                            CompositionLocalProvider(LocalContentColor provides textColor) { +                                with(items[itemIndex]) { label() } +                            }                          }                      }                  } @@ -265,8 +275,22 @@ data class VolumePanelRadioButtonBarColors(      val indicatorColor: Color,      /** Color of the indicator background. */      val indicatorBackgroundColor: Color, +    /** Color of the icon. */ +    val iconColor: Color, +    /** Color of the icon when it's selected. */ +    val selectedIconColor: Color, +    /** Color of the label. */ +    val labelColor: Color, +    /** Color of the label when it's selected. */ +    val selectedLabelColor: Color,  ) +private fun VolumePanelRadioButtonBarColors.getIconColor(selected: Boolean): Color = +    if (selected) selectedIconColor else iconColor + +private fun VolumePanelRadioButtonBarColors.getLabelColor(selected: Boolean): Color = +    if (selected) selectedLabelColor else labelColor +  object VolumePanelRadioButtonBarDefaults {      val DefaultIndicatorBackgroundPadding = 8.dp @@ -283,12 +307,20 @@ object VolumePanelRadioButtonBarDefaults {       */      @Composable      fun defaultColors( -        indicatorColor: Color = MaterialTheme.colorScheme.primaryContainer, +        indicatorColor: Color = MaterialTheme.colorScheme.tertiaryContainer,          indicatorBackgroundColor: Color = MaterialTheme.colorScheme.surface, +        iconColor: Color = MaterialTheme.colorScheme.onSurfaceVariant, +        selectedIconColor: Color = MaterialTheme.colorScheme.onTertiaryContainer, +        labelColor: Color = MaterialTheme.colorScheme.onSurfaceVariant, +        selectedLabelColor: Color = MaterialTheme.colorScheme.onSurface,      ): VolumePanelRadioButtonBarColors =          VolumePanelRadioButtonBarColors(              indicatorColor = indicatorColor,              indicatorBackgroundColor = indicatorBackgroundColor, +            iconColor = iconColor, +            selectedIconColor = selectedIconColor, +            labelColor = labelColor, +            selectedLabelColor = selectedLabelColor,          )  } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt index eed54dab6faf..f377fa6276a0 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt @@ -17,6 +17,7 @@  package com.android.systemui.volume.panel.component.spatialaudio.ui.composable  import androidx.compose.foundation.basicMarquee +import androidx.compose.material3.LocalContentColor  import androidx.compose.material3.MaterialTheme  import androidx.compose.material3.Text  import androidx.compose.runtime.Composable @@ -26,14 +27,15 @@ import androidx.compose.runtime.getValue  import androidx.compose.ui.Modifier  import androidx.compose.ui.res.stringResource  import androidx.compose.ui.text.style.TextAlign +import com.android.internal.logging.UiEventLogger  import com.android.systemui.animation.Expandable  import com.android.systemui.common.ui.compose.Icon -import com.android.systemui.common.ui.compose.toColor  import com.android.systemui.res.R  import com.android.systemui.statusbar.phone.SystemUIDialog  import com.android.systemui.volume.panel.component.popup.ui.composable.VolumePanelPopup  import com.android.systemui.volume.panel.component.selector.ui.composable.VolumePanelRadioButtonBar  import com.android.systemui.volume.panel.component.spatial.ui.viewmodel.SpatialAudioViewModel +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent  import javax.inject.Inject  class SpatialAudioPopup @@ -41,10 +43,17 @@ class SpatialAudioPopup  constructor(      private val viewModel: SpatialAudioViewModel,      private val volumePanelPopup: VolumePanelPopup, +    private val uiEventLogger: UiEventLogger,  ) {      /** Shows a popup with the [expandable] animation. */      fun show(expandable: Expandable) { +        uiEventLogger.logWithPosition( +            VolumePanelUiEvent.VOLUME_PANEL_SPATIAL_AUDIO_POP_UP_SHOWN, +            0, +            null, +            viewModel.spatialAudioButtons.value.indexOfFirst { it.button.isChecked } +        )          volumePanelPopup.show(expandable, { Title() }, { Content(it) })      } @@ -79,18 +88,13 @@ constructor(                      isSelected = buttonViewModel.button.isChecked,                      onItemSelected = { viewModel.setEnabled(buttonViewModel.model) },                      contentDescription = label, -                    icon = { -                        Icon( -                            icon = buttonViewModel.button.icon, -                            tint = buttonViewModel.iconColor.toColor(), -                        ) -                    }, +                    icon = { Icon(icon = buttonViewModel.button.icon) },                      label = {                          Text(                              modifier = Modifier.basicMarquee(),                              text = label,                              style = MaterialTheme.typography.labelMedium, -                            color = buttonViewModel.labelColor.toColor(), +                            color = LocalContentColor.current,                              textAlign = TextAlign.Center,                              maxLines = 2                          ) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt index f89669c8456c..a3467f2ab78e 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt @@ -85,6 +85,7 @@ fun ColumnVolumeSliders(                  onValueChange = { newValue: Float ->                      sliderViewModel.onValueChanged(sliderState, newValue)                  }, +                onValueChangeFinished = { sliderViewModel.onValueChangeFinished() },                  onIconTapped = { sliderViewModel.toggleMuted(sliderState) },                  sliderColors = sliderColors,              ) @@ -106,7 +107,7 @@ fun ColumnVolumeSliders(              }          }          transition.AnimatedVisibility( -            visible = { it }, +            visible = { it || !isExpandable },              enter =                  expandVertically(animationSpec = tween(durationMillis = EXPAND_DURATION_MILLIS)),              exit = @@ -121,7 +122,7 @@ fun ColumnVolumeSliders(                          val sliderState by sliderViewModel.slider.collectAsState()                          transition.AnimatedVisibility(                              modifier = Modifier.padding(top = 16.dp), -                            visible = { it }, +                            visible = { it || !isExpandable },                              enter = enterTransition(index = index, totalCount = viewModels.size),                              exit = exitTransition(index = index, totalCount = viewModels.size)                          ) { @@ -131,6 +132,7 @@ fun ColumnVolumeSliders(                                  onValueChange = { newValue: Float ->                                      sliderViewModel.onValueChanged(sliderState, newValue)                                  }, +                                onValueChangeFinished = { sliderViewModel.onValueChangeFinished() },                                  onIconTapped = { sliderViewModel.toggleMuted(sliderState) },                                  sliderColors = sliderColors,                              ) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt index b284c691ef0e..bb17499f021f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt @@ -46,6 +46,7 @@ fun GridVolumeSliders(                  onValueChange = { newValue: Float ->                      sliderViewModel.onValueChanged(sliderState, newValue)                  }, +                onValueChangeFinished = { sliderViewModel.onValueChangeFinished() },                  onIconTapped = { sliderViewModel.toggleMuted(sliderState) },                  sliderColors = sliderColors,              ) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt index 19d3f599ef31..228d29259038 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt @@ -16,13 +16,15 @@  package com.android.systemui.volume.panel.component.volume.ui.composable +import androidx.compose.animation.AnimatedVisibility  import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut  import androidx.compose.foundation.clickable  import androidx.compose.foundation.layout.Box  import androidx.compose.foundation.layout.fillMaxSize  import androidx.compose.foundation.layout.size -import androidx.compose.material3.LocalContentColor -import androidx.compose.material3.Text  import androidx.compose.runtime.Composable  import androidx.compose.runtime.State  import androidx.compose.runtime.getValue @@ -49,6 +51,7 @@ import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.Sl  fun VolumeSlider(      state: SliderState,      onValueChange: (newValue: Float) -> Unit, +    onValueChangeFinished: (() -> Unit)? = null,      onIconTapped: () -> Unit,      modifier: Modifier = Modifier,      sliderColors: PlatformSliderColors, @@ -83,28 +86,31 @@ fun VolumeSlider(          value = value,          valueRange = state.valueRange,          onValueChange = onValueChange, +        onValueChangeFinished = onValueChangeFinished,          enabled = state.isEnabled, -        icon = { isDragging -> -            if (isDragging) { -                Text(text = state.valueText, color = LocalContentColor.current) -            } else { -                state.icon?.let { -                    SliderIcon( -                        icon = it, -                        onIconTapped = onIconTapped, -                        isTappable = state.isMutable, -                    ) -                } +        icon = { +            state.icon?.let { +                SliderIcon( +                    icon = it, +                    onIconTapped = onIconTapped, +                    isTappable = state.isMutable, +                )              }          },          colors = sliderColors, -        label = { -            VolumeSliderContent( -                modifier = Modifier, -                label = state.label, -                isEnabled = state.isEnabled, -                disabledMessage = state.disabledMessage, -            ) +        label = { isDragging -> +            AnimatedVisibility( +                visible = !isDragging, +                enter = fadeIn(tween(150)), +                exit = fadeOut(tween(150)), +            ) { +                VolumeSliderContent( +                    modifier = Modifier, +                    label = state.label, +                    isEnabled = state.isEnabled, +                    disabledMessage = state.disabledMessage, +                ) +            }          }      )  } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt index b1cfdcf07977..dbec059715b4 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt @@ -204,15 +204,16 @@ internal class SceneTransitionLayoutImpl(                      }                  // Handle back events. -                // TODO(b/290184746): Make sure that this works with SystemUI once we use -                // SceneTransitionLayout in Flexiglass. -                scene(state.transitionState.currentScene).userActions[Back]?.let { result -> -                    // TODO(b/290184746): Handle predictive back and use result.distance if -                    // specified. -                    BackHandler { -                        val targetScene = result.toScene -                        if (state.canChangeScene(targetScene)) { -                            with(state) { coroutineScope.onChangeScene(targetScene) } +                val targetSceneForBackOrNull = +                    scene(state.transitionState.currentScene).userActions[Back]?.toScene +                BackHandler( +                    enabled = targetSceneForBackOrNull != null, +                ) { +                    targetSceneForBackOrNull?.let { targetSceneForBack -> +                        // TODO(b/290184746): Handle predictive back and use result.distance if +                        // specified. +                        if (state.canChangeScene(targetSceneForBack)) { +                            with(state) { coroutineScope.onChangeScene(targetSceneForBack) }                          }                      }                  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt index 1120914fec7c..2d4b63ef2c27 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt @@ -66,6 +66,7 @@ import com.android.systemui.res.R  import com.android.systemui.scene.domain.interactor.SceneInteractor  import com.android.systemui.scene.domain.interactor.sceneInteractor  import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags +import com.android.systemui.scene.shared.flag.sceneContainerFlags  import com.android.systemui.scene.shared.model.FakeSceneDataSource  import com.android.systemui.scene.shared.model.Scenes  import com.android.systemui.scene.shared.model.fakeSceneDataSource @@ -209,7 +210,6 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {          val keyguardKeyboardInteractor = KeyguardKeyboardInteractor(FakeKeyboardRepository())          featureFlags = FakeFeatureFlags() -        featureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)          featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false)          mSetFlagsRule.enableFlags( @@ -217,7 +217,8 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {          )          mSetFlagsRule.disableFlags(              FLAG_SIDEFPS_CONTROLLER_REFACTOR, -            AConfigFlags.FLAG_KEYGUARD_WM_STATE_REFACTOR +            AConfigFlags.FLAG_KEYGUARD_WM_STATE_REFACTOR, +            AConfigFlags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT,          )          keyguardPasswordViewController = @@ -267,7 +268,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {                  falsingManager,                  userSwitcherController,                  featureFlags, -                kosmos.fakeSceneContainerFlags, +                kosmos.sceneContainerFlags,                  globalSettings,                  sessionTracker,                  Optional.of(sideFpsController), diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt index 4950b96b077f..85774c67bccb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -537,4 +537,65 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {                  assertThat(lp.height).isEqualTo(overlayParams.sensorBounds.height())              }          } + +    @Test +    fun addViewPending_layoutIsNotUpdated() = +        testScope.runTest { +            withReasonSuspend(REASON_AUTH_KEYGUARD) { +                mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE) +                mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR) + +                // GIVEN going to sleep +                keyguardTransitionRepository.sendTransitionSteps( +                    from = KeyguardState.OFF, +                    to = KeyguardState.GONE, +                    testScope = this, +                ) +                powerRepository.updateWakefulness( +                    rawState = WakefulnessState.STARTING_TO_SLEEP, +                    lastWakeReason = WakeSleepReason.POWER_BUTTON, +                    lastSleepReason = WakeSleepReason.OTHER, +                ) +                runCurrent() + +                // WHEN a request comes to show the view +                controllerOverlay.show(udfpsController, overlayParams) +                runCurrent() + +                // THEN the view does not get added immediately +                verify(windowManager, never()).addView(any(), any()) + +                // WHEN updateOverlayParams gets called when the view is pending to be added +                controllerOverlay.updateOverlayParams(overlayParams) + +                // THEN the view layout is never updated +                verify(windowManager, never()).updateViewLayout(any(), any()) + +                // CLEANUPL we hide to end the job that listens for the finishedGoingToSleep signal +                controllerOverlay.hide() +            } +        } + +    @Test +    fun updateOverlayParams_viewLayoutUpdated() = +        testScope.runTest { +            withReasonSuspend(REASON_AUTH_KEYGUARD) { +                mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE) +                powerRepository.updateWakefulness( +                    rawState = WakefulnessState.AWAKE, +                    lastWakeReason = WakeSleepReason.POWER_BUTTON, +                    lastSleepReason = WakeSleepReason.OTHER, +                ) +                runCurrent() +                controllerOverlay.show(udfpsController, overlayParams) +                runCurrent() +                verify(windowManager).addView(any(), any()) + +                // WHEN updateOverlayParams gets called +                controllerOverlay.updateOverlayParams(overlayParams) + +                // THEN the view layout is updated +                verify(windowManager, never()).updateViewLayout(any(), any()) +            } +        }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt index 3afca96e07a0..0db0e0767767 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt @@ -18,6 +18,10 @@ package com.android.systemui.bouncer.ui.viewmodel  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.Back +import com.android.compose.animation.scene.Swipe +import com.android.compose.animation.scene.SwipeDirection +import com.android.compose.animation.scene.UserActionResult  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository  import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository @@ -34,7 +38,10 @@ import com.android.systemui.flags.Flags  import com.android.systemui.flags.fakeFeatureFlagsClassic  import com.android.systemui.kosmos.testScope  import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags +import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.scene.shared.model.fakeSceneDataSource  import com.android.systemui.testKosmos +import com.android.systemui.truth.containsEntriesExactly  import com.google.common.truth.Truth.assertThat  import com.google.common.truth.Truth.assertWithMessage  import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -193,6 +200,23 @@ class BouncerViewModelTest : SysuiTestCase() {              assertThat(isFoldSplitRequired).isTrue()          } +    @Test +    fun destinationScenes() = +        testScope.runTest { +            val destinationScenes by collectLastValue(underTest.destinationScenes) +            kosmos.fakeSceneDataSource.changeScene(Scenes.QuickSettings) +            runCurrent() + +            kosmos.fakeSceneDataSource.changeScene(Scenes.Bouncer) +            runCurrent() + +            assertThat(destinationScenes) +                .containsEntriesExactly( +                    Back to UserActionResult(Scenes.QuickSettings), +                    Swipe(SwipeDirection.Down) to UserActionResult(Scenes.QuickSettings), +                ) +        } +      private fun authMethodsToTest(): List<AuthenticationMethodModel> {          return listOf(None, Pin, Password, Pattern, Sim)      } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt index 5bb36a0acbdf..256687b56f4e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt @@ -389,6 +389,61 @@ class PinBouncerViewModelTest : SysuiTestCase() {              assertThat(isAnimationEnabled).isTrue()          } +    @Test +    fun onPinButtonClicked_whenInputSameLengthAsHintedPin_ignoresClick() = +        testScope.runTest { +            val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) +            kosmos.fakeAuthenticationRepository.setAutoConfirmFeatureEnabled(true) +            val hintedPinLength by collectLastValue(underTest.hintedPinLength) +            assertThat(hintedPinLength).isEqualTo(FakeAuthenticationRepository.HINTING_PIN_LENGTH) +            lockDeviceAndOpenPinBouncer() + +            repeat(FakeAuthenticationRepository.HINTING_PIN_LENGTH - 1) { repetition -> +                underTest.onPinButtonClicked(repetition + 1) +                runCurrent() +            } +            kosmos.fakeAuthenticationRepository.pauseCredentialChecking() +            // If credential checking were not paused, this would check the credentials and succeed. +            underTest.onPinButtonClicked(FakeAuthenticationRepository.HINTING_PIN_LENGTH) +            runCurrent() + +            // This one should be ignored because the user has already entered a number of digits +            // that's equal to the length of the hinting PIN length. It should result in a PIN +            // that's exactly the same length as the hinting PIN length. +            underTest.onPinButtonClicked(FakeAuthenticationRepository.HINTING_PIN_LENGTH + 1) +            runCurrent() + +            assertThat(pin) +                .isEqualTo( +                    buildList { +                        repeat(FakeAuthenticationRepository.HINTING_PIN_LENGTH) { index -> +                            add(index + 1) +                        } +                    } +                ) + +            kosmos.fakeAuthenticationRepository.unpauseCredentialChecking() +            runCurrent() +            assertThat(pin).isEmpty() +        } + +    @Test +    fun onPinButtonClicked_whenPinNotHinted_doesNotIgnoreClick() = +        testScope.runTest { +            val pin by collectLastValue(underTest.pinInput.map { it.getPin() }) +            kosmos.fakeAuthenticationRepository.setAutoConfirmFeatureEnabled(false) +            val hintedPinLength by collectLastValue(underTest.hintedPinLength) +            assertThat(hintedPinLength).isNull() +            lockDeviceAndOpenPinBouncer() + +            repeat(FakeAuthenticationRepository.HINTING_PIN_LENGTH + 1) { repetition -> +                underTest.onPinButtonClicked(repetition + 1) +                runCurrent() +            } + +            assertThat(pin).hasSize(FakeAuthenticationRepository.HINTING_PIN_LENGTH + 1) +        } +      private fun TestScope.switchToScene(toScene: SceneKey) {          val currentScene by collectLastValue(sceneInteractor.currentScene)          val bouncerHidden = currentScene == Scenes.Bouncer && toScene != Scenes.Bouncer diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt index a944afb70f38..76f15d2ed257 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt @@ -120,19 +120,20 @@ class CommunalSceneStartableTest : SysuiTestCase() {          }      @Test -    fun exitingDream_forceCommunalScene() = +    fun occluded_forceBlankScene() =          with(kosmos) {              testScope.runTest {                  val scene by collectLastValue(communalInteractor.desiredScene) -                assertThat(scene).isEqualTo(CommunalScenes.Blank) +                communalInteractor.changeScene(CommunalScenes.Communal) +                assertThat(scene).isEqualTo(CommunalScenes.Communal)                  updateDocked(true)                  fakeKeyguardTransitionRepository.sendTransitionSteps( -                    from = KeyguardState.DREAMING, -                    to = KeyguardState.LOCKSCREEN, +                    from = KeyguardState.GLANCEABLE_HUB, +                    to = KeyguardState.OCCLUDED,                      testScope = this                  ) -                assertThat(scene).isEqualTo(CommunalScenes.Communal) +                assertThat(scene).isEqualTo(CommunalScenes.Blank)              }          } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt index f71121c43ff8..ce7b60e86f8f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt @@ -23,6 +23,7 @@ import android.app.admin.devicePolicyManager  import android.appwidget.AppWidgetProviderInfo  import android.content.Intent  import android.content.pm.UserInfo +import android.os.UserManager.USER_TYPE_PROFILE_MANAGED  import android.platform.test.annotations.DisableFlags  import android.platform.test.annotations.EnableFlags  import android.provider.Settings @@ -59,6 +60,7 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() {          kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)          setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_FEATURES_NONE)          setKeyguardFeaturesDisabled(SECONDARY_USER, KEYGUARD_DISABLE_FEATURES_NONE) +        setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_FEATURES_NONE)          underTest = kosmos.communalSettingsRepository      } @@ -133,6 +135,30 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() {      @EnableFlags(FLAG_COMMUNAL_HUB)      @Test +    fun widgetsAllowedForWorkProfile_isFalse_whenDisallowedByDevicePolicy() = +        testScope.runTest { +            val widgetsAllowedForWorkProfile by +                collectLastValue(underTest.getAllowedByDevicePolicy(WORK_PROFILE)) +            assertThat(widgetsAllowedForWorkProfile).isTrue() + +            setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_WIDGETS_ALL) +            assertThat(widgetsAllowedForWorkProfile).isFalse() +        } + +    @EnableFlags(FLAG_COMMUNAL_HUB) +    @Test +    fun hubIsEnabled_whenDisallowedByDevicePolicyForWorkProfile() = +        testScope.runTest { +            val enabledStateForPrimaryUser by +                collectLastValue(underTest.getEnabledState(PRIMARY_USER)) +            assertThat(enabledStateForPrimaryUser?.enabled).isTrue() + +            setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_WIDGETS_ALL) +            assertThat(enabledStateForPrimaryUser?.enabled).isTrue() +        } + +    @EnableFlags(FLAG_COMMUNAL_HUB) +    @Test      fun hubIsDisabledByUserAndDevicePolicy() =          testScope.runTest {              val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) @@ -189,5 +215,13 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() {          val PRIMARY_USER =              UserInfo(/* id= */ 0, /* name= */ "primary user", /* flags= */ UserInfo.FLAG_MAIN)          val SECONDARY_USER = UserInfo(/* id= */ 1, /* name= */ "secondary user", /* flags= */ 0) +        val WORK_PROFILE = +            UserInfo( +                10, +                "work", +                /* iconPath= */ "", +                /* flags= */ 0, +                USER_TYPE_PROFILE_MANAGED, +            )      }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt index e7ccde26e161..f21e9697c91f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt @@ -17,6 +17,8 @@  package com.android.systemui.communal.domain.interactor +import android.app.admin.DevicePolicyManager +import android.app.admin.devicePolicyManager  import android.app.smartspace.SmartspaceTarget  import android.appwidget.AppWidgetProviderInfo  import android.content.Intent @@ -32,6 +34,7 @@ import androidx.test.filters.SmallTest  import com.android.compose.animation.scene.ObservableTransitionState  import com.android.systemui.Flags.FLAG_COMMUNAL_HUB  import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.broadcastDispatcher  import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl  import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository  import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository @@ -71,6 +74,7 @@ import com.android.systemui.util.mockito.any  import com.android.systemui.util.mockito.argumentCaptor  import com.android.systemui.util.mockito.capture  import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.nullable  import com.android.systemui.util.mockito.whenever  import com.android.systemui.util.settings.fakeSettings  import com.google.common.truth.Truth.assertThat @@ -929,7 +933,6 @@ class CommunalInteractorTest : SysuiTestCase() {              keyguardRepository.setKeyguardShowing(true)              keyguardRepository.setKeyguardOccluded(false)              tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) -            userRepository.setSelectedUserInfo(mainUser)              val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)              userRepository.setUserInfos(userInfos) @@ -937,6 +940,7 @@ class CommunalInteractorTest : SysuiTestCase() {                  userInfos = userInfos,                  selectedUserIndex = 0,              ) +            userRepository.setSelectedUserInfo(MAIN_USER_INFO)              runCurrent()              // Widgets available. @@ -955,7 +959,6 @@ class CommunalInteractorTest : SysuiTestCase() {                  AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,                  mainUser.id              ) -            runCurrent()              // Only the keyguard widget is enabled.              assertThat(widgetContent).hasSize(3) @@ -974,7 +977,6 @@ class CommunalInteractorTest : SysuiTestCase() {              keyguardRepository.setKeyguardShowing(true)              keyguardRepository.setKeyguardOccluded(false)              tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) -            userRepository.setSelectedUserInfo(mainUser)              val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)              userRepository.setUserInfos(userInfos) @@ -982,6 +984,7 @@ class CommunalInteractorTest : SysuiTestCase() {                  userInfos = userInfos,                  selectedUserIndex = 0,              ) +            userRepository.setSelectedUserInfo(MAIN_USER_INFO)              runCurrent()              // Widgets available. @@ -1001,7 +1004,6 @@ class CommunalInteractorTest : SysuiTestCase() {                      AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,                  mainUser.id              ) -            runCurrent()              // All widgets are enabled.              assertThat(widgetContent).hasSize(3) @@ -1011,6 +1013,79 @@ class CommunalInteractorTest : SysuiTestCase() {              }          } +    @Test +    fun filterWidgets_whenDisallowedByDevicePolicyForWorkProfile() = +        testScope.runTest { +            // Keyguard showing, and tutorial completed. +            keyguardRepository.setKeyguardShowing(true) +            keyguardRepository.setKeyguardOccluded(false) +            tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + +            val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) +            userRepository.setUserInfos(userInfos) +            userTracker.set( +                userInfos = userInfos, +                selectedUserIndex = 0, +            ) +            userRepository.setSelectedUserInfo(MAIN_USER_INFO) +            runCurrent() + +            val widgetContent by collectLastValue(underTest.widgetContent) +            // Given three widgets, and one of them is associated with work profile. +            val widget1 = createWidgetForUser(1, USER_INFO_WORK.id) +            val widget2 = createWidgetForUser(2, MAIN_USER_INFO.id) +            val widget3 = createWidgetForUser(3, MAIN_USER_INFO.id) +            val widgets = listOf(widget1, widget2, widget3) +            widgetRepository.setCommunalWidgets(widgets) + +            setKeyguardFeaturesDisabled( +                USER_INFO_WORK, +                DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL +            ) + +            // Widget under work profile is filtered out and the remaining two link to main user id. +            assertThat(widgetContent).hasSize(2) +            widgetContent!!.forEach { model -> +                assertThat(model.providerInfo.profile?.identifier).isEqualTo(MAIN_USER_INFO.id) +            } +        } + +    @Test +    fun filterWidgets_whenAllowedByDevicePolicyForWorkProfile() = +        testScope.runTest { +            // Keyguard showing, and tutorial completed. +            keyguardRepository.setKeyguardShowing(true) +            keyguardRepository.setKeyguardOccluded(false) +            tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + +            val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) +            userRepository.setUserInfos(userInfos) +            userTracker.set( +                userInfos = userInfos, +                selectedUserIndex = 0, +            ) +            userRepository.setSelectedUserInfo(MAIN_USER_INFO) +            runCurrent() + +            val widgetContent by collectLastValue(underTest.widgetContent) +            // Given three widgets, and one of them is associated with work profile. +            val widget1 = createWidgetForUser(1, USER_INFO_WORK.id) +            val widget2 = createWidgetForUser(2, MAIN_USER_INFO.id) +            val widget3 = createWidgetForUser(3, MAIN_USER_INFO.id) +            val widgets = listOf(widget1, widget2, widget3) +            widgetRepository.setCommunalWidgets(widgets) + +            setKeyguardFeaturesDisabled( +                USER_INFO_WORK, +                DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE +            ) + +            // Widget under work profile is available. +            assertThat(widgetContent).hasSize(3) +            assertThat(widgetContent!![0].providerInfo.profile?.identifier) +                .isEqualTo(USER_INFO_WORK.id) +        } +      private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget {          val timer = mock(SmartspaceTarget::class.java)          whenever(timer.smartspaceTargetId).thenReturn(id) @@ -1020,6 +1095,15 @@ class CommunalInteractorTest : SysuiTestCase() {          return timer      } +    private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) { +        whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id))) +            .thenReturn(disabledFlags) +        kosmos.broadcastDispatcher.sendIntentToMatchingReceiversOnly( +            context, +            Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), +        ) +    } +      private fun createWidgetForUser(appWidgetId: Int, userId: Int): CommunalWidgetContentModel =          mock<CommunalWidgetContentModel> {              whenever(this.appWidgetId).thenReturn(appWidgetId) @@ -1044,6 +1128,13 @@ class CommunalInteractorTest : SysuiTestCase() {      private companion object {          val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN) -        val USER_INFO_WORK = UserInfo(10, "work", UserInfo.FLAG_PROFILE) +        val USER_INFO_WORK = +            UserInfo( +                10, +                "work", +                /* iconPath= */ "", +                /* flags= */ 0, +                UserManager.USER_TYPE_PROFILE_MANAGED, +            )      }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index 9a13bb261aa7..6b2a1d59e62d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -32,7 +32,6 @@ import android.hardware.face.FaceManager  import android.hardware.face.FaceSensorProperties  import android.hardware.face.FaceSensorPropertiesInternal  import android.os.CancellationSignal -import android.view.Display  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.internal.logging.InstanceId.fakeInstanceId @@ -54,7 +53,6 @@ import com.android.systemui.deviceentry.shared.model.FaceAuthenticationStatus  import com.android.systemui.deviceentry.shared.model.FaceDetectionStatus  import com.android.systemui.deviceentry.shared.model.HelpFaceAuthenticationStatus  import com.android.systemui.deviceentry.shared.model.SuccessFaceAuthenticationStatus -import com.android.systemui.display.data.repository.display  import com.android.systemui.display.data.repository.displayRepository  import com.android.systemui.dump.DumpManager  import com.android.systemui.flags.FakeFeatureFlags @@ -68,6 +66,7 @@ import com.android.systemui.keyguard.data.repository.fakeTrustRepository  import com.android.systemui.keyguard.domain.interactor.keyguardInteractor  import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor  import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.StatusBarState  import com.android.systemui.keyguard.shared.model.TransitionState  import com.android.systemui.keyguard.shared.model.TransitionStep  import com.android.systemui.kosmos.testDispatcher @@ -697,9 +696,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {              )              runCurrent() -            displayRepository.emit(setOf(display(0, 0, Display.DEFAULT_DISPLAY, Display.STATE_OFF))) -            displayRepository.emitDisplayChangeEvent(Display.DEFAULT_DISPLAY) - +            displayRepository.setDefaultDisplayOff(true)              runCurrent()              assertThat(canFaceAuthRun()).isTrue() @@ -717,10 +714,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {                  )                  runCurrent() -                displayRepository.emit( -                    setOf(display(0, 0, Display.DEFAULT_DISPLAY, Display.STATE_OFF)) -                ) -                displayRepository.emitDisplayChangeEvent(Display.DEFAULT_DISPLAY) +                displayRepository.setDefaultDisplayOff(true)              }          } @@ -827,13 +821,14 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {          }      @Test -    fun isAuthenticatedIsResetToFalseWhenTransitioningToGone() = +    fun isAuthenticatedIsResetToFalseWhenFinishedTransitioningToGoneAndStatusBarStateShade() =          testScope.runTest {              initCollectors()              allPreconditionsToRunFaceAuthAreTrue()              triggerFaceAuth(false) +            keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)              authenticationCallback.value.onAuthenticationSucceeded(                  mock(FaceManager.AuthenticationResult::class.java)              ) @@ -847,7 +842,16 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {                      to = KeyguardState.GONE,                  )              ) +            keyguardTransitionRepository.sendTransitionStep( +                TransitionStep( +                    transitionState = TransitionState.FINISHED, +                    from = KeyguardState.LOCKSCREEN, +                    to = KeyguardState.GONE, +                ) +            ) +            assertThat(authenticated()).isTrue() +            keyguardRepository.setStatusBarState(StatusBarState.SHADE)              assertThat(authenticated()).isFalse()          } @@ -1167,8 +1171,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {          faceLockoutResetCallback.value.onLockoutReset(0)          bouncerRepository.setAlternateVisible(true)          keyguardRepository.setKeyguardShowing(true) -        displayRepository.emit(setOf(display(0, 0, Display.DEFAULT_DISPLAY, Display.STATE_ON))) -        displayRepository.emitDisplayChangeEvent(Display.DEFAULT_DISPLAY) +        displayRepository.setDefaultDisplayOff(false)          keyguardTransitionRepository.sendTransitionSteps(              from = KeyguardState.AOD,              to = KeyguardState.LOCKSCREEN, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java index 315a24bfd945..a43415869580 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java @@ -16,6 +16,8 @@  package com.android.systemui.dreams.complication; +import static com.android.systemui.Flags.FLAG_REMOVE_DREAM_OVERLAY_HIDE_ON_TOUCH; +  import static org.mockito.ArgumentMatchers.anyInt;  import static org.mockito.ArgumentMatchers.eq;  import static org.mockito.Mockito.never; @@ -23,6 +25,8 @@ import static org.mockito.Mockito.verify;  import static org.mockito.Mockito.when;  import android.os.Handler; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags;  import android.view.MotionEvent;  import android.view.View; @@ -90,6 +94,7 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase {       * Ensures no actions are taken when there multiple sessions.       */      @Test +    @DisableFlags(FLAG_REMOVE_DREAM_OVERLAY_HIDE_ON_TOUCH)      public void testSessionEndOnMultipleSessions() {          final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(                  mVisibilityController, @@ -122,6 +127,7 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase {       * Ensures no actions are taken when the bouncer is showing.       */      @Test +    @DisableFlags(FLAG_REMOVE_DREAM_OVERLAY_HIDE_ON_TOUCH)      public void testSessionEndWhenBouncerShowing() {          final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(                  mVisibilityController, @@ -154,6 +160,7 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase {       * Ensures no actions are taken when there multiple sessions.       */      @Test +    @DisableFlags(FLAG_REMOVE_DREAM_OVERLAY_HIDE_ON_TOUCH)      public void testSessionEndWithTouchInInset() {          final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(                  mVisibilityController, @@ -202,6 +209,7 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase {       * Make sure visibility changes are triggered from session events.       */      @Test +    @DisableFlags(FLAG_REMOVE_DREAM_OVERLAY_HIDE_ON_TOUCH)      public void testSessionLifecycle() {          final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(                  mVisibilityController, @@ -259,4 +267,34 @@ public class HideComplicationTouchHandlerTest extends SysuiTestCase {          // Verify session ended.          verify(mSession).pop();      } + +    @Test +    @EnableFlags(FLAG_REMOVE_DREAM_OVERLAY_HIDE_ON_TOUCH) +    public void testNoActionWhenDisabledByFlag() { +        final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler( +                mVisibilityController, +                RESTORE_TIMEOUT, +                HIDE_DELAY, +                mTouchInsetManager, +                mStatusBarKeyguardViewManager, +                mFakeExecutor, +                mStateController); + +        // Report one session. +        when(mSession.getActiveSessionCount()).thenReturn(1); + +        // Bouncer is showing. +        when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false); + +        // Start session. +        touchHandler.onSessionStart(mSession); + +        // Verify session end. +        verify(mSession).pop(); + +        mClock.advanceTime(HIDE_DELAY); + +        // Verify no interaction with visibility controller. +        verify(mVisibilityController, never()).setVisibility(anyInt()); +    }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java index 0f8fc3824e3f..9f52ae9a7406 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java @@ -31,6 +31,8 @@ import android.animation.ValueAnimator;  import android.content.pm.UserInfo;  import android.graphics.Rect;  import android.graphics.Region; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags;  import android.view.GestureDetector;  import android.view.GestureDetector.OnGestureListener;  import android.view.MotionEvent; @@ -41,6 +43,7 @@ import androidx.test.filters.SmallTest;  import com.android.internal.logging.UiEventLogger;  import com.android.internal.widget.LockPatternUtils; +import com.android.systemui.Flags;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;  import com.android.systemui.dreams.touch.scrim.ScrimController; @@ -277,6 +280,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {      /**       * Makes sure swiping up when bouncer initially showing doesn't change the expansion amount.       */ +    @DisableFlags(Flags.FLAG_DREAM_OVERLAY_BOUNCER_SWIPE_DIRECTION_FILTERING)      @Test      public void testSwipeUp_whenBouncerInitiallyShowing_doesNotSetExpansion() {          when(mCentralSurfaces.isBouncerShowing()).thenReturn(true); @@ -297,8 +301,36 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {          final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,                  0, 0, 0); -        assertThat(gestureListener.onScroll(event1, event2, 0, distanceY)) -                .isTrue(); +        assertThat(gestureListener.onScroll(event1, event2, 0, distanceY)).isTrue(); + +        verify(mScrimController, never()).expand(any()); +    } + +    /** +     * Makes sure swiping up when bouncer initially showing doesn't change the expansion amount. +     */ +    @Test +    @EnableFlags(Flags.FLAG_DREAM_OVERLAY_BOUNCER_SWIPE_DIRECTION_FILTERING) +    public void testSwipeUp_whenBouncerInitiallyShowing_doesNotSetExpansion_directionFiltering() { +        when(mCentralSurfaces.isBouncerShowing()).thenReturn(true); + +        mTouchHandler.onSessionStart(mTouchSession); +        ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor = +                ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); +        verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); + +        final OnGestureListener gestureListener = gestureListenerCaptor.getValue(); + +        final float percent = .3f; +        final float distanceY = SCREEN_HEIGHT_PX * percent; + +        // Swiping up near the top of the screen where the touch initiation region is. +        final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, +                0, distanceY, 0); +        final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, +                0, 0, 0); + +        assertThat(gestureListener.onScroll(event1, event2, 0, distanceY)).isFalse();          verify(mScrimController, never()).expand(any());      } @@ -307,6 +339,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {       * Makes sure swiping down when bouncer initially hidden doesn't change the expansion amount.       */      @Test +    @DisableFlags(Flags.FLAG_DREAM_OVERLAY_BOUNCER_SWIPE_DIRECTION_FILTERING)      public void testSwipeDown_whenBouncerInitiallyHidden_doesNotSetExpansion() {          mTouchHandler.onSessionStart(mTouchSession);          ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor = @@ -324,8 +357,34 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {          final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,                  0, SCREEN_HEIGHT_PX, 0); -        assertThat(gestureListener.onScroll(event1, event2, 0, distanceY)) -                .isTrue(); +        assertThat(gestureListener.onScroll(event1, event2, 0, -distanceY)).isTrue(); + +        verify(mScrimController, never()).expand(any()); +    } + +    /** +     * Makes sure swiping down when bouncer initially hidden doesn't change the expansion amount. +     */ +    @Test +    @EnableFlags(Flags.FLAG_DREAM_OVERLAY_BOUNCER_SWIPE_DIRECTION_FILTERING) +    public void testSwipeDown_whenBouncerInitiallyHidden_doesNotSetExpansion_directionFiltering() { +        mTouchHandler.onSessionStart(mTouchSession); +        ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor = +                ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); +        verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); + +        final OnGestureListener gestureListener = gestureListenerCaptor.getValue(); + +        final float percent = .15f; +        final float distanceY = SCREEN_HEIGHT_PX * percent; + +        // Swiping down near the bottom of the screen where the touch initiation region is. +        final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, +                0, SCREEN_HEIGHT_PX - distanceY, 0); +        final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, +                0, SCREEN_HEIGHT_PX, 0); + +        assertThat(gestureListener.onScroll(event1, event2, 0, -distanceY)).isFalse();          verify(mScrimController, never()).expand(any());      } @@ -444,7 +503,8 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {                  0, direction == Direction.UP ? SCREEN_HEIGHT_PX - distanceY : distanceY, 0);          reset(mScrimController); -        assertThat(gestureListener.onScroll(event1, event2, 0, distanceY)) +        assertThat(gestureListener.onScroll(event1, event2, 0, +                direction == Direction.UP ? distanceY : -distanceY))                  .isTrue();          // Ensure only called once @@ -643,7 +703,8 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {          final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,                  0, direction == Direction.UP ? SCREEN_HEIGHT_PX - distanceY : distanceY, 0); -        assertThat(gestureListenerCaptor.getValue().onScroll(event1, event2, 0, distanceY)) +        assertThat(gestureListenerCaptor.getValue().onScroll(event1, event2, 0, +                direction == Direction.UP ? distanceY : -distanceY))                  .isTrue();          final MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt index 8f03717b42f2..3889703e74c4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/qs/QSLongPressEffectTest.kt @@ -26,39 +26,34 @@ import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.animation.AnimatorTestRule  import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.haptics.vibratorHelper +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.kosmos.backgroundCoroutineContext  import com.android.systemui.kosmos.testScope -import com.android.systemui.statusbar.VibratorHelper  import com.android.systemui.testKosmos -import com.android.systemui.util.mockito.whenever  import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.UnconfinedTestDispatcher -import kotlinx.coroutines.test.advanceTimeBy  import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Rule  import org.junit.Test  import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.any  import org.mockito.Mock -import org.mockito.Mockito.never -import org.mockito.Mockito.verify  import org.mockito.junit.MockitoJUnit  import org.mockito.junit.MockitoRule  @SmallTest  @RunWith(AndroidJUnit4::class) -@OptIn(ExperimentalCoroutinesApi::class)  @RunWithLooper(setAsMainLooper = true)  class QSLongPressEffectTest : SysuiTestCase() {      @Rule @JvmField val mMockitoRule: MockitoRule = MockitoJUnit.rule() -    @Mock private lateinit var vibratorHelper: VibratorHelper      @Mock private lateinit var testView: View      @get:Rule val animatorTestRule = AnimatorTestRule(this)      private val kosmos = testKosmos() +    private val vibratorHelper = kosmos.vibratorHelper      private val effectDuration = 400      private val lowTickDuration = 12 @@ -68,19 +63,71 @@ class QSLongPressEffectTest : SysuiTestCase() {      @Before      fun setup() { -        whenever( -                vibratorHelper.getPrimitiveDurations( -                    VibrationEffect.Composition.PRIMITIVE_LOW_TICK, -                    VibrationEffect.Composition.PRIMITIVE_SPIN, -                ) -            ) -            .thenReturn(intArrayOf(lowTickDuration, spinDuration)) +        vibratorHelper.primitiveDurations[VibrationEffect.Composition.PRIMITIVE_LOW_TICK] = +            lowTickDuration +        vibratorHelper.primitiveDurations[VibrationEffect.Composition.PRIMITIVE_SPIN] = spinDuration + +        kosmos.fakeKeyguardRepository.setKeyguardDismissible(true)          longPressEffect =              QSLongPressEffect(                  vibratorHelper, -                effectDuration, +                kosmos.keyguardInteractor, +                CoroutineScope(kosmos.backgroundCoroutineContext),              ) +        longPressEffect.initializeEffect(effectDuration) +    } + +    @Test +    fun onReset_whileIdle_resetsEffect() = testWithScope { +        // GIVEN a call to reset +        longPressEffect.resetEffect() + +        // THEN the effect remains idle and has not been initialized +        val state by collectLastValue(longPressEffect.state) +        assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE) +        assertThat(longPressEffect.hasInitialized).isFalse() +    } + +    @Test +    fun onReset_whileRunning_resetsEffect() = testWhileRunning { +        // GIVEN a call to reset +        longPressEffect.resetEffect() + +        // THEN the effect remains idle and has not been initialized +        val state by collectLastValue(longPressEffect.state) +        assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE) +        assertThat(longPressEffect.hasInitialized).isFalse() +    } + +    @Test +    fun onInitialize_withNegativeDuration_doesNotInitialize() = testWithScope { +        // GIVEN an effect that has reset +        longPressEffect.resetEffect() + +        // WHEN attempting to initialize with a negative duration +        val couldInitialize = longPressEffect.initializeEffect(-1) + +        // THEN the effect can't initialized and remains reset +        val state by collectLastValue(longPressEffect.state) +        assertThat(couldInitialize).isFalse() +        assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE) +        assertThat(longPressEffect.hasInitialized).isFalse() +    } + +    @Test +    fun onInitialize_withPositiveDuration_initializes() = testWithScope { +        // GIVEN an effect that has reset +        longPressEffect.resetEffect() + +        // WHEN attempting to initialize with a positive duration +        val couldInitialize = longPressEffect.initializeEffect(effectDuration) + +        // THEN the effect is initialized +        val state by collectLastValue(longPressEffect.state) +        assertThat(couldInitialize).isTrue() +        assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE) +        assertThat(longPressEffect.hasInitialized).isTrue()      }      @Test @@ -90,7 +137,8 @@ class QSLongPressEffectTest : SysuiTestCase() {          longPressEffect.onTouch(testView, downEvent)          // THEN the effect moves to the TIMEOUT_WAIT state -        assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.TIMEOUT_WAIT) +        val state by collectLastValue(longPressEffect.state) +        assertThat(state).isEqualTo(QSLongPressEffect.State.TIMEOUT_WAIT)      }      @Test @@ -100,7 +148,8 @@ class QSLongPressEffectTest : SysuiTestCase() {          longPressEffect.onTouch(testView, cancelEvent)          // THEN the effect goes back to idle and does not start -        assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE) +        val state by collectLastValue(longPressEffect.state) +        assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE)          assertEffectDidNotStart()      } @@ -121,7 +170,7 @@ class QSLongPressEffectTest : SysuiTestCase() {      @Test      fun onWaitComplete_whileWaiting_beginsEffect() = testWhileWaiting {          // GIVEN the pressed timeout is complete -        advanceTimeBy(QSLongPressEffect.PRESSED_TIMEOUT + 10L) +        longPressEffect.handleTimeoutComplete()          // THEN the effect starts          assertEffectStarted() @@ -154,15 +203,28 @@ class QSLongPressEffectTest : SysuiTestCase() {      }      @Test -    fun onAnimationComplete_effectEnds() = testWhileRunning { +    fun onAnimationComplete_keyguardDismissible_effectEndsWithLongPress() = testWhileRunning {          // GIVEN that the animation completes          animatorTestRule.advanceTimeBy(effectDuration + 10L) -        // THEN the long-press effect completes -        assertEffectCompleted() +        // THEN the long-press effect completes with a LONG_PRESS +        assertEffectCompleted(QSLongPressEffect.ActionType.LONG_PRESS)      }      @Test +    fun onAnimationComplete_keyguardNotDismissible_effectEndsWithResetAndLongPress() = +        testWhileRunning { +            // GIVEN that the keyguard is not dismissible +            kosmos.fakeKeyguardRepository.setKeyguardDismissible(false) + +            // GIVEN that the animation completes +            animatorTestRule.advanceTimeBy(effectDuration + 10L) + +            // THEN the long-press effect completes with RESET_AND_LONG_PRESS +            assertEffectCompleted(QSLongPressEffect.ActionType.RESET_AND_LONG_PRESS) +        } + +    @Test      fun onActionDown_whileRunningBackwards_resets() = testWhileRunning {          // GIVEN that the effect is at the middle of its completion (progress of 50%)          animatorTestRule.advanceTimeBy(effectDuration / 2L) @@ -192,33 +254,21 @@ class QSLongPressEffectTest : SysuiTestCase() {          animatorTestRule.advanceTimeBy(effectDuration.toLong())          // THEN the state goes to [QSLongPressEffect.State.IDLE] -        assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE) +        val state by collectLastValue(longPressEffect.state) +        assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE)      }      private fun buildMotionEvent(action: Int): MotionEvent =          MotionEventBuilder.newBuilder().setAction(action).build()      private fun testWithScope(test: suspend TestScope.() -> Unit) = -        with(kosmos) { -            testScope.runTest { -                // GIVEN an effect with a testing scope -                longPressEffect.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler)) - -                // THEN run the test -                test() -            } -        } +        with(kosmos) { testScope.runTest { test() } }      private fun testWhileWaiting(test: suspend TestScope.() -> Unit) =          with(kosmos) {              testScope.runTest { -                // GIVEN an effect with a testing scope -                longPressEffect.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler)) -                  // GIVEN the TIMEOUT_WAIT state is entered -                val downEvent = -                    MotionEventBuilder.newBuilder().setAction(MotionEvent.ACTION_DOWN).build() -                longPressEffect.onTouch(testView, downEvent) +                longPressEffect.setState(QSLongPressEffect.State.TIMEOUT_WAIT)                  // THEN run the test                  test() @@ -228,16 +278,9 @@ class QSLongPressEffectTest : SysuiTestCase() {      private fun testWhileRunning(test: suspend TestScope.() -> Unit) =          with(kosmos) {              testScope.runTest { -                // GIVEN an effect with a testing scope -                longPressEffect.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler)) - -                // GIVEN the down event that enters the TIMEOUT_WAIT state -                val downEvent = -                    MotionEventBuilder.newBuilder().setAction(MotionEvent.ACTION_DOWN).build() -                longPressEffect.onTouch(testView, downEvent) - -                // GIVEN that the timeout completes and the effect starts -                advanceTimeBy(QSLongPressEffect.PRESSED_TIMEOUT + 10L) +                // GIVEN that the effect starts after the tap timeout is complete +                longPressEffect.setState(QSLongPressEffect.State.TIMEOUT_WAIT) +                longPressEffect.handleTimeoutComplete()                  // THEN run the test                  test() @@ -252,6 +295,7 @@ class QSLongPressEffectTest : SysuiTestCase() {       */      private fun TestScope.assertEffectStarted() {          val effectProgress by collectLastValue(longPressEffect.effectProgress) +        val state by collectLastValue(longPressEffect.state)          val longPressHint =              LongPressHapticBuilder.createLongPressHint(                  lowTickDuration, @@ -259,10 +303,10 @@ class QSLongPressEffectTest : SysuiTestCase() {                  effectDuration,              ) -        assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.RUNNING_FORWARD) +        assertThat(state).isEqualTo(QSLongPressEffect.State.RUNNING_FORWARD)          assertThat(effectProgress).isEqualTo(0f)          assertThat(longPressHint).isNotNull() -        verify(vibratorHelper).vibrate(longPressHint!!) +        assertThat(vibratorHelper.hasVibratedWithEffects(longPressHint!!)).isTrue()      }      /** @@ -274,11 +318,12 @@ class QSLongPressEffectTest : SysuiTestCase() {       */      private fun TestScope.assertEffectDidNotStart() {          val effectProgress by collectLastValue(longPressEffect.effectProgress) +        val state by collectLastValue(longPressEffect.state) -        assertThat(longPressEffect.state).isNotEqualTo(QSLongPressEffect.State.RUNNING_FORWARD) -        assertThat(longPressEffect.state).isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS) +        assertThat(state).isNotEqualTo(QSLongPressEffect.State.RUNNING_FORWARD) +        assertThat(state).isNotEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS)          assertThat(effectProgress).isNull() -        verify(vibratorHelper, never()).vibrate(any(/* type= */ VibrationEffect::class.java)) +        assertThat(vibratorHelper.totalVibrations).isEqualTo(0)      }      /** @@ -286,18 +331,19 @@ class QSLongPressEffectTest : SysuiTestCase() {       * 1. The progress is null       * 2. The final snap haptics are played       * 3. The internal state goes back to [QSLongPressEffect.State.IDLE] -     * 4. The action to perform on the tile is the long-press action +     * 4. The action to perform on the tile is the action given as a parameter       */ -    private fun TestScope.assertEffectCompleted() { +    private fun TestScope.assertEffectCompleted(expectedAction: QSLongPressEffect.ActionType) {          val action by collectLastValue(longPressEffect.actionType)          val effectProgress by collectLastValue(longPressEffect.effectProgress)          val snapEffect = LongPressHapticBuilder.createSnapEffect() +        val state by collectLastValue(longPressEffect.state)          assertThat(effectProgress).isNull()          assertThat(snapEffect).isNotNull() -        verify(vibratorHelper).vibrate(snapEffect!!) -        assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.IDLE) -        assertThat(action).isEqualTo(QSLongPressEffect.ActionType.LONG_PRESS) +        assertThat(vibratorHelper.hasVibratedWithEffects(snapEffect!!)).isTrue() +        assertThat(state).isEqualTo(QSLongPressEffect.State.IDLE) +        assertThat(action).isEqualTo(expectedAction)      }      /** @@ -305,17 +351,18 @@ class QSLongPressEffectTest : SysuiTestCase() {       * 1. The internal state is [QSLongPressEffect.State.RUNNING_BACKWARDS]       * 2. The reverse haptics plays at the point where the animation was paused       */ -    private fun assertEffectReverses(pausedProgress: Float) { +    private fun TestScope.assertEffectReverses(pausedProgress: Float) {          val reverseHaptics =              LongPressHapticBuilder.createReversedEffect(                  pausedProgress,                  lowTickDuration,                  effectDuration,              ) +        val state by collectLastValue(longPressEffect.state) -        assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS) +        assertThat(state).isEqualTo(QSLongPressEffect.State.RUNNING_BACKWARDS)          assertThat(reverseHaptics).isNotNull() -        verify(vibratorHelper).vibrate(reverseHaptics!!) +        assertThat(vibratorHelper.hasVibratedWithEffects(reverseHaptics!!)).isTrue()      }      /** @@ -325,8 +372,9 @@ class QSLongPressEffectTest : SysuiTestCase() {       */      private fun TestScope.assertEffectResets() {          val effectProgress by collectLastValue(longPressEffect.effectProgress) -        assertThat(effectProgress).isEqualTo(0f) +        val state by collectLastValue(longPressEffect.state) -        assertThat(longPressEffect.state).isEqualTo(QSLongPressEffect.State.TIMEOUT_WAIT) +        assertThat(effectProgress).isNull() +        assertThat(state).isEqualTo(QSLongPressEffect.State.TIMEOUT_WAIT)      }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt new file mode 100644 index 000000000000..c88e432d15d2 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorTest.kt @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.keyguard.domain.interactor + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.keyguard.KeyguardClockSwitch.LARGE +import com.android.keyguard.KeyguardClockSwitch.SMALL +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.flags.EnableSceneContainer +import com.android.systemui.flags.Flags +import com.android.systemui.flags.fakeFeatureFlagsClassic +import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.data.repository.keyguardClockRepository +import com.android.systemui.keyguard.data.repository.keyguardRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.media.controls.data.repository.mediaFilterRepository +import com.android.systemui.media.controls.shared.model.MediaData +import com.android.systemui.shade.data.repository.shadeRepository +import com.android.systemui.shade.shared.model.ShadeMode +import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository +import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs +import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class KeyguardClockInteractorTest : SysuiTestCase() { +    private lateinit var kosmos: Kosmos +    private lateinit var underTest: KeyguardClockInteractor +    private lateinit var testScope: TestScope + +    @Before +    fun setup() { +        kosmos = testKosmos() +        testScope = kosmos.testScope +        underTest = kosmos.keyguardClockInteractor +    } + +    @Test +    @DisableSceneContainer +    fun clockSize_sceneContainerFlagOff_basedOnRepository() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockSize) +            kosmos.keyguardClockRepository.setClockSize(LARGE) +            assertThat(value).isEqualTo(LARGE) + +            kosmos.keyguardClockRepository.setClockSize(SMALL) +            assertThat(value).isEqualTo(SMALL) +        } + +    @Test +    @DisableSceneContainer +    fun clockShouldBeCentered_sceneContainerFlagOff_basedOnRepository() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockShouldBeCentered) +            kosmos.keyguardInteractor.setClockShouldBeCentered(true) +            assertThat(value).isEqualTo(true) + +            kosmos.keyguardInteractor.setClockShouldBeCentered(false) +            assertThat(value).isEqualTo(false) +        } + +    @Test +    @EnableSceneContainer +    fun clockSize_forceSmallClock_SMALL() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockSize) +            kosmos.fakeKeyguardClockRepository.setShouldForceSmallClock(true) +            kosmos.fakeFeatureFlagsClassic.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, true) +            transitionTo(KeyguardState.AOD, KeyguardState.LOCKSCREEN) +            assertThat(value).isEqualTo(SMALL) +        } + +    @Test +    @EnableSceneContainer +    fun clockSize_SceneContainerFlagOn_shadeModeSingle_hasNotifs_SMALL() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockSize) +            kosmos.shadeRepository.setShadeMode(ShadeMode.Single) +            kosmos.activeNotificationListRepository.setActiveNotifs(1) +            assertThat(value).isEqualTo(SMALL) +        } + +    @Test +    @EnableSceneContainer +    fun clockSize_SceneContainerFlagOn_shadeModeSingle_hasMedia_SMALL() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockSize) +            kosmos.shadeRepository.setShadeMode(ShadeMode.Single) +            val userMedia = MediaData().copy(active = true) +            kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia) +            assertThat(value).isEqualTo(SMALL) +        } + +    @Test +    @EnableSceneContainer +    fun clockSize_SceneContainerFlagOn_shadeModeSplit_isMediaVisible_SMALL() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockSize) +            val userMedia = MediaData().copy(active = true) +            kosmos.shadeRepository.setShadeMode(ShadeMode.Split) +            kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia) +            kosmos.keyguardRepository.setIsDozing(false) +            assertThat(value).isEqualTo(SMALL) +        } + +    @Test +    @EnableSceneContainer +    fun clockSize_SceneContainerFlagOn_shadeModeSplit_noMedia_LARGE() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockSize) +            kosmos.shadeRepository.setShadeMode(ShadeMode.Split) +            kosmos.keyguardRepository.setIsDozing(false) +            assertThat(value).isEqualTo(LARGE) +        } + +    @Test +    @EnableSceneContainer +    fun clockSize_SceneContainerFlagOn_shadeModeSplit_isDozing_LARGE() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockSize) +            val userMedia = MediaData().copy(active = true) +            kosmos.shadeRepository.setShadeMode(ShadeMode.Split) +            kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia) +            kosmos.keyguardRepository.setIsDozing(true) +            assertThat(value).isEqualTo(LARGE) +        } + +    @Test +    @EnableSceneContainer +    fun clockShouldBeCentered_sceneContainerFlagOn_notSplitMode_true() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockShouldBeCentered) +            kosmos.shadeRepository.setShadeMode(ShadeMode.Single) +            assertThat(value).isEqualTo(true) +        } + +    @Test +    @EnableSceneContainer +    fun clockShouldBeCentered_sceneContainerFlagOn_splitMode_noActiveNotifications_true() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockShouldBeCentered) +            kosmos.shadeRepository.setShadeMode(ShadeMode.Split) +            kosmos.activeNotificationListRepository.setActiveNotifs(0) +            assertThat(value).isEqualTo(true) +        } + +    @Test +    @EnableSceneContainer +    fun clockShouldBeCentered_sceneContainerFlagOn_splitMode_isActiveDreamLockscreenHosted_true() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockShouldBeCentered) +            kosmos.shadeRepository.setShadeMode(ShadeMode.Split) +            kosmos.activeNotificationListRepository.setActiveNotifs(1) +            kosmos.keyguardRepository.setIsActiveDreamLockscreenHosted(true) +            assertThat(value).isEqualTo(true) +        } + +    @Test +    @EnableSceneContainer +    fun clockShouldBeCentered_sceneContainerFlagOn_splitMode_hasPulsingNotifications_false() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockShouldBeCentered) +            kosmos.shadeRepository.setShadeMode(ShadeMode.Split) +            kosmos.activeNotificationListRepository.setActiveNotifs(1) +            kosmos.headsUpNotificationRepository.isHeadsUpAnimatingAway.value = true +            kosmos.keyguardRepository.setIsDozing(true) +            assertThat(value).isEqualTo(false) +        } + +    @Test +    @EnableSceneContainer +    fun clockShouldBeCentered_sceneContainerFlagOn_splitMode_onAod_true() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockShouldBeCentered) +            kosmos.shadeRepository.setShadeMode(ShadeMode.Split) +            kosmos.activeNotificationListRepository.setActiveNotifs(1) +            transitionTo(KeyguardState.LOCKSCREEN, KeyguardState.AOD) +            assertThat(value).isEqualTo(true) +        } + +    @Test +    @EnableSceneContainer +    fun clockShouldBeCentered_sceneContainerFlagOn_splitMode_offAod_false() = +        testScope.runTest { +            val value by collectLastValue(underTest.clockShouldBeCentered) +            kosmos.shadeRepository.setShadeMode(ShadeMode.Split) +            kosmos.activeNotificationListRepository.setActiveNotifs(1) +            transitionTo(KeyguardState.AOD, KeyguardState.LOCKSCREEN) +            assertThat(value).isEqualTo(false) +        } + +    private suspend fun transitionTo(from: KeyguardState, to: KeyguardState) { +        kosmos.fakeKeyguardTransitionRepository.sendTransitionStep( +            TransitionStep(from, to, 0f, TransitionState.STARTED) +        ) +        kosmos.fakeKeyguardTransitionRepository.sendTransitionStep( +            TransitionStep(from, to, 0.5f, TransitionState.RUNNING) +        ) +        kosmos.fakeKeyguardTransitionRepository.sendTransitionStep( +            TransitionStep(from, to, 1f, TransitionState.FINISHED) +        ) +    } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt index 6d7a0a96a71b..1dd5d073bef3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt @@ -38,6 +38,7 @@ import com.android.systemui.kosmos.testScope  import com.android.systemui.power.domain.interactor.PowerInteractorFactory  import com.android.systemui.scene.domain.interactor.sceneInteractor  import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags +import com.android.systemui.scene.shared.flag.sceneContainerFlags  import com.android.systemui.scene.shared.model.Scenes  import com.android.systemui.shade.data.repository.FakeShadeRepository  import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor @@ -75,7 +76,7 @@ class KeyguardInteractorTest : SysuiTestCase() {              repository = repository,              commandQueue = commandQueue,              powerInteractor = PowerInteractorFactory.create().powerInteractor, -            sceneContainerFlags = kosmos.fakeSceneContainerFlags, +            sceneContainerFlags = kosmos.sceneContainerFlags,              bouncerRepository = bouncerRepository,              configurationInteractor = ConfigurationInteractor(FakeConfigurationRepository()),              shadeRepository = shadeRepository, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt index 15c9cf73d51d..412292554e73 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt @@ -55,28 +55,29 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {      val testScope = kosmos.testScope      @Test -    fun transitionCollectorsReceivesOnlyAppropriateEvents() = runTest { -        val lockscreenToAodSteps by collectValues(underTest.lockscreenToAodTransition) -        val aodToLockscreenSteps by collectValues(underTest.aodToLockscreenTransition) - -        val steps = mutableListOf<TransitionStep>() -        steps.add(TransitionStep(AOD, GONE, 0f, STARTED)) -        steps.add(TransitionStep(AOD, GONE, 1f, FINISHED)) -        steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)) -        steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING)) -        steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED)) -        steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)) -        steps.add(TransitionStep(LOCKSCREEN, AOD, 0.1f, RUNNING)) -        steps.add(TransitionStep(LOCKSCREEN, AOD, 0.2f, RUNNING)) +    fun transitionCollectorsReceivesOnlyAppropriateEvents() = +        testScope.runTest { +            val lockscreenToAodSteps by collectValues(underTest.transition(LOCKSCREEN, AOD)) +            val aodToLockscreenSteps by collectValues(underTest.transition(AOD, LOCKSCREEN)) -        steps.forEach { -            repository.sendTransitionStep(it) -            runCurrent() -        } +            val steps = mutableListOf<TransitionStep>() +            steps.add(TransitionStep(AOD, GONE, 0f, STARTED)) +            steps.add(TransitionStep(AOD, GONE, 1f, FINISHED)) +            steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)) +            steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING)) +            steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED)) +            steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)) +            steps.add(TransitionStep(LOCKSCREEN, AOD, 0.1f, RUNNING)) +            steps.add(TransitionStep(LOCKSCREEN, AOD, 0.2f, RUNNING)) -        assertThat(aodToLockscreenSteps).isEqualTo(steps.subList(2, 5)) -        assertThat(lockscreenToAodSteps).isEqualTo(steps.subList(5, 8)) -    } +            steps.forEach { +                repository.sendTransitionStep(it) +                runCurrent() +            } + +            assertThat(aodToLockscreenSteps).isEqualTo(steps.subList(2, 5)) +            assertThat(lockscreenToAodSteps).isEqualTo(steps.subList(5, 8)) +        }      @Test      fun dozeAmountTransitionTest_AodToFromLockscreen() = @@ -187,59 +188,60 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() {          }      @Test -    fun finishedKeyguardTransitionStepTests() = runTest { -        val finishedSteps by collectValues(underTest.finishedKeyguardTransitionStep) +    fun finishedKeyguardTransitionStepTests() = +        testScope.runTest { +            val finishedSteps by collectValues(underTest.finishedKeyguardTransitionStep) +            val steps = mutableListOf<TransitionStep>() -        val steps = mutableListOf<TransitionStep>() +            steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)) +            steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING)) +            steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED)) +            steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)) +            steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING)) +            steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED)) +            steps.add(TransitionStep(AOD, GONE, 1f, STARTED)) -        steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)) -        steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING)) -        steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED)) -        steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)) -        steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING)) -        steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED)) -        steps.add(TransitionStep(AOD, GONE, 1f, STARTED)) +            steps.forEach { +                repository.sendTransitionStep(it) +                runCurrent() +            } -        steps.forEach { -            repository.sendTransitionStep(it) -            runCurrent() +            // Ignore the default state. +            assertThat(finishedSteps.subList(1, finishedSteps.size)) +                .isEqualTo(listOf(steps[2], steps[5]))          } -        // Ignore the default state. -        assertThat(finishedSteps.subList(1, finishedSteps.size)) -            .isEqualTo(listOf(steps[2], steps[5])) -    } -      @Test -    fun startedKeyguardTransitionStepTests() = runTest { -        val startedSteps by collectValues(underTest.startedKeyguardTransitionStep) +    fun startedKeyguardTransitionStepTests() = +        testScope.runTest { +            val startedSteps by collectValues(underTest.startedKeyguardTransitionStep) -        val steps = mutableListOf<TransitionStep>() +            val steps = mutableListOf<TransitionStep>() -        steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)) -        steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING)) -        steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED)) -        steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)) -        steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING)) -        steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED)) -        steps.add(TransitionStep(AOD, GONE, 1f, STARTED)) +            steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)) +            steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING)) +            steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED)) +            steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)) +            steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING)) +            steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED)) +            steps.add(TransitionStep(AOD, GONE, 1f, STARTED)) -        steps.forEach { -            repository.sendTransitionStep(it) -            runCurrent() -        } +            steps.forEach { +                repository.sendTransitionStep(it) +                runCurrent() +            } -        assertThat(startedSteps) -            .isEqualTo( -                listOf( -                    // The initial transition will also get sent when collect started -                    TransitionStep(OFF, LOCKSCREEN, 0f, STARTED), -                    steps[0], -                    steps[3], -                    steps[6] +            assertThat(startedSteps) +                .isEqualTo( +                    listOf( +                        // The initial transition will also get sent when collect started +                        TransitionStep(OFF, LOCKSCREEN, 0f, STARTED), +                        steps[0], +                        steps[3], +                        steps[6] +                    )                  ) -            ) -    } +        }      @Test      fun transitionValue() = diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt index f0607f4b70e1..0ac7ff5232a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt @@ -16,6 +16,7 @@  package com.android.systemui.keyguard.ui +import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE  import com.android.systemui.SysuiTestCase @@ -35,10 +36,9 @@ import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.junit.runners.JUnit4  @SmallTest -@RunWith(JUnit4::class) +@RunWith(AndroidJUnit4::class)  class KeyguardTransitionAnimationFlowTest : SysuiTestCase() {      val kosmos = testKosmos()      val testScope = kosmos.testScope diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt index 78bdfb350085..5bf0f4b8dc28 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelTest.kt @@ -36,6 +36,7 @@ import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.test.runCurrent  import kotlinx.coroutines.test.runTest +import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith @@ -45,16 +46,19 @@ import org.junit.runner.RunWith  class AlternateBouncerToGoneTransitionViewModelTest : SysuiTestCase() {      val kosmos =          testKosmos().apply { -            fakeFeatureFlagsClassic.apply { -                set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) -                set(Flags.FULL_SCREEN_USER_SWITCHER, false) -            } +            fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }          } +      private val testScope = kosmos.testScope      private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository      private val sysuiStatusBarStateController = kosmos.sysuiStatusBarStateController      private val underTest by lazy { kosmos.alternateBouncerToGoneTransitionViewModel } +    @Before +    fun setup() { +        mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT) +    } +      @Test      fun deviceEntryParentViewDisappear() =          testScope.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt index ff41ea25f470..854a4786d059 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt @@ -32,6 +32,7 @@ import com.android.systemui.testKosmos  import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.test.runTest +import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith @@ -41,15 +42,17 @@ import org.junit.runner.RunWith  class AlternateBouncerToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() {      private val kosmos =          testKosmos().apply { -            fakeFeatureFlagsClassic.apply { -                set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) -                set(Flags.FULL_SCREEN_USER_SWITCHER, false) -            } +            fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }          }      private val testScope = kosmos.testScope      private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }      private val underTest by lazy { kosmos.alternateBouncerToPrimaryBouncerTransitionViewModel } +    @Before +    fun setup() { +        mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT) +    } +      @Test      fun deviceEntryParentViewDisappear() =          testScope.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt index e6b30176d3ee..ee217a63e8ac 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt @@ -57,10 +57,7 @@ class BouncerToGoneFlowsTest : SysuiTestCase() {      private val kosmos =          testKosmos().apply { -            fakeFeatureFlagsClassic.apply { -                set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) -                set(Flags.FULL_SCREEN_USER_SWITCHER, false) -            } +            fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }          }      private val testScope = kosmos.testScope      private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository @@ -72,6 +69,7 @@ class BouncerToGoneFlowsTest : SysuiTestCase() {      @Before      fun setUp() {          MockitoAnnotations.initMocks(this) +        mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT)          whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false)          sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(false)      } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt index fc604aa5a1d2..e3eca6729188 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt @@ -30,11 +30,8 @@ import com.android.systemui.communal.data.repository.communalRepository  import com.android.systemui.communal.shared.model.CommunalScenes  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository -import com.android.systemui.flags.Flags -import com.android.systemui.flags.fakeFeatureFlagsClassic  import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository  import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.keyguardInteractor  import com.android.systemui.keyguard.shared.model.KeyguardState  import com.android.systemui.keyguard.shared.model.TransitionState  import com.android.systemui.keyguard.shared.model.TransitionStep @@ -60,13 +57,9 @@ import org.junit.runner.RunWith  @SmallTest  @RunWith(AndroidJUnit4::class)  class KeyguardRootViewModelTest : SysuiTestCase() { -    private val kosmos = -        testKosmos().apply { -            fakeFeatureFlagsClassic.apply { set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) } -        } +    private val kosmos = testKosmos()      private val testScope = kosmos.testScope      private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository -    private val keyguardInteractor = kosmos.keyguardInteractor      private val keyguardRepository = kosmos.fakeKeyguardRepository      private val communalRepository = kosmos.communalRepository      private val screenOffAnimationController = kosmos.screenOffAnimationController @@ -82,7 +75,10 @@ class KeyguardRootViewModelTest : SysuiTestCase() {      fun setUp() {          mSetFlagsRule.enableFlags(AConfigFlags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR)          mSetFlagsRule.enableFlags(FLAG_NEW_AOD_TRANSITION) -        mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) +        mSetFlagsRule.disableFlags( +            AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT, +            AConfigFlags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT, +        )      }      @Test @@ -426,4 +422,23 @@ class KeyguardRootViewModelTest : SysuiTestCase() {              shadeRepository.setQsExpansion(0.5f)              assertThat(alpha).isEqualTo(0f)          } + +    @Test +    fun alpha_idleOnDream_isZero() = +        testScope.runTest { +            val alpha by collectLastValue(underTest.alpha(viewState)) +            assertThat(alpha).isEqualTo(1f) + +            // Go to GONE state +            keyguardTransitionRepository.sendTransitionSteps( +                from = KeyguardState.LOCKSCREEN, +                to = KeyguardState.DREAMING, +                testScope = testScope, +            ) +            assertThat(alpha).isEqualTo(0f) + +            // Try pulling down shade and ensure the value doesn't change +            shadeRepository.setQsExpansion(0.5f) +            assertThat(alpha).isEqualTo(0f) +        }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt index 66f7e015a133..776f1a55fdcb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt @@ -34,6 +34,8 @@ import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository  import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor  import com.android.systemui.kosmos.testScope +import com.android.systemui.power.data.repository.fakePowerRepository +import com.android.systemui.power.shared.model.WakefulnessState  import com.android.systemui.scene.domain.interactor.sceneInteractor  import com.android.systemui.scene.shared.model.Scenes  import com.android.systemui.shade.data.repository.shadeRepository @@ -43,6 +45,7 @@ import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificati  import com.android.systemui.testKosmos  import com.android.systemui.util.mockito.mock  import com.google.common.truth.Truth.assertThat +import kotlin.math.pow  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.test.runTest  import org.junit.BeforeClass @@ -57,22 +60,26 @@ import platform.test.runner.parameterized.Parameters  class LockscreenSceneViewModelTest : SysuiTestCase() {      companion object { +        private const val parameterCount = 6 +          @Parameters(              name =                  "canSwipeToEnter={0}, downWithTwoPointers={1}, downFromEdge={2}," + -                    " isSingleShade={3}, isCommunalAvailable={4}" +                    " isSingleShade={3}, isCommunalAvailable={4}, isShadeTouchable={5}"          )          @JvmStatic          fun combinations() = buildList { -            repeat(32) { combination -> +            repeat(2f.pow(parameterCount).toInt()) { combination ->                  add(                      arrayOf( -                        /* canSwipeToEnter= */ combination and 1 != 0, -                        /* downWithTwoPointers= */ combination and 2 != 0, -                        /* downFromEdge= */ combination and 4 != 0, -                        /* isSingleShade= */ combination and 8 != 0, -                        /* isCommunalAvailable= */ combination and 16 != 0, -                    ) +                            /* canSwipeToEnter= */ combination and 1 != 0, +                            /* downWithTwoPointers= */ combination and 2 != 0, +                            /* downFromEdge= */ combination and 4 != 0, +                            /* isSingleShade= */ combination and 8 != 0, +                            /* isCommunalAvailable= */ combination and 16 != 0, +                            /* isShadeTouchable= */ combination and 32 != 0, +                        ) +                        .also { check(it.size == parameterCount) }                  )              }          } @@ -82,8 +89,15 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {          fun setUp() {              val combinationStrings =                  combinations().map { array -> -                    check(array.size == 5) -                    "${array[4]},${array[3]},${array[2]},${array[1]},${array[0]}" +                    check(array.size == parameterCount) +                    buildString { +                        ((parameterCount - 1) downTo 0).forEach { index -> +                            append("${array[index]}") +                            if (index > 0) { +                                append(",") +                            } +                        } +                    }                  }              val uniqueCombinations = combinationStrings.toSet()              assertThat(combinationStrings).hasSize(uniqueCombinations.size) @@ -92,8 +106,35 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {          private fun expectedDownDestination(              downFromEdge: Boolean,              isSingleShade: Boolean, -        ): SceneKey { -            return if (downFromEdge && isSingleShade) Scenes.QuickSettings else Scenes.Shade +            isShadeTouchable: Boolean, +        ): SceneKey? { +            return when { +                !isShadeTouchable -> null +                downFromEdge && isSingleShade -> Scenes.QuickSettings +                else -> Scenes.Shade +            } +        } + +        private fun expectedUpDestination( +            canSwipeToEnter: Boolean, +            isShadeTouchable: Boolean, +        ): SceneKey? { +            return when { +                !isShadeTouchable -> null +                canSwipeToEnter -> Scenes.Gone +                else -> Scenes.Bouncer +            } +        } + +        private fun expectedLeftDestination( +            isCommunalAvailable: Boolean, +            isShadeTouchable: Boolean, +        ): SceneKey? { +            return when { +                !isShadeTouchable -> null +                isCommunalAvailable -> Scenes.Communal +                else -> null +            }          }      } @@ -106,6 +147,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {      @JvmField @Parameter(2) var downFromEdge: Boolean = false      @JvmField @Parameter(3) var isSingleShade: Boolean = true      @JvmField @Parameter(4) var isCommunalAvailable: Boolean = false +    @JvmField @Parameter(5) var isShadeTouchable: Boolean = false      private val underTest by lazy { createLockscreenSceneViewModel() } @@ -130,6 +172,14 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {                  }              )              kosmos.setCommunalAvailable(isCommunalAvailable) +            kosmos.fakePowerRepository.updateWakefulness( +                rawState = +                    if (isShadeTouchable) { +                        WakefulnessState.AWAKE +                    } else { +                        WakefulnessState.ASLEEP +                    }, +            )              val destinationScenes by collectLastValue(underTest.destinationScenes) @@ -148,14 +198,25 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {                      expectedDownDestination(                          downFromEdge = downFromEdge,                          isSingleShade = isSingleShade, +                        isShadeTouchable = isShadeTouchable,                      )                  )              assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene) -                .isEqualTo(if (canSwipeToEnter) Scenes.Gone else Scenes.Bouncer) +                .isEqualTo( +                    expectedUpDestination( +                        canSwipeToEnter = canSwipeToEnter, +                        isShadeTouchable = isShadeTouchable, +                    ) +                )              assertThat(destinationScenes?.get(Swipe(SwipeDirection.Left))?.toScene) -                .isEqualTo(Scenes.Communal.takeIf { isCommunalAvailable }) +                .isEqualTo( +                    expectedLeftDestination( +                        isCommunalAvailable = isCommunalAvailable, +                        isShadeTouchable = isShadeTouchable, +                    ) +                )          }      private fun createLockscreenSceneViewModel(): LockscreenSceneViewModel { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt index dddf6485d0f4..4c16a339d696 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt @@ -49,9 +49,7 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() {      val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository      val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository      val configurationRepository = kosmos.fakeConfigurationRepository -    val underTest by lazy { -        kosmos.occludedToLockscreenTransitionViewModel -    } +    val underTest by lazy { kosmos.occludedToLockscreenTransitionViewModel }      @Test      fun lockscreenFadeIn() = @@ -164,25 +162,6 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() {              values.forEach { assertThat(it).isEqualTo(1f) }          } -    @Test -    fun deviceEntryBackgroundView_noUdfpsEnrolled_noUpdates() = -        testScope.runTest { -            fingerprintPropertyRepository.supportsRearFps() -            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) -            val values by collectValues(underTest.deviceEntryBackgroundViewAlpha) - -            keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) -            keyguardTransitionRepository.sendTransitionStep(step(0.1f)) -            keyguardTransitionRepository.sendTransitionStep(step(0.3f)) -            keyguardTransitionRepository.sendTransitionStep(step(0.4f)) -            keyguardTransitionRepository.sendTransitionStep(step(0.5f)) -            keyguardTransitionRepository.sendTransitionStep(step(0.6f)) -            keyguardTransitionRepository.sendTransitionStep(step(0.8f)) -            keyguardTransitionRepository.sendTransitionStep(step(1f)) - -            assertThat(values).isEmpty() // no updates -        } -      private fun step(          value: Float,          state: TransitionState = TransitionState.RUNNING diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt index db1d5d91eb65..18e9009611c9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt @@ -44,10 +44,7 @@ import org.junit.runner.RunWith  class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {      val kosmos =          testKosmos().apply { -            fakeFeatureFlagsClassic.apply { -                set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) -                set(Flags.FULL_SCREEN_USER_SWITCHER, false) -            } +            fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }          }      val testScope = kosmos.testScope @@ -58,6 +55,7 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() {      @Before      fun setUp() { +        mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT)          whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(false)          sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(false)      } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt index 956ef661d467..33eb90acdcb3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt @@ -26,7 +26,9 @@ import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.kosmos.testScope  import com.android.systemui.media.controls.MediaTestHelper  import com.android.systemui.media.controls.shared.model.MediaData +import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel  import com.android.systemui.media.controls.shared.model.SmartspaceMediaData +import com.android.systemui.media.controls.shared.model.SmartspaceMediaLoadingModel  import com.android.systemui.testKosmos  import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.test.runTest @@ -144,6 +146,37 @@ class MediaFilterRepositoryTest : SysuiTestCase() {              assertThat(smartspaceMediaData?.isActive).isFalse()          } +    @Test +    fun addMediaDataLoadingState() = +        testScope.runTest { +            val mediaDataLoadedStates by collectLastValue(underTest.mediaDataLoadedStates) +            val instanceId = InstanceId.fakeInstanceId(123) +            val mediaLoadedStates = mutableListOf(MediaDataLoadingModel.Loaded(instanceId)) + +            underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) + +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStates) + +            mediaLoadedStates.remove(MediaDataLoadingModel.Loaded(instanceId)) + +            underTest.addMediaDataLoadingState(MediaDataLoadingModel.Removed(instanceId)) + +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStates) +        } + +    @Test +    fun setRecommendationsLoadingState() = +        testScope.runTest { +            val recommendationsLoadingState by +                collectLastValue(underTest.recommendationsLoadingState) +            val recommendationsLoadingModel = +                SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE) + +            underTest.setRecommedationsLoadingState(recommendationsLoadingModel) + +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel) +        } +      companion object {          private const val KEY = "KEY"          private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID" diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt index d9d84f2d2aac..a0a1eb3a6ca6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt @@ -20,6 +20,7 @@ import android.R  import android.graphics.drawable.Icon  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest +import com.android.internal.logging.InstanceId  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.flags.Flags @@ -28,13 +29,20 @@ import com.android.systemui.kosmos.testScope  import com.android.systemui.media.controls.MediaTestHelper  import com.android.systemui.media.controls.data.repository.MediaFilterRepository  import com.android.systemui.media.controls.data.repository.mediaFilterRepository +import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl  import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor  import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor +import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter  import com.android.systemui.media.controls.shared.model.MediaData +import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel  import com.android.systemui.media.controls.shared.model.SmartspaceMediaData +import com.android.systemui.media.controls.shared.model.SmartspaceMediaLoadingModel +import com.android.systemui.statusbar.notificationLockscreenUserManager  import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.whenever  import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.test.runTest +import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith @@ -45,9 +53,17 @@ class MediaCarouselInteractorTest : SysuiTestCase() {      private val kosmos = testKosmos()      private val testScope = kosmos.testScope +    private val mediaDataFilter: MediaDataFilterImpl = kosmos.mediaDataFilter +    private val notificationLockscreenUserManager = kosmos.notificationLockscreenUserManager      private val mediaFilterRepository: MediaFilterRepository = kosmos.mediaFilterRepository +      private val underTest: MediaCarouselInteractor = kosmos.mediaCarouselInteractor +    @Before +    fun setUp() { +        underTest.start() +    } +      @Test      fun addUserMediaEntry_activeThenInactivate() =          testScope.runTest { @@ -56,7 +72,7 @@ class MediaCarouselInteractorTest : SysuiTestCase() {              val hasActiveMedia by collectLastValue(underTest.hasActiveMedia)              val hasAnyMedia by collectLastValue(underTest.hasAnyMedia) -            val userMedia = MediaData().copy(active = true) +            val userMedia = MediaData(active = true)              mediaFilterRepository.addSelectedUserMediaEntry(userMedia) @@ -79,7 +95,7 @@ class MediaCarouselInteractorTest : SysuiTestCase() {              val hasActiveMedia by collectLastValue(underTest.hasActiveMedia)              val hasAnyMedia by collectLastValue(underTest.hasAnyMedia) -            val userMedia = MediaData().copy(active = false) +            val userMedia = MediaData(active = false)              val instanceId = userMedia.instanceId              mediaFilterRepository.addSelectedUserMediaEntry(userMedia) @@ -112,7 +128,7 @@ class MediaCarouselInteractorTest : SysuiTestCase() {                      isActive = true,                      recommendations = MediaTestHelper.getValidRecommendationList(icon),                  ) -            val userMedia = MediaData().copy(active = false) +            val userMedia = MediaData(active = false)              mediaFilterRepository.setRecommendation(userMediaRecommendation) @@ -199,7 +215,80 @@ class MediaCarouselInteractorTest : SysuiTestCase() {      fun hasActiveMediaOrRecommendation_nothingSet_returnsFalse() =          testScope.runTest { assertThat(underTest.hasActiveMediaOrRecommendation.value).isFalse() } +    @Test +    fun onMediaDataUpdated_updatesLoadingState() = +        testScope.runTest { +            whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true) +            whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true) +            val mediaDataLoadedStates by collectLastValue(underTest.mediaDataLoadedStates) +            val instanceId = InstanceId.fakeInstanceId(123) +            val mediaLoadedStates: MutableList<MediaDataLoadingModel> = mutableListOf() + +            mediaLoadedStates.add(MediaDataLoadingModel.Loaded(instanceId)) +            mediaDataFilter.onMediaDataLoaded( +                KEY, +                KEY, +                MediaData(userId = USER_ID, instanceId = instanceId) +            ) + +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStates) + +            val newInstanceId = InstanceId.fakeInstanceId(321) + +            mediaLoadedStates.add(MediaDataLoadingModel.Loaded(newInstanceId)) +            mediaDataFilter.onMediaDataLoaded( +                KEY_2, +                KEY_2, +                MediaData(userId = USER_ID, instanceId = newInstanceId) +            ) + +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStates) + +            mediaLoadedStates.remove(MediaDataLoadingModel.Loaded(instanceId)) + +            mediaDataFilter.onMediaDataRemoved(KEY) + +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStates) + +            mediaLoadedStates.remove(MediaDataLoadingModel.Loaded(newInstanceId)) + +            mediaDataFilter.onMediaDataRemoved(KEY_2) + +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStates) +        } + +    @Test +    fun onMediaRecommendationsUpdated_updatesLoadingState() = +        testScope.runTest { +            whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true) +            whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true) +            val recommendationsLoadingState by +                collectLastValue(underTest.recommendationsLoadingState) +            val icon = Icon.createWithResource(context, R.drawable.ic_media_play) +            val mediaRecommendations = +                SmartspaceMediaData( +                    targetId = KEY_MEDIA_SMARTSPACE, +                    isActive = true, +                    recommendations = MediaTestHelper.getValidRecommendationList(icon), +                ) +            var recommendationsLoadingModel: SmartspaceMediaLoadingModel = +                SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE, isPrioritized = true) + +            mediaDataFilter.onSmartspaceMediaDataLoaded(KEY_MEDIA_SMARTSPACE, mediaRecommendations) + +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel) + +            recommendationsLoadingModel = SmartspaceMediaLoadingModel.Removed(KEY_MEDIA_SMARTSPACE) + +            mediaDataFilter.onSmartspaceMediaDataRemoved(KEY_MEDIA_SMARTSPACE) + +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel) +        } +      companion object { +        private const val KEY = "key" +        private const val KEY_2 = "key2" +        private const val USER_ID = 0          private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"      }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt index a1cee8aaac7c..1cba185600cc 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt @@ -16,10 +16,17 @@  package com.android.systemui.media.controls.domain.interactor +import android.app.PendingIntent +import android.os.Bundle  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.internal.logging.InstanceId  import com.android.systemui.SysuiTestCase +import com.android.systemui.activityIntentHelper +import com.android.systemui.animation.ActivityTransitionAnimator +import com.android.systemui.animation.DialogTransitionAnimator +import com.android.systemui.animation.Expandable +import com.android.systemui.bluetooth.mockBroadcastDialogController  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.kosmos.testScope  import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl @@ -28,13 +35,22 @@ import com.android.systemui.media.controls.domain.pipeline.interactor.mediaContr  import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter  import com.android.systemui.media.controls.shared.model.MediaData  import com.android.systemui.media.controls.util.mediaInstanceId +import com.android.systemui.media.mediaOutputDialogManager +import com.android.systemui.mockActivityIntentHelper +import com.android.systemui.plugins.activityStarter  import com.android.systemui.statusbar.notificationLockscreenUserManager +import com.android.systemui.statusbar.policy.keyguardStateController  import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock  import com.android.systemui.util.mockito.whenever  import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.test.runTest  import org.junit.Test  import org.junit.runner.RunWith +import org.mockito.Mockito.never +import org.mockito.Mockito.verify  @SmallTest  @RunWith(AndroidJUnit4::class) @@ -44,10 +60,16 @@ class MediaControlInteractorTest : SysuiTestCase() {      private val testScope = kosmos.testScope      private val mediaDataFilter: MediaDataFilterImpl = kosmos.mediaDataFilter +    private val activityStarter = kosmos.activityStarter +    private val keyguardStateController = kosmos.keyguardStateController      private val instanceId: InstanceId = kosmos.mediaInstanceId      private val notificationLockscreenUserManager = kosmos.notificationLockscreenUserManager -    private val underTest: MediaControlInteractor = kosmos.mediaControlInteractor +    private val underTest: MediaControlInteractor = +        with(kosmos) { +            activityIntentHelper = mockActivityIntentHelper +            kosmos.mediaControlInteractor +        }      @Test      fun onMediaDataUpdated() = @@ -55,39 +77,141 @@ class MediaControlInteractorTest : SysuiTestCase() {              whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true)              whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true)              val controlModel by collectLastValue(underTest.mediaControl) -            var mediaData = -                MediaData(userId = USER_ID, instanceId = instanceId, artist = SESSION_ARTIST) +            var mediaData = MediaData(userId = USER_ID, instanceId = instanceId, artist = ARTIST)              mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData)              assertThat(controlModel?.instanceId).isEqualTo(instanceId) -            assertThat(controlModel?.artistName).isEqualTo(SESSION_ARTIST) +            assertThat(controlModel?.artistName).isEqualTo(ARTIST) -            mediaData = -                MediaData(userId = USER_ID, instanceId = instanceId, artist = SESSION_ARTIST_2) +            mediaData = MediaData(userId = USER_ID, instanceId = instanceId, artist = ARTIST_2)              mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData)              assertThat(controlModel?.instanceId).isEqualTo(instanceId) -            assertThat(controlModel?.artistName).isEqualTo(SESSION_ARTIST_2) +            assertThat(controlModel?.artistName).isEqualTo(ARTIST_2)              mediaData =                  MediaData(                      userId = USER_ID,                      instanceId = InstanceId.fakeInstanceId(2), -                    artist = SESSION_ARTIST +                    artist = ARTIST                  )              mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData)              assertThat(controlModel?.instanceId).isNotEqualTo(mediaData.instanceId) -            assertThat(controlModel?.artistName).isEqualTo(SESSION_ARTIST_2) +            assertThat(controlModel?.artistName).isEqualTo(ARTIST_2)          } +    @Test +    fun startSettings() { +        underTest.startSettings() + +        verify(activityStarter).startActivity(any(), eq(true)) +    } + +    @Test +    fun startClickIntent_showOverLockscreen() { +        whenever(keyguardStateController.isShowing).thenReturn(true) +        whenever(kosmos.activityIntentHelper.wouldPendingShowOverLockscreen(any(), any())) +            .thenReturn(true) + +        val clickIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } +        val expandable = mock<Expandable>() + +        underTest.startClickIntent(expandable, clickIntent) + +        verify(clickIntent).send(any<Bundle>()) +    } + +    @Test +    fun startClickIntent_hideOverLockscreen() { +        whenever(keyguardStateController.isShowing).thenReturn(false) + +        val clickIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } +        val expandable = mock<Expandable>() +        val activityController = mock<ActivityTransitionAnimator.Controller>() +        whenever(expandable.activityTransitionController(any())).thenReturn(activityController) + +        underTest.startClickIntent(expandable, clickIntent) + +        verify(activityStarter) +            .postStartActivityDismissingKeyguard(eq(clickIntent), eq(activityController)) +    } + +    @Test +    fun startDeviceIntent_showOverLockscreen() { +        whenever(keyguardStateController.isShowing).thenReturn(true) +        whenever(kosmos.activityIntentHelper.wouldPendingShowOverLockscreen(any(), any())) +            .thenReturn(true) + +        val deviceIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } + +        underTest.startDeviceIntent(deviceIntent) + +        verify(deviceIntent).send(any<Bundle>()) +    } + +    @Test +    fun startDeviceIntent_intentNotActivity() { +        whenever(keyguardStateController.isShowing).thenReturn(true) +        whenever(kosmos.activityIntentHelper.wouldPendingShowOverLockscreen(any(), any())) +            .thenReturn(true) + +        val deviceIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(false) } + +        underTest.startDeviceIntent(deviceIntent) + +        verify(deviceIntent, never()).send(any<Bundle>()) +    } + +    @Test +    fun startDeviceIntent_hideOverLockscreen() { +        whenever(keyguardStateController.isShowing).thenReturn(false) + +        val deviceIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } + +        underTest.startDeviceIntent(deviceIntent) + +        verify(activityStarter).postStartActivityDismissingKeyguard(eq(deviceIntent)) +    } + +    @Test +    fun startMediaOutputDialog() { +        val expandable = mock<Expandable>() +        val dialogTransitionController = mock<DialogTransitionAnimator.Controller>() +        whenever(expandable.dialogTransitionController(any())) +            .thenReturn(dialogTransitionController) + +        underTest.startMediaOutputDialog(expandable, PACKAGE_NAME) + +        verify(kosmos.mediaOutputDialogManager) +            .createAndShowWithController(eq(PACKAGE_NAME), eq(true), eq(dialogTransitionController)) +    } + +    @Test +    fun startBroadcastDialog() { +        val expandable = mock<Expandable>() +        val dialogTransitionController = mock<DialogTransitionAnimator.Controller>() +        whenever(expandable.dialogTransitionController()).thenReturn(dialogTransitionController) + +        underTest.startBroadcastDialog(expandable, APP_NAME, PACKAGE_NAME) + +        verify(kosmos.mockBroadcastDialogController) +            .createBroadcastDialogWithController( +                eq(APP_NAME), +                eq(PACKAGE_NAME), +                eq(dialogTransitionController) +            ) +    } +      companion object {          private const val USER_ID = 0          private const val KEY = "key" -        private const val SESSION_ARTIST = "artist" -        private const val SESSION_ARTIST_2 = "artist2" +        private const val PACKAGE_NAME = "com.example.app" +        private const val APP_NAME = "app" +        private const val ARTIST = "artist" +        private const val ARTIST_2 = "artist2"      }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt new file mode 100644 index 000000000000..9558e5d23a25 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.controls.ui.viewmodel + +import android.R +import android.content.packageManager +import android.content.pm.ApplicationInfo +import android.media.MediaMetadata +import android.media.session.MediaSession +import android.media.session.PlaybackState +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.internal.logging.InstanceId +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl +import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter +import com.android.systemui.media.controls.shared.model.MediaData +import com.android.systemui.media.controls.shared.model.MediaDeviceData +import com.android.systemui.media.controls.util.mediaInstanceId +import com.android.systemui.statusbar.notificationLockscreenUserManager +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers +import org.mockito.Mockito + +@SmallTest +@RunWith(AndroidJUnit4::class) +class MediaControlViewModelTest : SysuiTestCase() { + +    private val kosmos = testKosmos() +    private val testScope = kosmos.testScope + +    private val mediaDataFilter: MediaDataFilterImpl = kosmos.mediaDataFilter +    private val notificationLockscreenUserManager = kosmos.notificationLockscreenUserManager +    private val packageManager = kosmos.packageManager +    private val drawable = context.getDrawable(R.drawable.ic_media_play) +    private val instanceId: InstanceId = kosmos.mediaInstanceId + +    private val underTest: MediaControlViewModel = kosmos.mediaControlViewModel + +    @Test +    fun addMediaControl_mediaControlViewModelIsLoaded() = +        testScope.runTest { +            whenever(packageManager.getApplicationIcon(Mockito.anyString())).thenReturn(drawable) +            whenever(packageManager.getApplicationIcon(any(ApplicationInfo::class.java))) +                .thenReturn(drawable) +            whenever(packageManager.getApplicationInfo(eq(PACKAGE_NAME), ArgumentMatchers.anyInt())) +                .thenReturn(ApplicationInfo()) +            whenever(packageManager.getApplicationLabel(any())).thenReturn(PACKAGE_NAME) +            whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true) +            whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true) +            val playerModel by collectLastValue(underTest.player) + +            context.setMockPackageManager(packageManager) + +            val mediaData = initMediaData() + +            mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) + +            assertThat(playerModel).isNotNull() +            assertThat(playerModel?.titleName).isEqualTo(TITLE) +            assertThat(playerModel?.artistName).isEqualTo(ARTIST) +            assertThat(playerModel?.gutsMenu).isNotNull() +            assertThat(playerModel?.outputSwitcher).isNotNull() +            assertThat(playerModel?.actionButtons).isNotNull() +            assertThat(playerModel?.playTurbulenceNoise).isFalse() +        } + +    private fun initMediaData(): MediaData { +        val device = MediaDeviceData(true, null, DEVICE_NAME, null, showBroadcastButton = true) + +        // Create media session +        val metadataBuilder = +            MediaMetadata.Builder().apply { +                putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST) +                putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE) +            } +        val playbackBuilder = +            PlaybackState.Builder().apply { +                setState(PlaybackState.STATE_PAUSED, 6000L, 1f) +                setActions(PlaybackState.ACTION_PLAY) +            } +        val session = +            MediaSession(context, SESSION_KEY).apply { +                setMetadata(metadataBuilder.build()) +                setPlaybackState(playbackBuilder.build()) +            } +        session.isActive = true + +        return MediaData( +            userId = USER_ID, +            artist = ARTIST, +            song = TITLE, +            packageName = PACKAGE, +            token = session.sessionToken, +            device = device, +            instanceId = instanceId +        ) +    } + +    companion object { +        private const val USER_ID = 0 +        private const val KEY = "key" +        private const val PACKAGE_NAME = "com.example.app" +        private const val PACKAGE = "PKG" +        private const val ARTIST = "ARTIST" +        private const val TITLE = "TITLE" +        private const val DEVICE_NAME = "DEVICE_NAME" +        private const val SESSION_KEY = "SESSION_KEY" +        private const val SESSION_ARTIST = "SESSION_ARTIST" +        private const val SESSION_TITLE = "SESSION_TITLE" +    } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt index 6d6fd754341d..d0699aa12a43 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt @@ -16,7 +16,9 @@  package com.android.systemui.qs.pipeline.domain.autoaddable -import android.platform.test.annotations.EnabledOnRavenwood +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.view.accessibility.Flags  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase @@ -44,7 +46,6 @@ import org.mockito.MockitoAnnotations  @OptIn(ExperimentalCoroutinesApi::class)  @SmallTest -@EnabledOnRavenwood  @RunWith(AndroidJUnit4::class)  class ReduceBrightColorsAutoAddableTest : SysuiTestCase() { @@ -67,12 +68,14 @@ class ReduceBrightColorsAutoAddableTest : SysuiTestCase() {          }      @Test +    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)      fun available_strategyIfNotAdded() =          testWithFeatureAvailability(available = true) {              assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.IfNotAdded(SPEC))          }      @Test +    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)      fun activated_addSignal() = testWithFeatureAvailability {          val signal by collectLastValue(underTest.autoAddSignal(0))          runCurrent() @@ -85,6 +88,7 @@ class ReduceBrightColorsAutoAddableTest : SysuiTestCase() {      }      @Test +    @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)      fun notActivated_noSignal() = testWithFeatureAvailability {          val signal by collectLastValue(underTest.autoAddSignal(0))          runCurrent() @@ -96,6 +100,13 @@ class ReduceBrightColorsAutoAddableTest : SysuiTestCase() {          assertThat(signal).isNull()      } +    @Test +    @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) +    fun available_a11yQsShortcutFlagEnabled_strategyDisabled() = +        testWithFeatureAvailability(available = true) { +            assertThat(underTest.autoAddTracking).isEqualTo(AutoAddTracking.Disabled) +        } +      private fun testWithFeatureAvailability(          available: Boolean = true,          body: suspend TestScope.() -> TestResult diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt index 9856f9050c4b..93302e32b607 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt @@ -293,6 +293,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {                  occlusionInteractor = kosmos.sceneContainerOcclusionInteractor,                  faceUnlockInteractor = kosmos.deviceEntryFaceAuthInteractor,                  deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor, +                shadeInteractor = kosmos.shadeInteractor,              )          startable.start() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt index ae31058e7a54..7f7c24e6efa4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt @@ -39,7 +39,6 @@ import org.junit.runner.RunWith  @SmallTest  @RunWith(AndroidJUnit4::class) -@android.platform.test.annotations.EnabledOnRavenwood  class SceneContainerRepositoryTest : SysuiTestCase() {      private val kosmos = testKosmos().apply { fakeSceneContainerFlags.enabled = true } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt index 3fd5306abb71..61adcd2e2c25 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt @@ -20,13 +20,11 @@ package com.android.systemui.scene.domain.startable  import android.app.StatusBarManager  import android.os.PowerManager -import android.platform.test.annotations.EnableFlags  import android.view.Display  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest  import com.android.compose.animation.scene.ObservableTransitionState  import com.android.compose.animation.scene.SceneKey -import com.android.systemui.Flags as AconfigFlags  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository  import com.android.systemui.authentication.domain.interactor.authenticationInteractor @@ -40,6 +38,7 @@ import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepositor  import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInteractor  import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor  import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor +import com.android.systemui.flags.EnableSceneContainer  import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository  import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository  import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository @@ -48,14 +47,17 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor  import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus  import com.android.systemui.kosmos.testScope  import com.android.systemui.model.sysUiState +import com.android.systemui.power.data.repository.fakePowerRepository  import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest  import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest  import com.android.systemui.power.domain.interactor.PowerInteractorFactory +import com.android.systemui.power.shared.model.WakefulnessState  import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor  import com.android.systemui.scene.domain.interactor.sceneInteractor  import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags  import com.android.systemui.scene.shared.model.Scenes  import com.android.systemui.scene.shared.model.fakeSceneDataSource +import com.android.systemui.shade.domain.interactor.shadeInteractor  import com.android.systemui.shared.system.QuickStepContract  import com.android.systemui.statusbar.NotificationShadeWindowController  import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor @@ -91,7 +93,7 @@ import org.mockito.MockitoAnnotations  @SmallTest  @RunWith(AndroidJUnit4::class) -@EnableFlags(AconfigFlags.FLAG_SCENE_CONTAINER) +@EnableSceneContainer  class SceneContainerStartableTest : SysuiTestCase() {      @Mock private lateinit var windowController: NotificationShadeWindowController @@ -140,6 +142,7 @@ class SceneContainerStartableTest : SysuiTestCase() {                  occlusionInteractor = kosmos.sceneContainerOcclusionInteractor,                  faceUnlockInteractor = kosmos.deviceEntryFaceAuthInteractor,                  deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor, +                shadeInteractor = kosmos.shadeInteractor,              )      } @@ -287,6 +290,38 @@ class SceneContainerStartableTest : SysuiTestCase() {          }      @Test +    fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked() = +        testScope.runTest { +            val currentSceneKey by collectLastValue(sceneInteractor.currentScene) + +            val transitionState = +                prepareState( +                    authenticationMethod = AuthenticationMethodModel.Pin, +                    isDeviceUnlocked = false, +                    initialSceneKey = Scenes.Lockscreen, +                ) +            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen) +            underTest.start() +            runCurrent() + +            sceneInteractor.changeScene(Scenes.QuickSettings, "switching to qs for test") +            transitionState.value = ObservableTransitionState.Idle(Scenes.QuickSettings) +            runCurrent() +            assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) + +            sceneInteractor.changeScene(Scenes.Bouncer, "switching to bouncer for test") +            transitionState.value = ObservableTransitionState.Idle(Scenes.Bouncer) +            runCurrent() +            assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer) + +            kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( +                SuccessFingerprintAuthenticationStatus(0, true) +            ) + +            assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) +        } + +    @Test      fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn() =          testScope.runTest {              val currentSceneKey by collectLastValue(sceneInteractor.currentScene) @@ -1127,6 +1162,33 @@ class SceneContainerStartableTest : SysuiTestCase() {              assertThat(kosmos.fakeDeviceEntryFaceAuthRepository.isAuthRunning.value).isTrue()          } +    @Test +    fun switchToLockscreen_whenShadeBecomesNotTouchable() = +        testScope.runTest { +            val currentScene by collectLastValue(sceneInteractor.currentScene) +            val isShadeTouchable by collectLastValue(kosmos.shadeInteractor.isShadeTouchable) +            val transitionStateFlow = prepareState() +            underTest.start() +            assertThat(currentScene).isEqualTo(Scenes.Lockscreen) +            // Flung to bouncer, 90% of the way there: +            transitionStateFlow.value = +                ObservableTransitionState.Transition( +                    fromScene = Scenes.Lockscreen, +                    toScene = Scenes.Bouncer, +                    progress = flowOf(0.9f), +                    isInitiatedByUserInput = true, +                    isUserInputOngoing = flowOf(false), +                ) +            runCurrent() +            assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + +            kosmos.fakePowerRepository.updateWakefulness(WakefulnessState.ASLEEP) +            runCurrent() +            assertThat(isShadeTouchable).isFalse() + +            assertThat(currentScene).isEqualTo(Scenes.Lockscreen) +        } +      private fun TestScope.emulateSceneTransition(          transitionStateFlow: MutableStateFlow<ObservableTransitionState>,          toScene: SceneKey, @@ -1166,6 +1228,7 @@ class SceneContainerStartableTest : SysuiTestCase() {          isLockscreenEnabled: Boolean = true,          startsAwake: Boolean = true,          isDeviceProvisioned: Boolean = true, +        isInteractive: Boolean = true,      ): MutableStateFlow<ObservableTransitionState> {          if (authenticationMethod?.isSecure == true) {              assert(isLockscreenEnabled) { @@ -1205,6 +1268,7 @@ class SceneContainerStartableTest : SysuiTestCase() {          } else {              powerInteractor.setAsleepForTest()          } +        kosmos.fakePowerRepository.setInteractive(isInteractive)          kosmos.fakeDeviceProvisioningRepository.setDeviceProvisioned(isDeviceProvisioned) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagParameterizationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagParameterizationTest.kt new file mode 100644 index 000000000000..db31ad52e3b0 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagParameterizationTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.scene.shared.flag + +import android.platform.test.flag.junit.FlagsParameterization +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_COMPOSE_LOCKSCREEN +import com.android.systemui.Flags.FLAG_EXAMPLE_FLAG +import com.android.systemui.Flags.FLAG_SCENE_CONTAINER +import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.andSceneContainer +import com.google.common.truth.Truth +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +internal class SceneContainerFlagParameterizationTest : SysuiTestCase() { + +    @Test +    fun emptyAndSceneContainer() { +        val result = FlagsParameterization.allCombinationsOf().andSceneContainer() +        Truth.assertThat(result).hasSize(2) +        Truth.assertThat(result[0].mOverrides[FLAG_SCENE_CONTAINER]).isFalse() +        Truth.assertThat(result[1].mOverrides[FLAG_SCENE_CONTAINER]).isTrue() +    } + +    @Test +    fun oneUnrelatedAndSceneContainer() { +        val unrelatedFlag = FLAG_EXAMPLE_FLAG +        val result = FlagsParameterization.allCombinationsOf(unrelatedFlag).andSceneContainer() +        Truth.assertThat(result).hasSize(4) +        Truth.assertThat(result[0].mOverrides[unrelatedFlag]).isFalse() +        Truth.assertThat(result[0].mOverrides[FLAG_SCENE_CONTAINER]).isFalse() +        Truth.assertThat(result[1].mOverrides[unrelatedFlag]).isFalse() +        Truth.assertThat(result[1].mOverrides[FLAG_SCENE_CONTAINER]).isTrue() +        Truth.assertThat(result[2].mOverrides[unrelatedFlag]).isTrue() +        Truth.assertThat(result[2].mOverrides[FLAG_SCENE_CONTAINER]).isFalse() +        Truth.assertThat(result[3].mOverrides[unrelatedFlag]).isTrue() +        Truth.assertThat(result[3].mOverrides[FLAG_SCENE_CONTAINER]).isTrue() +    } + +    @Test +    fun oneDependencyAndSceneContainer() { +        val dependentFlag = FLAG_COMPOSE_LOCKSCREEN +        val result = FlagsParameterization.allCombinationsOf(dependentFlag).andSceneContainer() +        Truth.assertThat(result).hasSize(3) +        Truth.assertThat(result[0].mOverrides[dependentFlag]).isFalse() +        Truth.assertThat(result[0].mOverrides[FLAG_SCENE_CONTAINER]).isFalse() +        Truth.assertThat(result[1].mOverrides[dependentFlag]).isTrue() +        Truth.assertThat(result[1].mOverrides[FLAG_SCENE_CONTAINER]).isFalse() +        Truth.assertThat(result[2].mOverrides[dependentFlag]).isTrue() +        Truth.assertThat(result[2].mOverrides[FLAG_SCENE_CONTAINER]).isTrue() +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt index 543f6c91513e..2938acf293b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt @@ -16,12 +16,12 @@  package com.android.systemui.scene.shared.flag -import android.platform.test.annotations.DisableFlags  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.systemui.Flags.FLAG_SCENE_CONTAINER  import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.DisableSceneContainer  import com.android.systemui.flags.EnableSceneContainer +import com.android.systemui.kosmos.Kosmos  import com.google.common.truth.Truth  import org.junit.Test  import org.junit.runner.RunWith @@ -31,10 +31,11 @@ import org.junit.runner.RunWith  internal class SceneContainerFlagsTest : SysuiTestCase() {      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) +    @DisableSceneContainer      fun isNotEnabled_withoutAconfigFlags() {          Truth.assertThat(SceneContainerFlag.isEnabled).isEqualTo(false)          Truth.assertThat(SceneContainerFlagsImpl().isEnabled()).isEqualTo(false) +        Truth.assertThat(Kosmos().sceneContainerFlags.isEnabled()).isEqualTo(false)      }      @Test @@ -42,5 +43,6 @@ internal class SceneContainerFlagsTest : SysuiTestCase() {      fun isEnabled_withAconfigFlags() {          Truth.assertThat(SceneContainerFlag.isEnabled).isEqualTo(true)          Truth.assertThat(SceneContainerFlagsImpl().isEnabled()).isEqualTo(true) +        Truth.assertThat(Kosmos().sceneContainerFlags.isEnabled()).isEqualTo(true)      }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt index 757a6c9e5ac6..5b33ecbb28be 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt @@ -641,7 +641,6 @@ class ShadeInteractorImplTest : SysuiTestCase() {                  )              )              val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) -            runCurrent()              assertThat(isShadeTouchable).isFalse()          } @@ -668,13 +667,17 @@ class ShadeInteractorImplTest : SysuiTestCase() {                  )              )              val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) -            runCurrent()              assertThat(isShadeTouchable).isTrue()          }      @Test      fun isShadeTouchable_isFalse_whenStartingToSleepAndNotControlScreenOff() =          testScope.runTest { +            whenever(dozeParameters.shouldControlScreenOff()).thenReturn(false) +            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) +            // Assert the default condition is true +            assertThat(isShadeTouchable).isTrue() +              powerRepository.updateWakefulness(                  rawState = WakefulnessState.STARTING_TO_SLEEP,                  lastWakeReason = WakeSleepReason.POWER_BUTTON, @@ -688,15 +691,17 @@ class ShadeInteractorImplTest : SysuiTestCase() {                      transitionState = TransitionState.STARTED,                  )              ) -            whenever(dozeParameters.shouldControlScreenOff()).thenReturn(false) -            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) -            runCurrent()              assertThat(isShadeTouchable).isFalse()          }      @Test      fun isShadeTouchable_isTrue_whenStartingToSleepAndControlScreenOff() =          testScope.runTest { +            whenever(dozeParameters.shouldControlScreenOff()).thenReturn(true) +            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) +            // Assert the default condition is true +            assertThat(isShadeTouchable).isTrue() +              powerRepository.updateWakefulness(                  rawState = WakefulnessState.STARTING_TO_SLEEP,                  lastWakeReason = WakeSleepReason.POWER_BUTTON, @@ -710,9 +715,6 @@ class ShadeInteractorImplTest : SysuiTestCase() {                      transitionState = TransitionState.STARTED,                  )              ) -            whenever(dozeParameters.shouldControlScreenOff()).thenReturn(true) -            val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) -            runCurrent()              assertThat(isShadeTouchable).isTrue()          } @@ -730,7 +732,6 @@ class ShadeInteractorImplTest : SysuiTestCase() {                  )              )              val isShadeTouchable by collectLastValue(underTest.isShadeTouchable) -            runCurrent()              assertThat(isShadeTouchable).isTrue()          }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt index ac8387f28e6c..8f7a56de0040 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt @@ -20,17 +20,21 @@  package com.android.systemui.statusbar.notification.stack.ui.viewmodel  import android.platform.test.annotations.DisableFlags -import androidx.test.ext.junit.runners.AndroidJUnit4 +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.FlagsParameterization  import androidx.test.filters.SmallTest  import com.android.systemui.Flags.FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX +import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT  import com.android.systemui.Flags.FLAG_SCENE_CONTAINER  import com.android.systemui.SysuiTestCase  import com.android.systemui.common.shared.model.NotificationContainerBounds  import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.coroutines.collectValues +import com.android.systemui.flags.BrokenWithSceneContainer  import com.android.systemui.flags.EnableSceneContainer  import com.android.systemui.flags.Flags +import com.android.systemui.flags.andSceneContainer  import com.android.systemui.flags.fakeFeatureFlagsClassic  import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository  import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository @@ -47,6 +51,8 @@ import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel  import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel  import com.android.systemui.kosmos.testScope  import com.android.systemui.res.R +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.shared.flag.sceneContainerFlags  import com.android.systemui.shade.data.repository.shadeRepository  import com.android.systemui.shade.mockLargeScreenHeaderHelper  import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor @@ -64,19 +70,36 @@ import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith  import org.mockito.Mockito.mock +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters  @SmallTest -@RunWith(AndroidJUnit4::class) -class SharedNotificationContainerViewModelTest : SysuiTestCase() { +@RunWith(ParameterizedAndroidJunit4::class) +// SharedNotificationContainerViewModel is only bound when FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT is on +@EnableFlags(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) +class SharedNotificationContainerViewModelTest(flags: FlagsParameterization?) : SysuiTestCase() { + +    companion object { +        @JvmStatic +        @Parameters(name = "{0}") +        fun getParams(): List<FlagsParameterization> { +            return FlagsParameterization.allCombinationsOf( +                    FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX, +                ) +                .andSceneContainer() +        } +    } + +    init { +        mSetFlagsRule.setFlagsParameterization(flags!!) +    } +      val aodBurnInViewModel = mock(AodBurnInViewModel::class.java)      lateinit var movementFlow: MutableStateFlow<BurnInModel>      val kosmos =          testKosmos().apply { -            fakeFeatureFlagsClassic.apply { -                set(Flags.FULL_SCREEN_USER_SWITCHER, false) -                set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) -            } +            fakeFeatureFlagsClassic.apply { set(Flags.FULL_SCREEN_USER_SWITCHER, false) }          }      init { @@ -84,19 +107,28 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {      }      val testScope = kosmos.testScope -    val configurationRepository = kosmos.fakeConfigurationRepository -    val keyguardRepository = kosmos.fakeKeyguardRepository -    val keyguardInteractor = kosmos.keyguardInteractor -    val keyguardRootViewModel = kosmos.keyguardRootViewModel -    val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository -    val shadeRepository = kosmos.shadeRepository -    val sharedNotificationContainerInteractor = kosmos.sharedNotificationContainerInteractor -    val largeScreenHeaderHelper = kosmos.mockLargeScreenHeaderHelper +    val configurationRepository +        get() = kosmos.fakeConfigurationRepository +    val keyguardRepository +        get() = kosmos.fakeKeyguardRepository +    val keyguardInteractor +        get() = kosmos.keyguardInteractor +    val keyguardRootViewModel +        get() = kosmos.keyguardRootViewModel +    val keyguardTransitionRepository +        get() = kosmos.fakeKeyguardTransitionRepository +    val shadeRepository +        get() = kosmos.shadeRepository +    val sharedNotificationContainerInteractor +        get() = kosmos.sharedNotificationContainerInteractor +    val largeScreenHeaderHelper +        get() = kosmos.mockLargeScreenHeaderHelper      lateinit var underTest: SharedNotificationContainerViewModel      @Before      fun setUp() { +        assertThat(kosmos.sceneContainerFlags.isEnabled()).isEqualTo(SceneContainerFlag.isEnabled)          overrideResource(R.bool.config_use_split_notification_shade, false)          movementFlow = MutableStateFlow(BurnInModel())          whenever(aodBurnInViewModel.movement(any())).thenReturn(movementFlow) @@ -130,9 +162,9 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)      fun validatePaddingTopInSplitShade_refactorFlagOff_usesLargeHeaderResource() =          testScope.runTest { -            mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)              whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)              overrideResource(R.bool.config_use_split_notification_shade, true)              overrideResource(R.bool.config_use_large_screen_shade_header, true) @@ -148,9 +180,9 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @EnableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)      fun validatePaddingTopInSplitShade_refactorFlagOn_usesLargeHeaderHelper() =          testScope.runTest { -            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)              whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5)              overrideResource(R.bool.config_use_split_notification_shade, true)              overrideResource(R.bool.config_use_large_screen_shade_header, true) @@ -243,9 +275,9 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {      @Test      @DisableFlags(FLAG_SCENE_CONTAINER) +    @EnableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)      fun validateMarginTopWithLargeScreenHeader_refactorFlagOn_usesHelper() =          testScope.runTest { -            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)              val headerResourceHeight = 50              val headerHelperHeight = 100              whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()) @@ -263,9 +295,9 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {      @Test      @EnableSceneContainer +    @EnableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)      fun validateMarginTopWithLargeScreenHeader_sceneContainerFlagOn_stillZero() =          testScope.runTest { -            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)              val headerResourceHeight = 50              val headerHelperHeight = 100              whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()) @@ -282,6 +314,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @BrokenWithSceneContainer(bugId = 333132830)      fun glanceableHubAlpha_lockscreenToHub() =          testScope.runTest {              val alpha by collectLastValue(underTest.glanceableHubAlpha) @@ -431,6 +464,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @BrokenWithSceneContainer(bugId = 333132830)      fun isOnLockscreenWithoutShade() =          testScope.runTest {              val isOnLockscreenWithoutShade by collectLastValue(underTest.isOnLockscreenWithoutShade) @@ -467,6 +501,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @BrokenWithSceneContainer(bugId = 333132830)      fun isOnGlanceableHubWithoutShade() =          testScope.runTest {              val isOnGlanceableHubWithoutShade by @@ -503,6 +538,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(FLAG_SCENE_CONTAINER)      fun boundsOnLockscreenNotInSplitShade() =          testScope.runTest {              val bounds by collectLastValue(underTest.bounds) @@ -523,9 +559,9 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX, FLAG_SCENE_CONTAINER)      fun boundsOnLockscreenInSplitShade_refactorFlagOff_usesLargeHeaderResource() =          testScope.runTest { -            mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)              val bounds by collectLastValue(underTest.bounds)              // When in split shade @@ -547,13 +583,20 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {              runCurrent()              // Top should be equal to bounds (1) - padding adjustment (10) -            assertThat(bounds).isEqualTo(NotificationContainerBounds(top = -9f, bottom = 2f)) +            assertThat(bounds) +                .isEqualTo( +                    NotificationContainerBounds( +                        top = -9f, +                        bottom = 2f, +                    ) +                )          }      @Test +    @EnableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX) +    @DisableFlags(FLAG_SCENE_CONTAINER)      fun boundsOnLockscreenInSplitShade_refactorFlagOn_usesLargeHeaderHelper() =          testScope.runTest { -            mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)              val bounds by collectLastValue(underTest.bounds)              // When in split shade @@ -579,6 +622,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(FLAG_SCENE_CONTAINER)      fun boundsOnShade() =          testScope.runTest {              val bounds by collectLastValue(underTest.bounds) @@ -594,6 +638,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(FLAG_SCENE_CONTAINER)      fun boundsOnQS() =          testScope.runTest {              val bounds by collectLastValue(underTest.bounds) @@ -638,6 +683,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @BrokenWithSceneContainer(bugId = 333132830)      fun maxNotificationsOnLockscreen_DoesNotUpdateWhenUserInteracting() =          testScope.runTest {              var notificationCount = 10 @@ -674,6 +720,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @BrokenWithSceneContainer(bugId = 333132830)      fun maxNotificationsOnShade() =          testScope.runTest {              val calculateSpace = { space: Float, useExtraShelfSpace: Boolean -> 10 } @@ -693,6 +740,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(FLAG_SCENE_CONTAINER)      fun translationYUpdatesOnKeyguardForBurnIn() =          testScope.runTest {              val translationY by collectLastValue(underTest.translationY(BurnInParameters())) @@ -726,6 +774,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(FLAG_SCENE_CONTAINER)      fun translationYDoesNotUpdateWhenShadeIsExpanded() =          testScope.runTest {              val translationY by collectLastValue(underTest.translationY(BurnInParameters())) @@ -746,6 +795,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @DisableFlags(FLAG_SCENE_CONTAINER)      fun updateBounds_fromKeyguardRoot() =          testScope.runTest {              val bounds by collectLastValue(underTest.bounds) @@ -757,6 +807,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @BrokenWithSceneContainer(bugId = 333132830)      fun alphaOnFullQsExpansion() =          testScope.runTest {              val viewState = ViewStateAccessor() @@ -864,6 +915,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {          }      @Test +    @BrokenWithSceneContainer(bugId = 333132830)      fun shadeCollapseFadeIn() =          testScope.runTest {              val fadeIn by collectValues(underTest.shadeCollapseFadeIn) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt index c8062fb4e724..f0498ded64a5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt @@ -16,57 +16,20 @@  package com.android.systemui.statusbar.phone -import android.app.ActivityOptions  import android.app.PendingIntent  import android.content.Intent -import android.os.Bundle -import android.os.RemoteException -import android.os.UserHandle -import android.view.View -import android.widget.FrameLayout -import android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest -import com.android.keyguard.KeyguardUpdateMonitor -import com.android.systemui.ActivityIntentHelper  import com.android.systemui.SysuiTestCase -import com.android.systemui.animation.ActivityTransitionAnimator -import com.android.systemui.animation.LaunchableView -import com.android.systemui.assist.AssistManager -import com.android.systemui.keyguard.KeyguardViewMediator -import com.android.systemui.keyguard.WakefulnessLifecycle -import com.android.systemui.plugins.ActivityStarter.OnDismissAction -import com.android.systemui.settings.UserTracker -import com.android.systemui.shade.ShadeController -import com.android.systemui.shade.data.repository.FakeShadeRepository -import com.android.systemui.shade.data.repository.ShadeAnimationRepository -import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl -import com.android.systemui.statusbar.CommandQueue -import com.android.systemui.statusbar.NotificationLockscreenUserManager -import com.android.systemui.statusbar.NotificationShadeWindowController  import com.android.systemui.statusbar.SysuiStatusBarStateController -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow -import com.android.systemui.statusbar.policy.DeviceProvisionedController -import com.android.systemui.statusbar.policy.KeyguardStateController -import com.android.systemui.statusbar.window.StatusBarWindowController  import com.android.systemui.util.concurrency.FakeExecutor -import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.argumentCaptor -import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.nullable -import com.android.systemui.util.mockito.whenever  import com.android.systemui.util.time.FakeSystemClock  import com.google.common.truth.Truth.assertThat -import dagger.Lazy -import java.util.Optional  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.anyBoolean  import org.mockito.Mockito.mock -import org.mockito.Mockito.never  import org.mockito.Mockito.times  import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations @@ -74,177 +37,22 @@ import org.mockito.MockitoAnnotations  @SmallTest  @RunWith(AndroidJUnit4::class)  class ActivityStarterImplTest : SysuiTestCase() { -    @Mock private lateinit var centralSurfaces: CentralSurfaces -    @Mock private lateinit var assistManager: AssistManager -    @Mock private lateinit var dozeServiceHost: DozeServiceHost -    @Mock private lateinit var biometricUnlockController: BiometricUnlockController -    @Mock private lateinit var keyguardViewMediator: KeyguardViewMediator -    @Mock private lateinit var shadeController: ShadeController -    @Mock private lateinit var commandQueue: CommandQueue -    @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager -    @Mock private lateinit var mActivityTransitionAnimator: ActivityTransitionAnimator -    @Mock private lateinit var lockScreenUserManager: NotificationLockscreenUserManager -    @Mock private lateinit var statusBarWindowController: StatusBarWindowController -    @Mock private lateinit var notifShadeWindowController: NotificationShadeWindowController -    @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle -    @Mock private lateinit var keyguardStateController: KeyguardStateController +    @Mock private lateinit var legacyActivityStarterInternal: LegacyActivityStarterInternalImpl +    @Mock private lateinit var activityStarterInternal: ActivityStarterInternalImpl      @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController -    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor -    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController -    @Mock private lateinit var userTracker: UserTracker -    @Mock private lateinit var activityIntentHelper: ActivityIntentHelper      private lateinit var underTest: ActivityStarterImpl      private val mainExecutor = FakeExecutor(FakeSystemClock()) -    private val shadeAnimationInteractor = -        ShadeAnimationInteractorLegacyImpl(ShadeAnimationRepository(), FakeShadeRepository())      @Before      fun setUp() {          MockitoAnnotations.initMocks(this)          underTest =              ActivityStarterImpl( -                Lazy { Optional.of(centralSurfaces) }, -                Lazy { assistManager }, -                Lazy { dozeServiceHost }, -                Lazy { biometricUnlockController }, -                Lazy { keyguardViewMediator }, -                Lazy { shadeController }, -                commandQueue, -                shadeAnimationInteractor, -                Lazy { statusBarKeyguardViewManager }, -                Lazy { notifShadeWindowController }, -                mActivityTransitionAnimator, -                context, -                DISPLAY_ID, -                lockScreenUserManager, -                statusBarWindowController, -                wakefulnessLifecycle, -                keyguardStateController, -                statusBarStateController, -                keyguardUpdateMonitor, -                deviceProvisionedController, -                userTracker, -                activityIntentHelper, -                mainExecutor, +                statusBarStateController = statusBarStateController, +                mainExecutor = mainExecutor, +                legacyActivityStarter = { legacyActivityStarterInternal }, +                activityStarterInternal = { activityStarterInternal },              ) -        whenever(userTracker.userHandle).thenReturn(UserHandle.OWNER) -    } - -    @Test -    fun startPendingIntentDismissingKeyguard_keyguardShowing_dismissWithAction() { -        val pendingIntent = mock(PendingIntent::class.java) -        whenever(pendingIntent.isActivity).thenReturn(true) -        whenever(keyguardStateController.isShowing).thenReturn(true) -        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) - -        underTest.startPendingIntentDismissingKeyguard(pendingIntent) -        mainExecutor.runAllReady() - -        verify(statusBarKeyguardViewManager) -            .dismissWithAction(any(OnDismissAction::class.java), eq(null), anyBoolean(), eq(null)) -    } - -    @Test -    fun startPendingIntentMaybeDismissingKeyguard_keyguardShowing_showOverLs_launchAnimator() { -        val pendingIntent = mock(PendingIntent::class.java) -        val parent = FrameLayout(context) -        val view = -            object : View(context), LaunchableView { -                override fun setShouldBlockVisibilityChanges(block: Boolean) {} -            } -        parent.addView(view) -        val controller = ActivityTransitionAnimator.Controller.fromView(view) -        whenever(pendingIntent.isActivity).thenReturn(true) -        whenever(keyguardStateController.isShowing).thenReturn(true) -        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) -        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(eq(pendingIntent), anyInt())) -            .thenReturn(true) - -        underTest.startPendingIntentMaybeDismissingKeyguard( -            intent = pendingIntent, -            animationController = controller, -            intentSentUiThreadCallback = null, -        ) -        mainExecutor.runAllReady() - -        verify(mActivityTransitionAnimator) -            .startPendingIntentWithAnimation( -                nullable(), -                eq(true), -                nullable(), -                eq(true), -                any(), -            ) -    } - -    fun startPendingIntentDismissingKeyguard_fillInIntentAndExtraOptions_sendAndReturnResult() { -        val pendingIntent = mock(PendingIntent::class.java) -        val fillInIntent = mock(Intent::class.java) -        val parent = FrameLayout(context) -        val view = -            object : View(context), LaunchableView { -                override fun setShouldBlockVisibilityChanges(block: Boolean) {} -            } -        parent.addView(view) -        val controller = ActivityTransitionAnimator.Controller.fromView(view) -        whenever(pendingIntent.isActivity).thenReturn(true) -        whenever(keyguardStateController.isShowing).thenReturn(true) -        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) -        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(eq(pendingIntent), anyInt())) -            .thenReturn(false) - -        // extra activity options to set on pending intent -        val activityOptions = mock(ActivityOptions::class.java) -        activityOptions.splashScreenStyle = SPLASH_SCREEN_STYLE_SOLID_COLOR -        activityOptions.isPendingIntentBackgroundActivityLaunchAllowedByPermission = false -        val bundleCaptor = argumentCaptor<Bundle>() - -        underTest.startPendingIntentMaybeDismissingKeyguard( -            intent = pendingIntent, -            animationController = controller, -            intentSentUiThreadCallback = null, -            fillInIntent = fillInIntent, -            extraOptions = activityOptions.toBundle(), -        ) -        mainExecutor.runAllReady() - -        // Fill-in intent is passed and options contain extra values specified -        verify(pendingIntent) -            .sendAndReturnResult( -                eq(context), -                eq(0), -                eq(fillInIntent), -                nullable(), -                nullable(), -                nullable(), -                bundleCaptor.capture() -            ) -        val options = ActivityOptions.fromBundle(bundleCaptor.value) -        assertThat(options.isPendingIntentBackgroundActivityLaunchAllowedByPermission).isFalse() -        assertThat(options.splashScreenStyle).isEqualTo(SPLASH_SCREEN_STYLE_SOLID_COLOR) -    } - -    @Test -    fun startPendingIntentDismissingKeyguard_associatedView_getAnimatorController() { -        val pendingIntent = mock(PendingIntent::class.java) -        val associatedView = mock(ExpandableNotificationRow::class.java) - -        underTest.startPendingIntentDismissingKeyguard( -            intent = pendingIntent, -            intentSentUiThreadCallback = null, -            associatedView = associatedView, -        ) - -        verify(centralSurfaces).getAnimatorControllerFromNotification(associatedView) -    } - -    @Test -    fun startActivity_noUserHandleProvided_getUserHandle() { -        val intent = mock(Intent::class.java) - -        underTest.startActivity(intent, false) - -        verify(userTracker).userHandle      }      @Test @@ -258,115 +66,9 @@ class ActivityStarterImplTest : SysuiTestCase() {      @Test      fun postStartActivityDismissingKeyguard_intent_postsOnMain() { -        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) -        val intent = mock(Intent::class.java) - -        underTest.postStartActivityDismissingKeyguard(intent, 0) +        underTest.postStartActivityDismissingKeyguard(mock(Intent::class.java), 0)          assertThat(mainExecutor.numPending()).isEqualTo(1) -        mainExecutor.runAllReady() - -        verify(deviceProvisionedController).isDeviceProvisioned -        verify(shadeController).collapseShadeForActivityStart() -    } - -    @Test -    fun postStartActivityDismissingKeyguard_intent_notDeviceProvisioned_doesNotProceed() { -        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(false) -        val intent = mock(Intent::class.java) - -        underTest.postStartActivityDismissingKeyguard(intent, 0) -        mainExecutor.runAllReady() - -        verify(deviceProvisionedController).isDeviceProvisioned -        verify(shadeController, never()).collapseShadeForActivityStart() -    } - -    @Test -    fun dismissKeyguardThenExecute_startWakeAndUnlock() { -        whenever(wakefulnessLifecycle.wakefulness) -            .thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP) -        whenever(keyguardStateController.canDismissLockScreen()).thenReturn(true) -        whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false) -        whenever(dozeServiceHost.isPulsing).thenReturn(true) - -        underTest.dismissKeyguardThenExecute({ true }, {}, false) - -        verify(biometricUnlockController) -            .startWakeAndUnlock(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) -    } - -    @Test -    fun dismissKeyguardThenExecute_keyguardIsShowing_dismissWithAction() { -        val customMessage = "Enter your pin." -        whenever(keyguardStateController.isShowing).thenReturn(true) - -        underTest.dismissKeyguardThenExecute({ true }, {}, false, customMessage) - -        verify(statusBarKeyguardViewManager) -            .dismissWithAction( -                any(OnDismissAction::class.java), -                any(Runnable::class.java), -                eq(false), -                eq(customMessage) -            ) -    } - -    @Test -    fun dismissKeyguardThenExecute_awakeDreams() { -        val customMessage = "Enter your pin." -        var dismissActionExecuted = false -        whenever(keyguardStateController.isShowing).thenReturn(false) -        whenever(keyguardUpdateMonitor.isDreaming).thenReturn(true) - -        underTest.dismissKeyguardThenExecute( -            { -                dismissActionExecuted = true -                true -            }, -            {}, -            false, -            customMessage -        ) - -        verify(centralSurfaces).awakenDreams() -        assertThat(dismissActionExecuted).isTrue() -    } - -    @Test -    @Throws(RemoteException::class) -    fun executeRunnableDismissingKeyguard_dreaming_notShowing_awakenDreams() { -        whenever(keyguardStateController.isShowing).thenReturn(false) -        whenever(keyguardStateController.isOccluded).thenReturn(false) -        whenever(keyguardUpdateMonitor.isDreaming).thenReturn(true) - -        underTest.executeRunnableDismissingKeyguard( -            runnable = {}, -            cancelAction = null, -            dismissShade = false, -            afterKeyguardGone = false, -            deferred = false -        ) - -        verify(centralSurfaces, times(1)).awakenDreams() -    } - -    @Test -    @Throws(RemoteException::class) -    fun executeRunnableDismissingKeyguard_notDreaming_notShowing_doNotAwakenDreams() { -        whenever(keyguardStateController.isShowing).thenReturn(false) -        whenever(keyguardStateController.isOccluded).thenReturn(false) -        whenever(keyguardUpdateMonitor.isDreaming).thenReturn(false) - -        underTest.executeRunnableDismissingKeyguard( -            runnable = {}, -            cancelAction = null, -            dismissShade = false, -            afterKeyguardGone = false, -            deferred = false -        ) - -        verify(centralSurfaces, never()).awakenDreams()      }      @Test @@ -377,8 +79,4 @@ class ActivityStarterImplTest : SysuiTestCase() {          mainExecutor.runAllReady()          verify(statusBarStateController).setLeaveOpenOnKeyguardHide(true)      } - -    private companion object { -        private const val DISPLAY_ID = 0 -    }  } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt new file mode 100644 index 000000000000..b443489f98e2 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImplTest.kt @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone + +import android.app.ActivityOptions +import android.app.PendingIntent +import android.content.Intent +import android.os.Bundle +import android.os.RemoteException +import android.os.UserHandle +import android.view.View +import android.widget.FrameLayout +import android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.ActivityIntentHelper +import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.ActivityTransitionAnimator +import com.android.systemui.animation.LaunchableView +import com.android.systemui.assist.AssistManager +import com.android.systemui.keyguard.KeyguardViewMediator +import com.android.systemui.keyguard.WakefulnessLifecycle +import com.android.systemui.plugins.ActivityStarter.OnDismissAction +import com.android.systemui.settings.UserTracker +import com.android.systemui.shade.ShadeController +import com.android.systemui.shade.data.repository.FakeShadeRepository +import com.android.systemui.shade.data.repository.ShadeAnimationRepository +import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl +import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.statusbar.NotificationLockscreenUserManager +import com.android.systemui.statusbar.NotificationShadeWindowController +import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.policy.DeviceProvisionedController +import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.statusbar.window.StatusBarWindowController +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.argumentCaptor +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.nullable +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat +import java.util.Optional +import kotlinx.coroutines.ExperimentalCoroutinesApi +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.anyBoolean +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class LegacyActivityStarterInternalImplTest : SysuiTestCase() { +    @Mock private lateinit var centralSurfaces: CentralSurfaces +    @Mock private lateinit var assistManager: AssistManager +    @Mock private lateinit var dozeServiceHost: DozeServiceHost +    @Mock private lateinit var biometricUnlockController: BiometricUnlockController +    @Mock private lateinit var keyguardViewMediator: KeyguardViewMediator +    @Mock private lateinit var shadeController: ShadeController +    @Mock private lateinit var commandQueue: CommandQueue +    @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager +    @Mock private lateinit var activityTransitionAnimator: ActivityTransitionAnimator +    @Mock private lateinit var lockScreenUserManager: NotificationLockscreenUserManager +    @Mock private lateinit var statusBarWindowController: StatusBarWindowController +    @Mock private lateinit var notifShadeWindowController: NotificationShadeWindowController +    @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle +    @Mock private lateinit var keyguardStateController: KeyguardStateController +    @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController +    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor +    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController +    @Mock private lateinit var userTracker: UserTracker +    @Mock private lateinit var activityIntentHelper: ActivityIntentHelper +    private lateinit var underTest: LegacyActivityStarterInternalImpl +    private val mainExecutor = FakeExecutor(FakeSystemClock()) +    private val shadeAnimationInteractor = +        ShadeAnimationInteractorLegacyImpl(ShadeAnimationRepository(), FakeShadeRepository()) + +    @Before +    fun setUp() { +        MockitoAnnotations.initMocks(this) +        underTest = +            LegacyActivityStarterInternalImpl( +                centralSurfacesOptLazy = { Optional.of(centralSurfaces) }, +                assistManagerLazy = { assistManager }, +                dozeServiceHostLazy = { dozeServiceHost }, +                biometricUnlockControllerLazy = { biometricUnlockController }, +                keyguardViewMediatorLazy = { keyguardViewMediator }, +                shadeControllerLazy = { shadeController }, +                commandQueue = commandQueue, +                shadeAnimationInteractor = shadeAnimationInteractor, +                statusBarKeyguardViewManagerLazy = { statusBarKeyguardViewManager }, +                notifShadeWindowControllerLazy = { notifShadeWindowController }, +                activityTransitionAnimator = activityTransitionAnimator, +                context = context, +                displayId = DISPLAY_ID, +                lockScreenUserManager = lockScreenUserManager, +                statusBarWindowController = statusBarWindowController, +                wakefulnessLifecycle = wakefulnessLifecycle, +                keyguardStateController = keyguardStateController, +                statusBarStateController = statusBarStateController, +                keyguardUpdateMonitor = keyguardUpdateMonitor, +                deviceProvisionedController = deviceProvisionedController, +                userTracker = userTracker, +                activityIntentHelper = activityIntentHelper, +                mainExecutor = mainExecutor, +            ) +        whenever(userTracker.userHandle).thenReturn(UserHandle.OWNER) +    } + +    @Test +    fun startPendingIntentDismissingKeyguard_keyguardShowing_dismissWithAction() { +        val pendingIntent = mock(PendingIntent::class.java) +        whenever(pendingIntent.isActivity).thenReturn(true) +        whenever(keyguardStateController.isShowing).thenReturn(true) +        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) + +        underTest.startPendingIntentDismissingKeyguard(pendingIntent) +        mainExecutor.runAllReady() + +        verify(statusBarKeyguardViewManager) +            .dismissWithAction(any(OnDismissAction::class.java), eq(null), anyBoolean(), eq(null)) +    } + +    @Test +    fun startPendingIntentMaybeDismissingKeyguard_keyguardShowing_showOverLs_launchAnimator() { +        val pendingIntent = mock(PendingIntent::class.java) +        val parent = FrameLayout(context) +        val view = +            object : View(context), LaunchableView { +                override fun setShouldBlockVisibilityChanges(block: Boolean) {} +            } +        parent.addView(view) +        val controller = ActivityTransitionAnimator.Controller.fromView(view) +        whenever(pendingIntent.isActivity).thenReturn(true) +        whenever(keyguardStateController.isShowing).thenReturn(true) +        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(eq(pendingIntent), anyInt())) +            .thenReturn(true) + +        startPendingIntentMaybeDismissingKeyguard( +            intent = pendingIntent, +            animationController = controller, +            intentSentUiThreadCallback = null, +        ) +        mainExecutor.runAllReady() + +        verify(activityTransitionAnimator) +            .startPendingIntentWithAnimation( +                nullable(), +                eq(true), +                nullable(), +                eq(true), +                any(), +            ) +    } + +    fun startPendingIntentDismissingKeyguard_fillInIntentAndExtraOptions_sendAndReturnResult() { +        val pendingIntent = mock(PendingIntent::class.java) +        val fillInIntent = mock(Intent::class.java) +        val parent = FrameLayout(context) +        val view = +            object : View(context), LaunchableView { +                override fun setShouldBlockVisibilityChanges(block: Boolean) {} +            } +        parent.addView(view) +        val controller = ActivityTransitionAnimator.Controller.fromView(view) +        whenever(pendingIntent.isActivity).thenReturn(true) +        whenever(keyguardStateController.isShowing).thenReturn(true) +        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true) +        whenever(activityIntentHelper.wouldPendingShowOverLockscreen(eq(pendingIntent), anyInt())) +            .thenReturn(false) + +        // extra activity options to set on pending intent +        val activityOptions = mock(ActivityOptions::class.java) +        activityOptions.splashScreenStyle = SPLASH_SCREEN_STYLE_SOLID_COLOR +        activityOptions.isPendingIntentBackgroundActivityLaunchAllowedByPermission = false +        val bundleCaptor = argumentCaptor<Bundle>() + +        startPendingIntentMaybeDismissingKeyguard( +            intent = pendingIntent, +            animationController = controller, +            intentSentUiThreadCallback = null, +            fillInIntent = fillInIntent, +            extraOptions = activityOptions.toBundle(), +        ) +        mainExecutor.runAllReady() + +        // Fill-in intent is passed and options contain extra values specified +        verify(pendingIntent) +            .sendAndReturnResult( +                eq(context), +                eq(0), +                eq(fillInIntent), +                nullable(), +                nullable(), +                nullable(), +                bundleCaptor.capture() +            ) +        val options = ActivityOptions.fromBundle(bundleCaptor.value) +        assertThat(options.isPendingIntentBackgroundActivityLaunchAllowedByPermission).isFalse() +        assertThat(options.splashScreenStyle).isEqualTo(SPLASH_SCREEN_STYLE_SOLID_COLOR) +    } + +    @Test +    fun startPendingIntentDismissingKeyguard_associatedView_getAnimatorController() { +        val pendingIntent = mock(PendingIntent::class.java) +        val associatedView = mock(ExpandableNotificationRow::class.java) + +        underTest.startPendingIntentDismissingKeyguard( +            intent = pendingIntent, +            intentSentUiThreadCallback = null, +            associatedView = associatedView, +        ) + +        verify(centralSurfaces).getAnimatorControllerFromNotification(associatedView) +    } + +    @Test +    fun startActivity_noUserHandleProvided_getUserHandle() { +        val intent = mock(Intent::class.java) + +        underTest.startActivity(intent, false, null, false, null) + +        verify(userTracker).userHandle +    } + +    @Test +    fun dismissKeyguardThenExecute_startWakeAndUnlock() { +        whenever(wakefulnessLifecycle.wakefulness) +            .thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP) +        whenever(keyguardStateController.canDismissLockScreen()).thenReturn(true) +        whenever(statusBarStateController.leaveOpenOnKeyguardHide()).thenReturn(false) +        whenever(dozeServiceHost.isPulsing).thenReturn(true) + +        underTest.dismissKeyguardThenExecute({ true }, {}, false) + +        verify(biometricUnlockController) +            .startWakeAndUnlock(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) +    } + +    @Test +    fun dismissKeyguardThenExecute_keyguardIsShowing_dismissWithAction() { +        val customMessage = "Enter your pin." +        whenever(keyguardStateController.isShowing).thenReturn(true) + +        underTest.dismissKeyguardThenExecute({ true }, {}, false, customMessage) + +        verify(statusBarKeyguardViewManager) +            .dismissWithAction( +                any(OnDismissAction::class.java), +                any(Runnable::class.java), +                eq(false), +                eq(customMessage) +            ) +    } + +    @Test +    fun dismissKeyguardThenExecute_awakeDreams() { +        val customMessage = "Enter your pin." +        var dismissActionExecuted = false +        whenever(keyguardStateController.isShowing).thenReturn(false) +        whenever(keyguardUpdateMonitor.isDreaming).thenReturn(true) + +        underTest.dismissKeyguardThenExecute( +            { +                dismissActionExecuted = true +                true +            }, +            {}, +            false, +            customMessage +        ) + +        verify(centralSurfaces).awakenDreams() +        assertThat(dismissActionExecuted).isTrue() +    } + +    @Test +    @Throws(RemoteException::class) +    fun executeRunnableDismissingKeyguard_dreaming_notShowing_awakenDreams() { +        whenever(keyguardStateController.isShowing).thenReturn(false) +        whenever(keyguardStateController.isOccluded).thenReturn(false) +        whenever(keyguardUpdateMonitor.isDreaming).thenReturn(true) + +        underTest.executeRunnableDismissingKeyguard( +            runnable = {}, +            cancelAction = null, +            dismissShade = false, +            afterKeyguardGone = false, +            deferred = false +        ) + +        verify(centralSurfaces, times(1)).awakenDreams() +    } + +    @Test +    @Throws(RemoteException::class) +    fun executeRunnableDismissingKeyguard_notDreaming_notShowing_doNotAwakenDreams() { +        whenever(keyguardStateController.isShowing).thenReturn(false) +        whenever(keyguardStateController.isOccluded).thenReturn(false) +        whenever(keyguardUpdateMonitor.isDreaming).thenReturn(false) + +        underTest.executeRunnableDismissingKeyguard( +            runnable = {}, +            cancelAction = null, +            dismissShade = false, +            afterKeyguardGone = false, +            deferred = false +        ) + +        verify(centralSurfaces, never()).awakenDreams() +    } + +    private fun startPendingIntentMaybeDismissingKeyguard( +        intent: PendingIntent, +        intentSentUiThreadCallback: Runnable?, +        animationController: ActivityTransitionAnimator.Controller?, +        fillInIntent: Intent? = null, +        extraOptions: Bundle? = null, +    ) { +        underTest.startPendingIntentDismissingKeyguard( +            intent = intent, +            intentSentUiThreadCallback = intentSentUiThreadCallback, +            animationController = animationController, +            showOverLockscreen = true, +            fillInIntent = fillInIntent, +            extraOptions = extraOptions, +        ) +    } + +    private companion object { +        private const val DISPLAY_ID = 0 +    } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java index 3c9dc6345d31..69207ba07e6e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java @@ -89,7 +89,7 @@ class TestableHeadsUpManager extends BaseHeadsUpManager {      }      @Override -    public boolean isHeadsUpGoingAway() { +    public boolean isHeadsUpAnimatingAwayValue() {          throw new UnsupportedOperationException();      } @@ -115,7 +115,7 @@ class TestableHeadsUpManager extends BaseHeadsUpManager {      }      @Override -    public void setHeadsUpGoingAway(boolean headsUpGoingAway) { +    public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {          throw new UnsupportedOperationException();      } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/startable/AudioModeLoggerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/startable/AudioModeLoggerStartableTest.kt new file mode 100644 index 000000000000..8bb36724d1d8 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/startable/AudioModeLoggerStartableTest.kt @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.volume.domain.startable + +import android.media.AudioManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.internal.logging.uiEventLogger +import com.android.internal.logging.uiEventLoggerFake +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.android.systemui.volume.audioModeInteractor +import com.android.systemui.volume.audioRepository +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule + +@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(AndroidJUnit4::class) +@SmallTest +class AudioModeLoggerStartableTest : SysuiTestCase() { +    @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule() + +    private val kosmos = testKosmos() + +    private lateinit var underTest: AudioModeLoggerStartable + +    @Before +    fun setUp() { +        with(kosmos) { +            underTest = +                AudioModeLoggerStartable( +                    applicationCoroutineScope, +                    uiEventLogger, +                    audioModeInteractor +                ) +        } +    } + +    @Test +    fun audioMode_inCall() { +        with(kosmos) { +            testScope.runTest { +                audioRepository.setMode(AudioManager.MODE_IN_CALL) + +                underTest.start() +                runCurrent() + +                assertThat(uiEventLoggerFake.eventId(0)) +                    .isEqualTo(VolumePanelUiEvent.VOLUME_PANEL_AUDIO_MODE_CHANGE_TO_CALLING.id) +            } +        } +    } + +    @Test +    fun audioMode_notInCall() { +        with(kosmos) { +            testScope.runTest { +                audioRepository.setMode(AudioManager.MODE_NORMAL) + +                underTest.start() +                runCurrent() + +                assertThat(uiEventLoggerFake.eventId(0)) +                    .isEqualTo(VolumePanelUiEvent.VOLUME_PANEL_AUDIO_MODE_CHANGE_TO_NORMAL.id) +            } +        } +    } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt index e31cdcd82e7e..dc9613904e4e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt @@ -72,7 +72,7 @@ class AncSliceRepositoryTest : SysuiTestCase() {              testScope.runTest {                  localMediaRepository.updateCurrentConnectedDevice(null) -                val slice by collectLastValue(underTest.ancSlice(1)) +                val slice by collectLastValue(underTest.ancSlice(1, false, false))                  runCurrent()                  assertThat(slice).isNull() @@ -86,7 +86,7 @@ class AncSliceRepositoryTest : SysuiTestCase() {              testScope.runTest {                  localMediaRepository.updateCurrentConnectedDevice(createMediaDevice()) -                val slice by collectLastValue(underTest.ancSlice(1)) +                val slice by collectLastValue(underTest.ancSlice(1, false, false))                  runCurrent()                  assertThat(slice).isNotNull() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt index 53f0bc9ddb51..81e6ac412404 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt @@ -24,6 +24,7 @@ import com.android.systemui.kosmos.testScope  import com.android.systemui.testKosmos  import com.android.systemui.volume.panel.component.anc.FakeSliceFactory  import com.android.systemui.volume.panel.component.anc.ancSliceRepository +import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices  import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.test.runCurrent @@ -57,10 +58,10 @@ class AncSliceInteractorTest : SysuiTestCase() {                      FakeSliceFactory.createSlice(hasError = true, hasSliceItem = true)                  ) -                val slice by collectLastValue(underTest.ancSlice) +                val slice by collectLastValue(underTest.ancSlices)                  runCurrent() -                assertThat(slice).isNull() +                assertThat(slice).isInstanceOf(AncSlices.Unavailable::class.java)              }          }      } @@ -74,10 +75,10 @@ class AncSliceInteractorTest : SysuiTestCase() {                      FakeSliceFactory.createSlice(hasError = false, hasSliceItem = false)                  ) -                val slice by collectLastValue(underTest.ancSlice) +                val slice by collectLastValue(underTest.ancSlices)                  runCurrent() -                assertThat(slice).isNull() +                assertThat(slice).isInstanceOf(AncSlices.Unavailable::class.java)              }          }      } @@ -91,10 +92,10 @@ class AncSliceInteractorTest : SysuiTestCase() {                      FakeSliceFactory.createSlice(hasError = false, hasSliceItem = true)                  ) -                val slice by collectLastValue(underTest.ancSlice) +                val slice by collectLastValue(underTest.ancSlices)                  runCurrent() -                assertThat(slice).isNotNull() +                assertThat(slice).isInstanceOf(AncSlices.Ready::class.java)              }          }      } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt index 2cc1ad335535..27a813fb149e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt @@ -21,6 +21,8 @@ import android.content.Intent  import android.provider.Settings  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest +import com.android.internal.logging.uiEventLogger +import com.android.internal.logging.uiEventLoggerFake  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.kosmos.testScope @@ -29,6 +31,7 @@ import com.android.systemui.plugins.activityStarter  import com.android.systemui.testKosmos  import com.android.systemui.util.mockito.capture  import com.android.systemui.util.mockito.eq +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent  import com.android.systemui.volume.panel.volumePanelViewModel  import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -58,7 +61,10 @@ class BottomBarViewModelTest : SysuiTestCase() {      private lateinit var underTest: BottomBarViewModel      private fun initUnderTest() { -        underTest = with(kosmos) { BottomBarViewModel(activityStarter, volumePanelViewModel) } +        underTest = +            with(kosmos) { +                BottomBarViewModel(activityStarter, volumePanelViewModel, uiEventLogger) +            }      }      @Test @@ -96,6 +102,8 @@ class BottomBarViewModelTest : SysuiTestCase() {                          /* userHandle = */ eq(null),                      )                  assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_SOUND_SETTINGS) +                assertThat(uiEventLoggerFake.eventId(0)) +                    .isEqualTo(VolumePanelUiEvent.VOLUME_PANEL_SOUND_SETTINGS_CLICKED.id)                  activityStartedCaptor.value.onActivityStarted(ActivityManager.START_SUCCESS)                  val volumePanelState by collectLastValue(volumePanelViewModel.volumePanelState) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelTest.kt index 610195f5e87e..fdeded8422d6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.volume.panel.component.captioning.ui.viewmodel  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest +import com.android.internal.logging.uiEventLogger  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.kosmos.testScope @@ -45,7 +46,12 @@ class CaptioningViewModelTest : SysuiTestCase() {      fun setup() {          underTest =              with(kosmos) { -                CaptioningViewModel(context, captioningInteractor, testScope.backgroundScope) +                CaptioningViewModel( +                    context, +                    captioningInteractor, +                    testScope.backgroundScope, +                    uiEventLogger, +                )              }      } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt index ec55c75d4ae5..da0a2295143b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/domain/MediaOutputAvailabilityCriteriaTest.kt @@ -46,7 +46,10 @@ class MediaOutputAvailabilityCriteriaTest : SysuiTestCase() {      @Before      fun setup() { -        underTest = MediaOutputAvailabilityCriteria(kosmos.audioModeInteractor) +        underTest = +            MediaOutputAvailabilityCriteria( +                kosmos.audioModeInteractor, +            )      }      @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt index 462f36d73138..30524d93dc02 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelTest.kt @@ -22,6 +22,7 @@ import android.media.session.PlaybackState  import android.testing.TestableLooper  import androidx.test.ext.junit.runners.AndroidJUnit4  import androidx.test.filters.SmallTest +import com.android.internal.logging.uiEventLogger  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.kosmos.testScope @@ -64,6 +65,7 @@ class MediaOutputViewModelTest : SysuiTestCase() {                      mediaOutputActionsInteractor,                      mediaDeviceSessionInteractor,                      mediaOutputInteractor, +                    uiEventLogger,                  )              with(context.orCreateTestableResources) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractorTest.kt deleted file mode 100644 index 79d3fe9063b7..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractorTest.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.volume.panel.component.volume.domain.interactor - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.google.common.truth.Truth.assertThat -import org.junit.Test -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -@SmallTest -class VolumeSliderInteractorTest : SysuiTestCase() { - -    private val underTest = VolumeSliderInteractor() - -    @Test -    fun processVolumeToValue_returnsTranslatedVolume() { -        assertThat(underTest.processVolumeToValue(2, volumeRange)).isEqualTo(20f) -    } - -    private companion object { -        val volumeRange = 0..10 -    } -} diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml index 529d6090a501..b62e684b0105 100644 --- a/packages/SystemUI/res-keyguard/values-am/strings.xml +++ b/packages/SystemUI/res-keyguard/values-am/strings.xml @@ -108,7 +108,7 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"መሣሪያ እንደገና ከጀመረ በኋላ ስርዓተ ጥለት ያስፈልጋል"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"መሣሪያ እንደገና ከጀመረ በኋላ ፒን ያስፈልጋል"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"መሣሪያ እንደገና ከጀመረ በኋላ የይለፍ ቃል ያስፈልጋል"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ለተጨማሪ ደህንነት በምትኩ ስርዓተ ጥለት ይጠቀሙ"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ለተጨማሪ ደህንነት በምትኩ ሥርዓተ ጥለት ይጠቀሙ"</string>      <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ለተጨማሪ ደህንነት በምትኩ ፒን ይጠቀሙ"</string>      <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ለተጨማሪ ደህንነት በምትኩ የይለፍ ቃል ይጠቀሙ"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ፒን ለተጨማሪ ደህንነት ያስፈልጋል"</string> diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml index d07c5b560d44..427373de8bcc 100644 --- a/packages/SystemUI/res-keyguard/values-ar/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml @@ -21,13 +21,13 @@  <resources xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">      <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"أدخل رقم التعريف الشخصي (PIN)"</string> -    <string name="keyguard_enter_pin" msgid="8114529922480276834">"أدخِل رقم التعريف الشخصي."</string> +    <string name="keyguard_enter_pin" msgid="8114529922480276834">"أدخِل رقم التعريف الشخصي"</string>      <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"أدخل النقش"</string>      <string name="keyguard_enter_pattern" msgid="7616595160901084119">"ارسم النقش."</string>      <string name="keyguard_enter_your_password" msgid="7225626204122735501">"أدخل كلمة المرور"</string>      <string name="keyguard_enter_password" msgid="6483623792371009758">"أدخِل كلمة المرور."</string>      <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"بطاقة غير صالحة."</string> -    <string name="keyguard_charged" msgid="5478247181205188995">"تم الشحن"</string> +    <string name="keyguard_charged" msgid="5478247181205188995">"اكتمل الشحن"</string>      <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن لاسلكيًا"</string>      <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن"</string>      <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن"</string> @@ -80,9 +80,9 @@      <string name="kg_face_locked_out" msgid="2751559491287575">"يتعذّر فتح القفل بالوجه. أجريت محاولات كثيرة جدًا."</string>      <string name="kg_fp_locked_out" msgid="6228277682396768830">"يتعذّر الفتح ببصمة الإصبع. أجريت محاولات كثيرة جدًا."</string>      <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"ميزة \"الوكيل المعتمد\" غير متاحة."</string> -    <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"أجريت محاولات كثيرة جدًا بإدخال رقم تعريف شخصي خاطئ."</string> -    <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"أجريت محاولات كثيرة جدًا برسم نقش خاطئ."</string> -    <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"أجريت محاولات كثيرة جدًا بإدخال كلمة مرور خاطئة."</string> +    <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"أجريت محاولات كثيرة جدًا باستخدام رقم تعريف شخصي خاطئ"</string> +    <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"أجريت محاولات كثيرة جدًا باستخدام نقش خاطئ"</string> +    <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"أجريت محاولات كثيرة جدًا باستخدام كلمة مرور خاطئة"</string>      <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{أعِد المحاولة خلال ثانية واحدة.}zero{أعِد المحاولة خلال # ثانية.}two{أعِد المحاولة خلال ثانيتين.}few{أعِد المحاولة خلال # ثوانٍ.}many{أعِد المحاولة خلال # ثانية.}other{أعِد المحاولة خلال # ثانية.}}"</string>      <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"أدخل رقم التعريف الشخصي لشريحة SIM."</string>      <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"أدخل رقم التعريف الشخصي لشريحة SIM التابعة للمشغّل \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string> @@ -108,9 +108,9 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"يجب رسم النقش بعد إعادة تشغيل الجهاز."</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"يجب إدخال رقم التعريف الشخصي بعد إعادة تشغيل الجهاز."</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"يجب إدخال كلمة المرور بعد إعادة تشغيل الجهاز."</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"لمزيد من الأمان، استخدِم النقش بدلاً من ذلك."</string> -    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"لمزيد من الأمان، أدخِل رقم التعريف الشخصي بدلاً من ذلك."</string> -    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"لمزيد من الأمان، أدخِل كلمة المرور بدلاً من ذلك."</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"لمزيد من الأمان، يجب استخدام النقش"</string> +    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"لمزيد من الأمان، يجب إدخال رقم التعريف الشخصي"</string> +    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"لمزيد من الأمان، يجب إدخال كلمة المرور"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"يجب إدخال رقم التعريف الشخصي لمزيد من الأمان"</string>      <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"يجب رسم النقش لمزيد من الأمان"</string>      <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"يجب إدخال كلمة المرور لمزيد من الأمان"</string> diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml index ce8ebd3bf9e7..4ed7e27ff732 100644 --- a/packages/SystemUI/res-keyguard/values-as/strings.xml +++ b/packages/SystemUI/res-keyguard/values-as/strings.xml @@ -108,7 +108,7 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত আৰ্হিৰ আৱশ্যক"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত পিনৰ আৱশ্যক"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত পাছৱৰ্ডৰ আৱশ্যক"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"অতিৰিক্ত সুৰক্ষাৰ বাবে, ইয়াৰ পৰিৱৰ্তে আৰ্হি ব্যৱহাৰ কৰক"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"অতিৰিক্ত সুৰক্ষাৰ বাবে, আৰ্হি ব্যৱহাৰ কৰক"</string>      <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"অতিৰিক্ত সুৰক্ষাৰ বাবে, ইয়াৰ পৰিৱৰ্তে পিন ব্যৱহাৰ কৰক"</string>      <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"অতিৰিক্ত সুৰক্ষাৰ বাবে, ইয়াৰ পৰিৱৰ্তে পাছৱৰ্ড ব্যৱহাৰ কৰক"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"অতিৰিক্ত সুৰক্ষাৰ বাবে পিন দিয়াটো বাধ্যতামূলক"</string> diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml index 96779450d55e..4a5e789cab8a 100644 --- a/packages/SystemUI/res-keyguard/values-bs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml @@ -108,9 +108,9 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Uzorak je potreban nakon ponovnog pokretanja uređaja"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN je potreban nakon ponovnog pokretanja uređaja"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Lozinka je potrebna nakon pokretanja uređaja"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Radi dodatne zaštite, umjesto toga koristite uzorak"</string> -    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Radi dodatne zaštite, umjesto toga koristite PIN"</string> -    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Radi dodatne zašitite, umjesto toga koristite lozinku"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Za dodatnu sigurnost koristite uzorak"</string> +    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Za dodatnu sigurnost koristite PIN"</string> +    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Za dodatnu sigurnost koristite lozinku"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN je potreban radi dodatne sigurnosti"</string>      <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Uzorak je potreban radi dodatne sigurnosti"</string>      <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Lozinka je potrebna radi dodatne sigurnosti"</string> diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml index 8e97e84340d8..5a03cec97ce8 100644 --- a/packages/SystemUI/res-keyguard/values-cs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml @@ -83,7 +83,7 @@      <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Příliš mnoho pokusů s nesprávným kódem PIN"</string>      <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Příliš mnoho pokusů s nesprávným gestem"</string>      <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Příliš mnoho pokusů s nesprávným heslem"</string> -    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Zkuste to znovu za # sekundu.}few{Zkuste to znovu za # sekundy.}many{Zkuste to znovu za # sekundy.}other{Zkuste to znovu za # sekund.}}"</string> +    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Zkuste to znovu za # sekundu}few{Zkuste to znovu za # sekundy}many{Zkuste to znovu za # sekundy}other{Zkuste to znovu za # sekund}}"</string>      <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Zadejte kód PIN SIM karty."</string>      <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Zadejte kód PIN SIM karty <xliff:g id="CARRIER">%1$s</xliff:g>."</string>      <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> eSIM kartu deaktivujte, chcete-li zařízení používat bez mobilních služeb."</string> diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml index 2245710a0a5e..195fdeff3275 100644 --- a/packages/SystemUI/res-keyguard/values-de/strings.xml +++ b/packages/SystemUI/res-keyguard/values-de/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="keyguard_enter_your_pin" msgid="5429932527814874032">"Gib deine PIN ein"</string> +    <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"PIN eingeben"</string>      <string name="keyguard_enter_pin" msgid="8114529922480276834">"Gib die PIN ein"</string>      <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Muster eingeben"</string>      <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Zeichne das Muster"</string> diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml index ea1dd13c6848..c59bdc1604d5 100644 --- a/packages/SystemUI/res-keyguard/values-fi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml @@ -108,9 +108,9 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Kuvio tarvitaan uudelleenkäynnistyksen jälkeen"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN-koodi tarvitaan uudelleenkäynnistyksen jälkeen"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Salasana tarvitaan uudelleenkäynnistyksen jälkeen"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Lisäsuojaa saat, kun käytät sen sijaan kuviota"</string> -    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Lisäsuojaa saat, kun käytät sen sijaan PIN-koodia"</string> -    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Lisäsuojaa saat, kun käytät sen sijaan salasanaa"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Käytä kuviota, niin saat lisäsuojaa"</string> +    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Käytä PIN-koodia, niin saat lisäsuojaa"</string> +    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Käytä salasanaa, niin saat lisäsuojaa"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN-koodi vaaditaan suojauksen parantamiseksi."</string>      <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Kuvio vaaditaan suojauksen parantamiseksi."</string>      <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Salasana vaaditaan suojauksen parantamiseksi."</string> diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml index 6b51ac26cd52..e5cd788200a9 100644 --- a/packages/SystemUI/res-keyguard/values-gl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml @@ -108,9 +108,9 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Requírese o padrón tras reiniciar o dispositivo"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Requírese o PIN tras reiniciar o dispositivo"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Requírese o contrasinal tras reiniciar o dispositivo"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Utiliza un padrón para obter maior seguranza"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Utiliza un padrón para unha maior seguranza"</string>      <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Utiliza un PIN para obter maior seguranza"</string> -    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Utiliza un contrasinal para obter maior seguranza"</string> +    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Utiliza un contrasinal para unha maior seguranza"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"É necesario poñer o PIN como medida de seguranza adicional"</string>      <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"É necesario poñer o padrón como medida de seguranza adicional"</string>      <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"É necesario poñer o contrasinal como medida de seguranza adicional"</string> diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml index dc5b0b8c8077..e2ac8b65288f 100644 --- a/packages/SystemUI/res-keyguard/values-in/strings.xml +++ b/packages/SystemUI/res-keyguard/values-in/strings.xml @@ -80,10 +80,10 @@      <string name="kg_face_locked_out" msgid="2751559491287575">"Tidak dapat membuka kunci dengan wajah. Terlalu banyak upaya gagal."</string>      <string name="kg_fp_locked_out" msgid="6228277682396768830">"Tidak dapat membuka kunci dengan sidik jari. Terlalu banyak upaya gagal."</string>      <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Perangkat tepercaya tidak tersedia"</string> -    <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Terlalu banyak upaya dengan PIN yang salah"</string> -    <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Terlalu banyak upaya dengan pola yang salah"</string> -    <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Terlalu banyak upaya dengan sandi yang salah"</string> -    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Coba lagi dalam # detik.}other{Coba lagi dalam # detik.}}"</string> +    <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Terlalu banyak pemakaian PIN yang salah"</string> +    <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Terlalu banyak pemakaian pola yang salah"</string> +    <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Terlalu banyak pemakaian sandi yang salah"</string> +    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Coba lagi setelah # detik.}other{Coba lagi setelah # detik.}}"</string>      <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Masukkan PIN SIM."</string>      <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Masukkan PIN SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>      <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Nonaktifkan eSIM untuk menggunakan perangkat tanpa layanan seluler."</string> @@ -108,9 +108,9 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Pola diperlukan setelah perangkat dimulai ulang"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN diperlukan setelah perangkat dimulai ulang"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Sandi diperlukan setelah perangkat dimulai ulang"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Untuk keamanan tambahan, gunakan pola"</string> -    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Untuk keamanan tambahan, gunakan PIN"</string> -    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Untuk keamanan tambahan, gunakan sandi"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Agar lebih aman, gunakan pola"</string> +    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Agar lebih aman, gunakan PIN"</string> +    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Agar lebih aman, gunakan sandi"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN diperlukan untuk keamanan tambahan"</string>      <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Pola diperlukan untuk keamanan tambahan"</string>      <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Sandi diperlukan untuk keamanan tambahan"</string> diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml index 20808dbe4b0a..2deefd0b9643 100644 --- a/packages/SystemUI/res-keyguard/values-is/strings.xml +++ b/packages/SystemUI/res-keyguard/values-is/strings.xml @@ -108,9 +108,9 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Mynsturs er krafist eftir að tækið er endurræst"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN-númers er krafist eftir að tækið er endurræst"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Aðgangsorðs er krafist eftir að tækið er endurræst"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Fyrir aukið öryggi skaltu nota mynstur í staðinn"</string> -    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Fyrir aukið öryggi skaltu nota PIN-númer í staðinn"</string> -    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Fyrir aukið öryggi skaltu nota aðgangsorð í staðinn"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Til að auka öryggi skaltu nota mynstur í staðinn"</string> +    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Til að auka öryggi skaltu nota PIN-númer í staðinn"</string> +    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Til að auka öryggi skaltu nota aðgangsorð í staðinn"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"PIN-númers er krafist af öryggisástæðum"</string>      <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Mynsturs er krafist af öryggisástæðum"</string>      <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Aðgangsorðs er krafist af öryggisástæðum"</string> diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml index 8d86a8df1d69..69154aedd1a0 100644 --- a/packages/SystemUI/res-keyguard/values-ko/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml @@ -108,7 +108,7 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"기기가 다시 시작되어 패턴을 입력해야 합니다."</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"기기가 다시 시작되어 PIN을 입력해야 합니다."</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"기기가 다시 시작되어 비밀번호를 입력해야 합니다."</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"보안 강화를 위해 대신 패턴 사용"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"보안 강화를 위해 패턴 사용"</string>      <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"보안 강화를 위해 대신 PIN 사용"</string>      <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"보안 강화를 위해 대신 비밀번호 사용"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"보안 강화를 위해 PIN이 필요합니다."</string> diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml index 6bfbd64e5d53..6d2f0e508acf 100644 --- a/packages/SystemUI/res-keyguard/values-ky/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml @@ -49,7 +49,7 @@      <string name="disable_carrier_button_text" msgid="7153361131709275746">"eSIM-картаны өчүрүү"</string>      <string name="error_disable_esim_title" msgid="3802652622784813119">"eSIM-картаны өчүрүүгө болбойт"</string>      <string name="error_disable_esim_msg" msgid="2441188596467999327">"Катадан улам eSIM-картаны өчүрүүгө болбойт."</string> -    <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Киргизүү"</string> +    <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string>      <string name="kg_wrong_pattern" msgid="5907301342430102842">"Графикалык ачкыч туура эмес"</string>      <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Графклк ачкч тура эмс. Кайтлап крүңз."</string>      <string name="kg_wrong_password" msgid="4143127991071670512">"Сырсөз туура эмес"</string> diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml index 3e110b531ab1..6c57d89a36af 100644 --- a/packages/SystemUI/res-keyguard/values-mk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml @@ -49,7 +49,7 @@      <string name="disable_carrier_button_text" msgid="7153361131709275746">"Оневозможи ја eSIM"</string>      <string name="error_disable_esim_title" msgid="3802652622784813119">"Не може да се оневозможи eSIM"</string>      <string name="error_disable_esim_msg" msgid="2441188596467999327">"eSIM-картичката не може да се оневозможи поради грешка."</string> -    <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Внеси"</string> +    <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter"</string>      <string name="kg_wrong_pattern" msgid="5907301342430102842">"Погрешна шема"</string>      <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"Погрешна шема. Обидете се повторно."</string>      <string name="kg_wrong_password" msgid="4143127991071670512">"Погрешна лозинка"</string> diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml index 95d638e4c0d3..f74eb6697341 100644 --- a/packages/SystemUI/res-keyguard/values-my/strings.xml +++ b/packages/SystemUI/res-keyguard/values-my/strings.xml @@ -108,7 +108,7 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"စက်ကို ပြန်စပြီးနောက် ပုံဖော်ခြင်းလိုအပ်သည်"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"စက်ကို ပြန်စပြီးနောက် ပင်နံပါတ်လိုအပ်သည်"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"စက်ကို ပြန်စပြီးနောက် စကားဝှက်လိုအပ်သည်"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ထပ်ဆောင်းလုံခြုံရေးအတွက် ၎င်းအစား ပုံစံသုံးပါ"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ထပ်ဆောင်းလုံခြုံရေးအတွက် ပုံစံကို အစားထိုးသုံးပါ"</string>      <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ထပ်ဆောင်းလုံခြုံရေးအတွက် ၎င်းအစား ပင်နံပါတ်သုံးပါ"</string>      <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ထပ်ဆောင်းလုံခြုံရေးအတွက် ၎င်းအစား စကားဝှက်သုံးပါ"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"ထပ်ဆောင်း လုံခြုံရေးအတွက် ပင်နံပါတ် လိုအပ်သည်"</string> diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml index 219072b2bbb2..27856d6ba924 100644 --- a/packages/SystemUI/res-keyguard/values-ne/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml @@ -24,7 +24,7 @@      <string name="keyguard_enter_pin" msgid="8114529922480276834">"PIN हाल्नुहोस्"</string>      <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"प्याटर्न हाल्नुहोस्"</string>      <string name="keyguard_enter_pattern" msgid="7616595160901084119">"प्याटर्न कोर्नुहोस्"</string> -    <string name="keyguard_enter_your_password" msgid="7225626204122735501">"पासवर्ड हाल्नुहोस्…"</string> +    <string name="keyguard_enter_your_password" msgid="7225626204122735501">"पासवर्ड हाल्नुहोस्"</string>      <string name="keyguard_enter_password" msgid="6483623792371009758">"पासवर्ड हाल्नुहोस्"</string>      <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"अमान्य कार्ड।"</string>      <string name="keyguard_charged" msgid="5478247181205188995">"चार्ज भयो"</string> @@ -108,9 +108,9 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"डिभाइस रिस्टार्ट भएपछि प्याटर्न कोर्नु पर्ने हुन्छ"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"डिभाइस रिस्टार्ट भएपछि PIN हाल्नु पर्ने हुन्छ"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"डिभाइस रिस्टार्ट भएपछि पासवर्ड हाल्नु पर्ने हुन्छ"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"अतिरिक्त सुरक्षाका लागि यो प्रमाणीकरण विधिको साटो प्याटर्न प्रयोग गर्नुहोस्"</string> -    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"अतिरिक्त सुरक्षाका लागि यो प्रमाणीकरण विधिको साटो पिन प्रयोग गर्नुहोस्"</string> -    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"अतिरिक्त सुरक्षाका लागि यो प्रमाणीकरण विधिको साटो पासवर्ड प्रयोग गर्नुहोस्"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"अतिरिक्त सुरक्षाका लागि यसको साटो पासवर्ड प्रयोग गर्नुहोस्"</string> +    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"अतिरिक्त सुरक्षाका लागि यसको साटो पासवर्ड प्रयोग गर्नुहोस्"</string> +    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"अतिरिक्त सुरक्षाका लागि यसको साटो पासवर्ड प्रयोग गर्नुहोस्"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"अतिरिक्त सुरक्षाका लागि PIN चाहिन्छ"</string>      <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"अतिरिक्त सुरक्षाका लागि प्याटर्न चाहिन्छ"</string>      <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"अतिरिक्त सुरक्षाका लागि पासवर्ड चाहिन्छ"</string> diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml index 020640361e7f..9fb9e1bfe8a5 100644 --- a/packages/SystemUI/res-keyguard/values-nl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml @@ -22,7 +22,7 @@      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">      <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Geef je pincode op"</string>      <string name="keyguard_enter_pin" msgid="8114529922480276834">"Voer pincode in"</string> -    <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Geef je patroon op"</string> +    <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Voer je patroon in"</string>      <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Teken het patroon"</string>      <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Voer je wachtwoord in"</string>      <string name="keyguard_enter_password" msgid="6483623792371009758">"Geef het wachtwoord op"</string> @@ -80,9 +80,9 @@      <string name="kg_face_locked_out" msgid="2751559491287575">"Kan niet ontgrendelen met gezicht. Te veel pogingen."</string>      <string name="kg_fp_locked_out" msgid="6228277682396768830">"Niet ontgrendeld met vingerafdruk. Te veel pogingen."</string>      <string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Trust agent is niet beschikbaar"</string> -    <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Te veel pogingen met onjuiste pincode"</string> -    <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Te veel pogingen met onjuist patroon"</string> -    <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Te veel pogingen met onjuist wachtwoord"</string> +    <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Pincode te vaak verkeerd ingevoerd"</string> +    <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Patroon te vaak verkeerd getekend"</string> +    <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Wachtwoord te vaak verkeerd ingevoerd"</string>      <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Probeer het over # seconde opnieuw.}other{Probeer het over # seconden opnieuw.}}"</string>      <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Geef de pincode van de simkaart op."</string>      <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Geef de pincode voor de simkaart van \'<xliff:g id="CARRIER">%1$s</xliff:g>\' op."</string> @@ -108,9 +108,9 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Patroon is vereist na opnieuw opstarten apparaat"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Pincode is vereist na opnieuw opstarten apparaat"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Wachtwoord is vereist na opnieuw opstarten apparaat"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Gebruik in plaats daarvan het patroon voor extra beveiliging"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Gebruik het patroon voor extra beveiliging"</string>      <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Gebruik de pincode voor extra beveiliging"</string> -    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Gebruik in plaats daarvan het wachtwoord voor extra beveiliging"</string> +    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Gebruik het wachtwoord voor extra beveiliging"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Pincode vereist voor extra beveiliging"</string>      <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Patroon vereist voor extra beveiliging"</string>      <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Wachtwoord vereist voor extra beveiliging"</string> diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml index 4a8907031cbd..f25e9c5454ed 100644 --- a/packages/SystemUI/res-keyguard/values-pl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml @@ -83,7 +83,7 @@      <string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Zbyt wiele nieudanych prób wpisania kodu PIN"</string>      <string name="kg_primary_auth_locked_out_pattern" msgid="8266214607346180952">"Zbyt wiele nieudanych prób narysowania wzoru"</string>      <string name="kg_primary_auth_locked_out_password" msgid="6170245108400198659">"Zbyt wiele nieudanych prób wpisania hasła"</string> -    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Spróbuj ponownie za # sekundę.}few{Spróbuj ponownie za # sekundy.}many{Spróbuj ponownie za # sekund.}other{Spróbuj ponownie za # sekundy.}}"</string> +    <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{Spróbuj ponownie za # sekundę}few{Spróbuj ponownie za # sekundy}many{Spróbuj ponownie za # sekund}other{Spróbuj ponownie za # sekundy}}"</string>      <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"Wpisz kod PIN karty SIM."</string>      <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Wpisz kod PIN karty SIM „<xliff:g id="CARRIER">%1$s</xliff:g>”."</string>      <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Wyłącz kartę eSIM, by używać urządzenia bez usługi sieci komórkowej."</string> diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml index 1ae1aeba90cd..b29220476224 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml @@ -24,7 +24,7 @@      <string name="keyguard_enter_pin" msgid="8114529922480276834">"Introduza o PIN"</string>      <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Introduza o padrão"</string>      <string name="keyguard_enter_pattern" msgid="7616595160901084119">"Desenhe o padrão"</string> -    <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introduza a palavra-passe."</string> +    <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introduza a palavra-passe"</string>      <string name="keyguard_enter_password" msgid="6483623792371009758">"Introduza a palavra-passe"</string>      <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Cartão inválido."</string>      <string name="keyguard_charged" msgid="5478247181205188995">"Carregada"</string> @@ -108,9 +108,9 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Padrão necessário após reiniciar o dispositivo"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"PIN necessário após reiniciar o dispositivo"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Palavra-passe necessária após reiniciar dispositivo"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para uma segurança adicional, use antes o padrão"</string> -    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para uma segurança adicional, use antes o PIN"</string> -    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para uma segurança adicional, use antes a palavra-passe"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para segurança adicional, use o padrão"</string> +    <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para segurança adicional, use o PIN"</string> +    <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para segurança adicional, use a palavra-passe"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Para segurança adicional, é necessária um PIN"</string>      <string name="kg_prompt_added_security_pattern" msgid="1017068086102168544">"Para segurança adicional, é necessário um padrão"</string>      <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"Para segurança adicional, é necessária uma palavra-passe"</string> diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml index 5725fe0408c7..9b0647afb614 100644 --- a/packages/SystemUI/res-keyguard/values-sk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml @@ -108,7 +108,7 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Po reštarte zariadenia sa vyžaduje vzor"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Po reštarte zariadenia sa vyžaduje kód PIN"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Po reštarte zariadenia sa vyžaduje heslo"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"V rámci zvýšenia zabezpečenia použite radšej vzor"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Z bezpečnostných dôvodov použite radšej vzor"</string>      <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"V rámci zvýšenia zabezpečenia použite radšej PIN"</string>      <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"V rámci zvýšenia zabezpečenia použite radšej heslo"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Zvýšenie zabezpečenia vyžaduje kód PIN"</string> diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml index bfe5ae09d154..cb17459c84c4 100644 --- a/packages/SystemUI/res-keyguard/values-tl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml @@ -108,7 +108,7 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Kailangan ang pattern pagka-restart ng device"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Kailangan ang PIN pagka-restart ng device"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Kailangan ang password pagka-restart ng device"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para sa karagdagang seguridad, gumamit na lang ng pattern"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para sa karagdagang seguridad, gumamit ng pattern"</string>      <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para sa karagdagang seguridad, gumamit na lang ng PIN"</string>      <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para sa karagdagang seguridad, gumamit na lang ng password"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Kinakailangan ang PIN para sa karagdagang seguridad"</string> diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml index bbd319c3988a..72ea8500b746 100644 --- a/packages/SystemUI/res-keyguard/values-vi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml @@ -108,7 +108,7 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"Cần vẽ hình mở khoá sau khi khởi động lại thiết bị"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Cần nhập mã PIN sau khi khởi động lại thiết bị"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Cần nhập mật khẩu sau khi khởi động lại thiết bị"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Để tăng cường bảo mật, hãy sử dụng hình mở khoá"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Để tăng cường bảo mật, hãy dùng hình mở khoá"</string>      <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Để tăng cường bảo mật, hãy sử dụng mã PIN"</string>      <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Để tăng cường bảo mật, hãy sử dụng mật khẩu"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"Yêu cầu mã PIN để tăng cường bảo mật"</string> diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml index a316e8cc727f..7d74c9cb8224 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml @@ -22,7 +22,7 @@      xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">      <string name="keyguard_enter_your_pin" msgid="5429932527814874032">"输入您的 PIN 码"</string>      <string name="keyguard_enter_pin" msgid="8114529922480276834">"输入 PIN 码"</string> -    <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"绘制您的图案"</string> +    <string name="keyguard_enter_your_pattern" msgid="351503370332324745">"绘制解锁图案"</string>      <string name="keyguard_enter_pattern" msgid="7616595160901084119">"绘制图案"</string>      <string name="keyguard_enter_your_password" msgid="7225626204122735501">"输入您的密码"</string>      <string name="keyguard_enter_password" msgid="6483623792371009758">"输入密码"</string> @@ -108,7 +108,7 @@      <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"设备重启后,必须绘制图案才能解锁"</string>      <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"设备重启后,必须输入 PIN 码才能解锁"</string>      <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"设备重启后,必须输入密码才能解锁"</string> -    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"为增强安全性,请改用图案"</string> +    <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"为增强安全性,请改用解锁图案"</string>      <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"为增强安全性,请改用 PIN 码"</string>      <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"为增强安全性,请改用密码"</string>      <string name="kg_prompt_added_security_pin" msgid="5487992065995475528">"需要输入 PIN 码以进一步确保安全"</string> diff --git a/packages/SystemUI/res/drawable/ic_noise_aware.xml b/packages/SystemUI/res/drawable/ic_noise_aware.xml deleted file mode 100644 index 54826414f3f7..000000000000 --- a/packages/SystemUI/res/drawable/ic_noise_aware.xml +++ /dev/null @@ -1,26 +0,0 @@ -<!-- -  ~ Copyright (C) 2024 The Android Open Source Project -  ~ -  ~  Licensed under the Apache License, Version 2.0 (the "License"); -  ~  you may not use this file except in compliance with the License. -  ~  You may obtain a copy of the License at -  ~ -  ~       http://www.apache.org/licenses/LICENSE-2.0 -  ~ -  ~  Unless required by applicable law or agreed to in writing, software -  ~  distributed under the License is distributed on an "AS IS" BASIS, -  ~  WITHOUT 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="960" -    android:viewportHeight="960" -    android:tint="?attr/colorControlNormal"> -  <path -      android:fillColor="@android:color/white" -      android:pathData="M440,82Q450,81 460,80.5Q470,80 480,80Q491,80 500.5,80.5Q510,81 520,82L520,162Q510,160 500.5,160Q491,160 480,160Q469,160 459.5,160Q450,160 440,162L440,82ZM272,138Q289,127 306.5,119Q324,111 343,104L378,176Q358,182 340.5,190.5Q323,199 306,210L272,138ZM654,210Q637,199 619.5,190.5Q602,182 582,176L617,104Q636,111 653.5,119Q671,127 688,138L654,210ZM753,311Q742,294 729,278.5Q716,263 702,249L765,199Q779,213 792,228.5Q805,244 816,261L753,311ZM143,263Q154,246 166.5,230.5Q179,215 193,201L256,251Q242,265 229.5,280.5Q217,296 206,313L143,263ZM83,428Q85,408 90,388.5Q95,369 101,350L180,368Q173,387 168.5,406.5Q164,426 162,446L83,428ZM799,449Q797,429 792.5,409Q788,389 781,370L859,352Q865,371 870,390.5Q875,410 877,430L799,449ZM781,590Q788,571 792,552Q796,533 798,513L877,531Q875,551 870,570.5Q865,590 859,609L781,590ZM162,514Q164,534 168.5,553.5Q173,573 180,592L101,610Q95,591 90,571.5Q85,552 83,532L162,514ZM705,708Q719,694 731,678.5Q743,663 754,646L818,696Q807,713 794.5,728.5Q782,744 768,758L705,708ZM194,760Q180,746 167.5,730Q155,714 144,697L206,647Q217,664 229.5,680Q242,696 256,710L194,760ZM583,783Q603,776 620,768Q637,760 654,749L689,821Q672,832 654.5,840.5Q637,849 618,856L583,783ZM344,857Q325,850 307,841.5Q289,833 272,822L307,750Q324,761 341.5,769.5Q359,778 379,784L344,857ZM480,880Q470,880 460,879.5Q450,879 440,878L440,798Q453,800 480,800Q491,800 500.5,800Q510,800 520,798L520,878Q510,879 500.5,879.5Q491,880 480,880ZM520,720Q482,720 450.5,697Q419,674 406,638Q403,629 399.5,620.5Q396,612 389,605L334,550Q308,524 294,490.5Q280,457 280,420Q280,345 332.5,292.5Q385,240 460,240Q529,240 580,285.5Q631,331 639,400L558,400Q551,365 523.5,342.5Q496,320 460,320Q418,320 389,349Q360,378 360,420Q360,440 368,459.5Q376,479 391,494L445,548Q459,562 467.5,578.5Q476,595 482,612Q487,625 497,632.5Q507,640 520,640Q537,640 548.5,628.5Q560,617 560,600L640,600Q640,650 605.5,685Q571,720 520,720ZM540,560Q515,560 497.5,542.5Q480,525 480,500Q480,474 497.5,457Q515,440 540,440Q566,440 583,457Q600,474 600,500Q600,525 583,542.5Q566,560 540,560Z"/> -</vector> diff --git a/packages/SystemUI/res/drawable/shelf_action_chip_background.xml b/packages/SystemUI/res/drawable/shelf_action_chip_background.xml new file mode 100644 index 000000000000..63600beff126 --- /dev/null +++ b/packages/SystemUI/res/drawable/shelf_action_chip_background.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2024 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  ~ See the License for the specific language governing permissions and +  ~ limitations under the License. +  --> +<ripple +    xmlns:android="http://schemas.android.com/apk/res/android" +    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" +    android:color="@color/overlay_button_ripple"> +    <item android:id="@android:id/background"> +        <shape android:shape="rectangle"> +            <solid android:color="?androidprv:attr/materialColorSecondary"/> +            <corners android:radius="10000dp"/>  <!-- fully-rounded radius --> +        </shape> +    </item> +</ripple> diff --git a/packages/SystemUI/res/drawable/shelf_action_chip_container_background.xml b/packages/SystemUI/res/drawable/shelf_action_chip_container_background.xml new file mode 100644 index 000000000000..bb8cece9203b --- /dev/null +++ b/packages/SystemUI/res/drawable/shelf_action_chip_container_background.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2024 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT 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" +    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" +    android:shape="rectangle"> +    <solid android:color="?androidprv:attr/materialColorSurfaceBright"/> +    <corners android:radius="10000dp"/>  <!-- fully-rounded radius --> +</shape> diff --git a/packages/SystemUI/res/drawable/shelf_action_chip_divider.xml b/packages/SystemUI/res/drawable/shelf_action_chip_divider.xml new file mode 100644 index 000000000000..a5b44e564157 --- /dev/null +++ b/packages/SystemUI/res/drawable/shelf_action_chip_divider.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2024 The Android Open Source Project + +     Licensed under the Apache License, Version 2.0 (the "License"); +     you may not use this file except in compliance with the License. +     You may obtain a copy of the License at + +          http://www.apache.org/licenses/LICENSE-2.0 + +     Unless required by applicable law or agreed to in writing, software +     distributed under the License is distributed on an "AS IS" BASIS, +     WITHOUT 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"> +    <size +        android:width = "@dimen/overlay_action_chip_margin_start" +        android:height = "0dp"/> +</shape> diff --git a/packages/SystemUI/res/drawable/shelf_action_container_clipping_shape.xml b/packages/SystemUI/res/drawable/shelf_action_container_clipping_shape.xml new file mode 100644 index 000000000000..76779f9f1b2c --- /dev/null +++ b/packages/SystemUI/res/drawable/shelf_action_container_clipping_shape.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2024 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT 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"> +    <!-- We don't actually draw anything, just expressing the shape for clipping. --> +    <solid android:color="#0000"/> +    <corners android:radius="10000dp"/>  <!-- fully-rounded radius --> +</shape> diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml index 13355f374dd6..76d10ccb8a25 100644 --- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml +++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml @@ -47,7 +47,7 @@          android:layout_marginBottom="@dimen/bluetooth_dialog_layout_margin"          android:ellipsize="end"          android:gravity="center_vertical|center_horizontal" -        android:maxLines="1" +        android:maxLines="2"          android:text="@string/quick_settings_bluetooth_tile_subtitle"          android:textAppearance="@style/TextAppearance.Dialog.Body.Message"          app:layout_constraintEnd_toEndOf="parent" @@ -256,6 +256,24 @@                  app:constraint_referenced_ids="pair_new_device_button,bluetooth_auto_on_toggle_info_text" />              <Button +                android:id="@+id/audio_sharing_button" +                style="@style/Widget.Dialog.Button.BorderButton" +                android:layout_width="wrap_content" +                android:layout_height="wrap_content" +                android:layout_marginTop="9dp" +                android:layout_marginBottom="@dimen/dialog_bottom_padding" +                android:layout_marginEnd="@dimen/dialog_side_padding" +                android:layout_marginStart="@dimen/dialog_side_padding" +                android:ellipsize="end" +                android:maxLines="1" +                android:text="@string/quick_settings_bluetooth_audio_sharing_button" +                app:layout_constraintStart_toStartOf="parent" +                app:layout_constraintBottom_toBottomOf="parent" +                app:layout_constraintTop_toBottomOf="@+id/barrier" +                app:layout_constraintVertical_bias="1" +                android:visibility="gone" /> + +            <Button                  android:id="@+id/done_button"                  style="@style/Widget.Dialog.Button"                  android:layout_width="wrap_content" diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml index 1eb05bfd602d..e3c5a7d03d2e 100644 --- a/packages/SystemUI/res/layout/qs_panel.xml +++ b/packages/SystemUI/res/layout/qs_panel.xml @@ -36,8 +36,8 @@              android:layout_width="match_parent"              android:layout_height="wrap_content"              android:background="@android:color/transparent" -            android:focusable="true" -            android:accessibilityTraversalBefore="@android:id/edit" +            android:focusable="false" +            android:importantForAccessibility="yes"              android:clipToPadding="false"              android:clipChildren="false"> diff --git a/packages/SystemUI/res/layout/screenshot_shelf.xml b/packages/SystemUI/res/layout/screenshot_shelf.xml index eeb64bd8460e..6a5b999f5444 100644 --- a/packages/SystemUI/res/layout/screenshot_shelf.xml +++ b/packages/SystemUI/res/layout/screenshot_shelf.xml @@ -20,39 +20,37 @@      xmlns:app="http://schemas.android.com/apk/res-auto"      android:layout_width="match_parent"      android:layout_height="match_parent"> -    <ImageView +    <FrameLayout          android:id="@+id/actions_container_background"          android:visibility="gone" -        android:layout_height="0dp" -        android:layout_width="0dp" -        android:elevation="4dp" -        android:background="@drawable/action_chip_container_background" -        android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal" -        android:layout_marginBottom="@dimen/screenshot_shelf_vertical_margin" -        app:layout_constraintStart_toStartOf="parent" -        app:layout_constraintTop_toTopOf="@+id/actions_container" -        app:layout_constraintEnd_toEndOf="@+id/actions_container" -        app:layout_constraintBottom_toTopOf="@id/guideline"/> -    <HorizontalScrollView -        android:id="@+id/actions_container" -        android:layout_width="0dp"          android:layout_height="wrap_content" -        android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal" -        android:paddingHorizontal="@dimen/overlay_action_container_padding_end" -        android:paddingVertical="@dimen/overlay_action_container_padding_vertical" +        android:layout_width="wrap_content"          android:elevation="4dp" -        android:scrollbars="none" -        app:layout_constraintHorizontal_bias="0" -        app:layout_constraintWidth_percent="1.0" -        app:layout_constraintWidth_max="wrap" +        android:background="@drawable/shelf_action_chip_container_background" +        android:layout_marginHorizontal="@dimen/overlay_action_container_margin_horizontal" +        android:layout_marginBottom="@dimen/screenshot_shelf_vertical_margin"          app:layout_constraintStart_toStartOf="parent" -        app:layout_constraintEnd_toEndOf="parent" -        app:layout_constraintBottom_toBottomOf="@id/actions_container_background"> -        <LinearLayout -            android:id="@+id/screenshot_actions" +        app:layout_constraintBottom_toTopOf="@id/guideline" +        > +        <HorizontalScrollView +            android:id="@+id/actions_container"              android:layout_width="wrap_content" -            android:layout_height="wrap_content" /> -    </HorizontalScrollView> +            android:layout_height="wrap_content" +            android:layout_marginVertical="@dimen/overlay_action_container_padding_vertical" +            android:layout_marginHorizontal="@dimen/overlay_action_chip_margin_start" +            android:background="@drawable/shelf_action_container_clipping_shape" +            android:clipToOutline="true" +            android:scrollbars="none"> +            <LinearLayout +                android:id="@+id/screenshot_actions" +                android:layout_width="wrap_content" +                android:layout_height="wrap_content" +                android:showDividers="middle" +                android:divider="@drawable/shelf_action_chip_divider" +                android:animateLayoutChanges="true" +                /> +        </HorizontalScrollView> +    </FrameLayout>      <View          android:id="@+id/screenshot_preview_border"          android:layout_width="0dp" @@ -66,7 +64,7 @@          app:layout_constraintStart_toStartOf="parent"          app:layout_constraintTop_toTopOf="@id/screenshot_preview"          app:layout_constraintEnd_toEndOf="@id/screenshot_preview" -        app:layout_constraintBottom_toTopOf="@id/actions_container"/> +        app:layout_constraintBottom_toTopOf="@id/actions_container_background"/>      <ImageView          android:id="@+id/screenshot_preview"          android:layout_width="@dimen/overlay_x_scale" diff --git a/packages/SystemUI/res/layout/shelf_action_chip.xml b/packages/SystemUI/res/layout/shelf_action_chip.xml new file mode 100644 index 000000000000..709c80d07088 --- /dev/null +++ b/packages/SystemUI/res/layout/shelf_action_chip.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +  ~ Copyright (C) 2024 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  ~ See the License for the specific language governing permissions and +  ~ limitations under the License. +  --> +<com.android.systemui.screenshot.OverlayActionChip +    xmlns:android="http://schemas.android.com/apk/res/android" +    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" +    android:id="@+id/overlay_action_chip" +    android:theme="@style/FloatingOverlay" +    android:layout_width="wrap_content" +    android:layout_height="wrap_content" +    android:layout_gravity="center" +    android:gravity="center" +    android:alpha="0.0"> +    <LinearLayout +        android:layout_width="wrap_content" +        android:layout_height="wrap_content" +        android:paddingVertical="@dimen/overlay_action_chip_padding_vertical" +        android:background="@drawable/shelf_action_chip_background" +        android:gravity="center"> +        <ImageView +            android:id="@+id/overlay_action_chip_icon" +            android:tint="?androidprv:attr/materialColorOnSecondary" +            android:layout_width="@dimen/overlay_action_chip_icon_size" +            android:layout_height="@dimen/overlay_action_chip_icon_size"/> +        <TextView +            android:id="@+id/overlay_action_chip_text" +            android:layout_width="wrap_content" +            android:layout_height="wrap_content" +            android:fontFamily="@*android:string/config_headlineFontFamilyMedium" +            android:textSize="@dimen/overlay_action_chip_text_size" +            android:textColor="?androidprv:attr/materialColorOnSecondary"/> +    </LinearLayout> +</com.android.systemui.screenshot.OverlayActionChip> diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_ringer_drawer.xml index 9b1fa23081b4..8f1e0610853f 100644 --- a/packages/SystemUI/res/layout/volume_ringer_drawer.xml +++ b/packages/SystemUI/res/layout/volume_ringer_drawer.xml @@ -67,8 +67,8 @@                      android:layout_width="@dimen/volume_ringer_drawer_icon_size"                      android:layout_height="@dimen/volume_ringer_drawer_icon_size"                      android:layout_gravity="center" -                    android:tint="?android:attr/textColorPrimary" -                    android:src="@drawable/ic_volume_ringer_vibrate" /> +                    android:src="@drawable/ic_volume_ringer_vibrate" +                    android:tint="?android:attr/textColorPrimary" />              </FrameLayout> @@ -76,6 +76,7 @@                  android:id="@+id/volume_drawer_mute"                  android:layout_width="@dimen/volume_ringer_drawer_item_size"                  android:layout_height="@dimen/volume_ringer_drawer_item_size" +                android:accessibilityTraversalAfter="@id/volume_drawer_vibrate"                  android:contentDescription="@string/volume_ringer_hint_mute"                  android:gravity="center"> @@ -84,8 +85,8 @@                      android:layout_width="@dimen/volume_ringer_drawer_icon_size"                      android:layout_height="@dimen/volume_ringer_drawer_icon_size"                      android:layout_gravity="center" -                    android:tint="?android:attr/textColorPrimary" -                    android:src="@drawable/ic_speaker_mute" /> +                    android:src="@drawable/ic_speaker_mute" +                    android:tint="?android:attr/textColorPrimary" />              </FrameLayout> @@ -93,6 +94,7 @@                  android:id="@+id/volume_drawer_normal"                  android:layout_width="@dimen/volume_ringer_drawer_item_size"                  android:layout_height="@dimen/volume_ringer_drawer_item_size" +                android:accessibilityTraversalAfter="@id/volume_drawer_mute"                  android:contentDescription="@string/volume_ringer_hint_unmute"                  android:gravity="center"> @@ -101,8 +103,8 @@                      android:layout_width="@dimen/volume_ringer_drawer_icon_size"                      android:layout_height="@dimen/volume_ringer_drawer_icon_size"                      android:layout_gravity="center" -                    android:tint="?android:attr/textColorPrimary" -                    android:src="@drawable/ic_speaker_on" /> +                    android:src="@drawable/ic_speaker_on" +                    android:tint="?android:attr/textColorPrimary" />              </FrameLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 2027d168e750..ccea0fcc11db 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -71,7 +71,7 @@      <string name="usb_port_enabled" msgid="531823867664717018">"USB-poort is geaktiveer om laaiers en bykomstighede te bespeur"</string>      <string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Aktiveer USB"</string>      <string name="learn_more" msgid="4690632085667273811">"Kom meer te wete"</string> -    <string name="global_action_screenshot" msgid="2760267567509131654">"Skermkiekie"</string> +    <string name="global_action_screenshot" msgid="2760267567509131654">"Skermskoot"</string>      <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Hou Ontsluit is gedeaktiveer"</string>      <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"het \'n prent gestuur"</string>      <string name="screenshot_saving_title" msgid="2298349784913287333">"Stoor tans skermkiekie..."</string> @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Neem kwessie op"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Begin"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Foutverslag"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Watter deel van jou toestelervaring is geraak?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Kies soort kwessie"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skermopname"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standaard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Hoog"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Gehoortoestelle"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Gehoortoestelle"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Bind nuwe toestel saam"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nuwe toestel saam te bind"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokkeer toestelmikrofoon?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblokkeer toestelkamera?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblokkeer toestelkamera en mikrofoon?"</string> @@ -448,10 +445,8 @@      <string name="button_to_remove_widget" msgid="3948204829181214098">"Verwyder"</string>      <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Voeg legstuk by"</string>      <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klaar"</string> -    <!-- no translation found for label_for_button_in_empty_state_cta (7314975555382055823) --> -    <skip /> -    <!-- no translation found for title_for_empty_state_cta (6161654421223450530) --> -    <skip /> +    <string name="label_for_button_in_empty_state_cta" msgid="7314975555382055823">"Voeg legstukke by"</string> +    <string name="title_for_empty_state_cta" msgid="6161654421223450530">"Kry kitstoegang tot jou gunstelingapplegstukke sonder om jou tablet te ontsluit."</string>      <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"Laat enige legstuk op die sluitskerm toe?"</string>      <string name="button_text_to_open_settings" msgid="1987729256950941628">"Maak instellings oop"</string>      <string name="work_mode_off_title" msgid="5794818421357835873">"Hervat werkapps?"</string> @@ -747,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Wissel sleutelborduitleg"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"of"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Maak soeknavraag skoon"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Kortpaaie"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Kortpadsleutels"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Soek kortpaaie"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Geen kortpaaie gevind nie"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Stelsel"</string> @@ -772,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Maak Assistent oop"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Sluit skerm"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Maak ’n nota"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Verrig veelvuldige stelseltake"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Gaan by verdeelde skerm in met huidige app aan die regterkant"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Gaan by verdeelde skerm in met huidige app aan die linkerkant"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Verrigting van veelvuldige take"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Gebruik verdeelde skerm met huidige app aan die regterkant"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Gebruik verdeelde skerm met huidige app aan die linkerkant"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Skakel oor van verdeelde skerm na volskerm"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skakel oor na app regs of onder terwyl jy verdeelde skerm gebruik"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skakel oor na app links of bo terwyl jy verdeelde skerm gebruik"</string> @@ -895,12 +890,12 @@      <string name="notification_channel_alerts" msgid="3385787053375150046">"Opletberigte"</string>      <string name="notification_channel_battery" msgid="9219995638046695106">"Battery"</string>      <string name="notification_channel_screenshot" msgid="7665814998932211997">"Skermkiekies"</string> -    <string name="notification_channel_instant" msgid="7556135423486752680">"Kitsprogramme"</string> +    <string name="notification_channel_instant" msgid="7556135423486752680">"Kitsapps"</string>      <string name="notification_channel_setup" msgid="7660580986090760350">"Opstelling"</string>      <string name="notification_channel_storage" msgid="2720725707628094977">"Berging"</string>      <string name="notification_channel_hints" msgid="7703783206000346876">"Wenke"</string>      <string name="notification_channel_accessibility" msgid="8956203986976245820">"Toeganklikheid"</string> -    <string name="instant_apps" msgid="8337185853050247304">"Kitsprogramme"</string> +    <string name="instant_apps" msgid="8337185853050247304">"Kitsapps"</string>      <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> loop tans"</string>      <string name="instant_apps_message" msgid="6112428971833011754">"Program is oopgemaak sonder dat dit geïnstalleer is."</string>      <string name="instant_apps_message_with_help" msgid="1816952263531203932">"Program is oopgemaak sonder dat dit geïnstalleer is. Tik om meer te wete te kom."</string> @@ -1195,8 +1190,8 @@      <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Kies gebruiker"</string>      <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app is aktief}other{# apps is aktief}}"</string>      <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nuwe inligting"</string> -    <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiewe programme"</string> -    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Hierdie programme is aktief en werk, selfs wanneer jy hulle nie gebruik nie. Dit verbeter hul funksies, maar beïnvloed dalk ook batterylewe."</string> +    <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiewe apps"</string> +    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Hierdie apps is aktief en werk, selfs wanneer jy hulle nie gebruik nie. Dit verbeter hul funksies, maar beïnvloed dalk ook batterylewe."</string>      <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Stop"</string>      <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Gestop"</string>      <string name="clipboard_edit_text_done" msgid="4551887727694022409">"Klaar"</string> diff --git a/packages/SystemUI/res/values-af/tiles_states_strings.xml b/packages/SystemUI/res/values-af/tiles_states_strings.xml index 8f0532e00064..1b4781d24ebc 100644 --- a/packages/SystemUI/res/values-af/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-af/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Af"</item>      <item msgid="5137565285664080143">"Aan"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Nie beskikbaar nie"</item> +    <item msgid="3079622119444911877">"Af"</item> +    <item msgid="3028994095749238254">"Aan"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index a3700f2785d9..9e528e0c9ac0 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"ችግርን ቅዳ"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"ጀምር"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"አቁም"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"የሳንካ ሪፖርት"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"የትኛው የመሣሪያዎ ተሞክሮ ክፍል ተጎድቷል?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"የችግሩን አይነት ይምረጡ"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"የማያ መቅረጫ"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"መካከለኛ"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"ከፍተኛ"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"የመስሚያ መሣሪያዎች"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"የመስማት ችሎታ መሣሪያ"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"አዲስ መሣሪያ ያጣምሩ"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"አዲስ መሣሪያ ለማጣመር ጠቅ ያድርጉ"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"የመሣሪያ ማይክሮፎን እገዳ ይነሳ?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"የመሣሪያ ካሜራ እገዳ ይነሳ?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"የመሣሪያ ካሜራ እና ማይክሮፎን እገዳ ይነሳ?"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"የቁልፍ ሰሌዳ ገጽታ ለውጥ"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ወይም"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"የፍለጋ መጠይቅን አጽዳ"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"አቋራጮች"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"የቁልፍ ሰሌዳ አቋራጮች"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"አቋራጮችን ይፈልጉ"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"ምንም አቋራጮች አልተገኙም"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"ሥርዓት"</string> @@ -769,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"ረዳትን ክፈት"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"ማያ ገፅ ቁልፍ"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"ማስታወሻ ይውሰዱ"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"የሥርዓት ብዙ ተግባራትን በተመሳሳይ ጊዜ ማከናወን"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"ለአርኤችኤስ በአሁኑ መተግበሪያ ወደ የተከፈለ ማያ ገጽ ግባ"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"ለኤልኤችኤስ በአሁኑ መተግበሪያ ወደ የተከፈለ ማያ ገጽ ይግቡ"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"ብዙ ተግባራትን በተመሳሳይ ጊዜ ማከናወን"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"የአሁኑ መተግበሪያ በስተቀኝ ላይ ሆኖ የተከፈለ ማያ ገጽን ይጠቀሙ"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"የአሁኑ መተግበሪያ በስተግራ ላይ ሆኖ የተከፈለ ማያ ገጽን ይጠቀሙ"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"ከየተከፈለ ማያ ገጽ ወደ ሙሉ ገጽ ዕይታ ቀይር"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"የተከፈለ ማያ ገጽን ሲጠቀሙ በቀኝ ወይም ከታች ወዳለ መተግበሪያ ይቀይሩ"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"የተከፈለ ማያ ገጽን ሲጠቀሙ በቀኝ ወይም ከላይ ወዳለ መተግበሪያ ይቀይሩ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 767e909de2ea..759f957c543a 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -120,7 +120,7 @@      <string name="screenrecord_stop_label" msgid="72699670052087989">"إيقاف"</string>      <string name="screenrecord_share_label" msgid="5025590804030086930">"مشاركة"</string>      <string name="screenrecord_save_title" msgid="1886652605520893850">"تم حفظ تسجيل الشاشة"</string> -    <string name="screenrecord_save_text" msgid="3008973099800840163">"انقر لعرض التسجيل."</string> +    <string name="screenrecord_save_text" msgid="3008973099800840163">"انقر لعرض التسجيل"</string>      <string name="screenrecord_save_error" msgid="5862648532560118815">"حدث خطأ أثناء حفظ تسجيل محتوى الشاشة."</string>      <string name="screenrecord_start_error" msgid="2200660692479682368">"حدث خطأ في بدء تسجيل الشاشة"</string>      <string name="issuerecord_title" msgid="286627115110121849">"مسجّلة المشاكل"</string> @@ -287,7 +287,7 @@      <string name="quick_settings_location_label" msgid="2621868789013389163">"الموقع الجغرافي"</string>      <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"شاشة الاستراحة"</string>      <string name="quick_settings_camera_label" msgid="5612076679385269339">"الوصول إلى الكاميرا"</string> -    <string name="quick_settings_mic_label" msgid="8392773746295266375">"الوصول إلى الميكروفون"</string> +    <string name="quick_settings_mic_label" msgid="8392773746295266375">"الوصول للميكروفون"</string>      <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"متاح"</string>      <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"محظور"</string>      <string name="quick_settings_media_device_label" msgid="8034019242363789941">"جهاز الوسائط"</string> @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"تسجيل المشكلة"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"بدء"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"إيقاف"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"تقرير خطأ"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ما هو الجانب الذي تأثّر في تجربة استخدام الجهاز؟"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"اختيار نوع المشكلة"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"تسجيل الشاشة"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"عادي"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"متوسط"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"مرتفع"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سماعات الأذن الطبية"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سماعات الأذن الطبية"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"إقران جهاز جديد"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"انقر لإقران جهاز جديد"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"هل تريد إزالة حظر ميكروفون الجهاز؟"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"هل تريد إزالة حظر كاميرا الجهاز؟"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"هل تريد إزالة حظر الكاميرا والميكروفون؟"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"تبديل تنسيق لوحة المفاتيح"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"أو"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"محو طلب البحث"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"الاختصارات"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"اختصارات لوحة المفاتيح"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"البحث في الاختصارات"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"لم يُعثَر على اختصارات."</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"النظام"</string> @@ -770,14 +767,14 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"فتح \"مساعد Google\""</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"شاشة القفل"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"تدوين ملاحظة"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"تعدُّد المهام في النظام"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"تفعيل وضع \"تقسيم الشاشة\" مع عرض التطبيق الحالي على يسار الشاشة"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"تفعيل وضع \"تقسيم الشاشة\" مع عرض التطبيق الحالي على يمين الشاشة"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"تعدُّد المهام"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"استخدام \"وضع تقسيم الشاشة\" مع تثبيت التطبيق الحالي على اليمين"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"استخدام \"وضع تقسيم الشاشة\" مع تثبيت التطبيق الحالي على اليسار"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"التبديل من وضع \"تقسيم الشاشة\" إلى وضع \"ملء الشاشة\""</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"التبديل إلى التطبيق على اليسار أو الأسفل أثناء استخدام \"تقسيم الشاشة\""</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"التبديل إلى التطبيق على اليمين أو الأعلى أثناء استخدام \"تقسيم الشاشة\""</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"استبدال تطبيق بآخر في وضع \"تقسيم الشاشة\""</string> -    <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"إدخال"</string> +    <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"الإدخال"</string>      <string name="input_switch_input_language_next" msgid="3782155659868227855">"التبديل إلى اللغة التالية"</string>      <string name="input_switch_input_language_previous" msgid="6043341362202336623">"التبديل إلى اللغة السابقة"</string>      <string name="input_access_emoji" msgid="8105642858900406351">"الوصول إلى الرموز التعبيرية"</string> @@ -789,7 +786,7 @@      <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> -    <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"التقويم"</string> +    <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"تقويم Google"</string>      <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"الآلة الحاسبة"</string>      <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"خرائط Google"</string>      <string name="volume_and_do_not_disturb" msgid="502044092739382832">"عدم الإزعاج"</string> @@ -802,7 +799,7 @@      <string name="data_saver" msgid="3484013368530820763">"توفير البيانات"</string>      <string name="accessibility_data_saver_on" msgid="5394743820189757731">"تم تفعيل توفير البيانات"</string>      <string name="switch_bar_on" msgid="1770868129120096114">"مفعّل"</string> -    <string name="switch_bar_off" msgid="5669805115416379556">"متوقف"</string> +    <string name="switch_bar_off" msgid="5669805115416379556">"غير مفعّل"</string>      <string name="tile_unavailable" msgid="3095879009136616920">"غير متوفّر"</string>      <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"مزيد من المعلومات"</string>      <string name="nav_bar" msgid="4642708685386136807">"شريط التنقل"</string> @@ -830,7 +827,7 @@      <string name="left_icon" msgid="5036278531966897006">"رمز اليسار"</string>      <string name="right_icon" msgid="1103955040645237425">"رمز اليمين"</string>      <string name="drag_to_add_tiles" msgid="8933270127508303672">"اضغط باستمرار مع السحب لإضافة المربّعات"</string> -    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"اضغط باستمرار مع السحب لإعادة ترتيب الميزات."</string> +    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"اضغط باستمرار مع السحب لإعادة ترتيب الميزات"</string>      <string name="drag_to_remove_tiles" msgid="4682194717573850385">"اسحب هنا للإزالة"</string>      <string name="drag_to_remove_disabled" msgid="933046987838658850">"الحدّ الأدنى من عدد المربعات الذي تحتاج إليه هو <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>      <string name="qs_edit" msgid="5583565172803472437">"تعديل"</string> @@ -995,7 +992,7 @@      <string name="accessibility_floating_button_undo" msgid="511112888715708241">"تراجع"</string>      <string name="accessibility_floating_button_hidden_notification_title" msgid="4115036997406994799">"زر أدوات تسهيل الاستخدام مخفي"</string>      <string name="accessibility_floating_button_hidden_notification_text" msgid="1457021647040915658">"انقر لإظهار زر أدوات تسهيل الاستخدام."</string> -    <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"تمت إزالة اختصار <xliff:g id="FEATURE_NAME">%s</xliff:g>."</string> +    <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"تمت إزالة اختصار ميزة \"<xliff:g id="FEATURE_NAME">%s</xliff:g>\""</string>      <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{تمت إزالة اختصار واحد.}zero{تمت إزالة # اختصار.}two{تمت إزالة اختصارَين.}few{تمت إزالة # اختصارات.}many{تمت إزالة # اختصارًا.}other{تمت إزالة # اختصار.}}"</string>      <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"النقل إلى أعلى يمين الشاشة"</string>      <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"النقل إلى أعلى يسار الشاشة"</string> diff --git a/packages/SystemUI/res/values-ar/tiles_states_strings.xml b/packages/SystemUI/res/values-ar/tiles_states_strings.xml index 307a26e8e611..a89650aa6e19 100644 --- a/packages/SystemUI/res/values-ar/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ar/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"الخيار غير مفعَّل"</item>      <item msgid="5137565285664080143">"الخيار مفعَّل"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"غير متوفّرة"</item> +    <item msgid="3079622119444911877">"غير مفعَّلة"</item> +    <item msgid="3028994095749238254">"مفعَّلة"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 5a083abc0b50..1f859accbf55 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"ৰেকৰ্ড সম্পৰ্কীয় সমস্যা"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"আৰম্ভ কৰক"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"বন্ধ কৰক"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"বাগ ৰিপ’ৰ্ট"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"আপোনাৰ ডিভাইচৰ অভিজ্ঞতাৰ কোনটো অংশ প্ৰভাৱিত হৈছিল?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"সমস্যাৰ প্ৰকাৰ বাছনি কৰক"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"স্ক্ৰীন ৰেকৰ্ড"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"মধ্যমীয়া"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"উচ্চ"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"শুনাৰ ডিভাইচ"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"শুনাৰ ডিভাইচ"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"নতুন ডিভাইচ পেয়াৰ কৰক"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"নতুন ডিভাইচ পেয়াৰ কৰিবলৈ ক্লিক কৰক"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ডিভাইচৰ মাইক্ৰ\'ফ\'ন অৱৰোধৰ পৰা আঁতৰাবনে?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ডিভাইচৰ কেমেৰা অৱৰোধৰ পৰা আঁতৰাবনে?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ডিভাইচৰ কেমেৰা আৰু মাইক্ৰ\'ফ\'ন অৱৰোধৰ পৰা আঁতৰাবনে?"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"কীব\'ৰ্ডৰ সজ্জা সলনি কৰক"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"অথবা"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"সন্ধান কৰা প্ৰশ্ন মচক"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"শ্বৰ্টকাট"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"কীব’ৰ্ডৰ শ্বৰ্টকাট"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"সন্ধানৰ শ্বৰ্টকাট"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"কোনো শ্বৰ্টকাট বিচাৰি পোৱা নাই"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"ছিষ্টেম"</string> @@ -769,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant খোলক"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"লক স্ক্ৰীন"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"টোকা লিখক"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"ছিষ্টেম মাল্টিটাস্কিং"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"বৰ্তমানৰ এপৰ জৰিয়তে বিভাজিত স্ক্ৰীনৰ সোঁফালৰ স্ক্ৰীনখনত সোমাওক"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"বৰ্তমানৰ এপৰ জৰিয়তে বিভাজিত স্ক্ৰীনৰ বাওঁফালৰ স্ক্ৰীনখনত সোমাওক"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"মাল্টিটাস্কিং"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"বৰ্তমানৰ এপ্টোৰ সৈতে সোঁফালে বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰক"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"বৰ্তমানৰ এপ্টোৰ সৈতে বাওঁফালে বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰক"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"বিভাজিত স্ক্ৰীনৰ পৰা পূৰ্ণ স্ক্ৰীনলৈ সলনি কৰক"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰাৰ সময়ত সোঁফালে অথবা তলত থকা এপলৈ সলনি কৰক"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰাৰ সময়ত বাওঁফালে অথবা ওপৰত থকা এপলৈ সলনি কৰক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 7faec8a1e174..dc095c9169a3 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Qeyd problemi"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Başlayın"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Dayandırın"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Baq hesabatı"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cihaz istifadəsinə necə təsir etdi?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Problem növü seçin"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran qeydəalma"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standart"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Orta"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Yüksək"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Eşitmə cihazları"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Eşitmə cihazları"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yeni cihaz birləşdirin"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz birləşdirmək üçün klikləyin"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonu blokdan çıxarılsın?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Cihaz kamerası blokdan çıxarılsın?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Cihaz kamerası və mikrofonu blokdan çıxarılsın?"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Klaviatura düzümünü dəyişin"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"və ya"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Axtarış sorğusunu silin"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Qısayollar"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Klaviatura qısayolları"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Qısayollar axtarın"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Qısayol tapılmadı"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistem"</string> @@ -770,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistenti açın"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Kilid ekranı"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Qeyd götürün"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Sistemdə çoxsaylı tapşırıq icrası"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Cari tətbiq sağda olmaqla bölünmüş ekrana daxil olun"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Cari tətbiq solda olmaqla bölünmüş ekrana daxil olun"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Çoxsaylı tapşırıq icrası"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Cari tətbiq sağda olmaqla bölünmüş ekrandan istifadə edin"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Cari tətbiq solda olmaqla bölünmüş ekrandan istifadə edin"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Bölünmüş ekrandan tam ekrana keçin"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bölünmüş ekran istifadə edərkən sağda və ya aşağıda tətbiqə keçin"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bölünmüş ekran istifadə edərkən solda və ya yuxarıda tətbiqə keçin"</string> diff --git a/packages/SystemUI/res/values-az/tiles_states_strings.xml b/packages/SystemUI/res/values-az/tiles_states_strings.xml index f39036946434..c24f4029e415 100644 --- a/packages/SystemUI/res/values-az/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-az/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Deaktiv"</item>      <item msgid="5137565285664080143">"Aktiv"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Əlçatan deyil"</item> +    <item msgid="3079622119444911877">"Deaktiv"</item> +    <item msgid="3028994095749238254">"Aktiv"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index cd5dc2650b74..2f86ca4b3b8f 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Evidentirajte problem"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Pokreni"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Zaustavi"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Izveštaj o grešci"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na koji deo doživljaja na uređaju je ovo uticalo?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Izaberite tip problema"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje ekrana"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednje"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visoko"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni aparati"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni aparati"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Upari novi uređaj"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili nov uređaj"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite da odblokirate mikrofon uređaja?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite da odblokirate kameru uređaja?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite da odblokirate kameru i mikrofon uređaja?"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Promeni raspored tastature"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ili"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Obriši upit za pretragu"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Prečice"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tasterske prečice"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Pretražite prečice"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nisu pronađene prečice"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistem"</string> @@ -768,10 +766,10 @@      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Otvori podešavanja"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otvori pomoćnika"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Zaključavanje ekrana"</string> -    <string name="group_system_quick_memo" msgid="3764560265935722903">"Napravite belešku"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Obavljanje više zadataka sistema istovremeno"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Pokreni podeljeni ekran za aktuelnu aplikaciju na desnoj strani"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Pokreni podeljeni ekran za aktuelnu aplikaciju na levoj strani"</string> +    <string name="group_system_quick_memo" msgid="3764560265935722903">"Napravi belešku"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Obavljanje više zadataka istovremeno"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Koristite podeljeni ekran sa aktuelnom aplikacijom s desne strane"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Koristite podeljeni ekran sa aktuelnom aplikacijom s leve strane"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Pređi sa podeljenog ekrana na ceo ekran"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Pređite u aplikaciju zdesna ili ispod dok koristite podeljeni ekran"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pređite u aplikaciju sleva ili iznad dok koristite podeljeni ekran"</string> @@ -1295,9 +1293,9 @@      <string name="privacy_dialog_manage_permissions" msgid="2543451567190470413">"Upravljaj pristupom"</string>      <string name="privacy_dialog_active_call_usage" msgid="7858746847946397562">"Koristi telefonski poziv"</string>      <string name="privacy_dialog_recent_call_usage" msgid="1214810644978167344">"Nedavno korišćeno u telefonskom pozivu"</string> -    <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"Koriste <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> +    <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"Koristi <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Nedavno koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> -    <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"Koriste <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> +    <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"Koristi <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Nedavno koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Koriste <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>      <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Nedavno koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index a76c38b54218..bc03d8c25213 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Запіс праблемы"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Пачынайце"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Спыніцеся"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"З чым была звязана праблема, якая вам сустрэлася?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Выберыце тып праблемы"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запіс экрана"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандартная"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Сярэдняя"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Высокая"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слыхавыя апараты"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слыхавыя апараты"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Спалучыць новую прыладу"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Націсніце, каб спалучыць новую прыладу"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Разблакіраваць мікрафон прылады?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Разблакіраваць камеру прылады?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Разблакіраваць камеру і мікрафон прылады?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Пераключыць раскладку клавіятуры"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"або"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Ачысціць пошукавы запыт"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Ярлыкі"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Спалучэнні клавіш"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Пошук ярлыкоў"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Ярлыкі не знойдзены"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Сістэма"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Выклікаць Памочніка"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Экран блакіроўкі"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Стварыць нататку"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Шматзадачнасць сістэмы"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Перайсці ў рэжым падзеленага экрана з бягучай праграмай справа"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Перайсці ў рэжым падзеленага экрана з бягучай праграмай злева"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Шматзадачнасць"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Падзяліць экран і памясціць гэту праграму справа"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Падзяліць экран і памясціць гэту праграму злева"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Пераключыцца з рэжыму падзеленага экрана на поўнаэкранны рэжым"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Пераключыцца на праграму справа або ўнізе на падзеленым экране"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Пераключыцца на праграму злева або ўверсе на падзеленым экране"</string> diff --git a/packages/SystemUI/res/values-be/tiles_states_strings.xml b/packages/SystemUI/res/values-be/tiles_states_strings.xml index 32619ef03053..33e704cae0b1 100644 --- a/packages/SystemUI/res/values-be/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-be/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Выключана"</item>      <item msgid="5137565285664080143">"Уключана"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Недаступна"</item> +    <item msgid="3079622119444911877">"Выключана"</item> +    <item msgid="3028994095749238254">"Уключана"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index f8793b3faeea..d80b8894dd18 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Записване на проблем"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Стартиране"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Спиране"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"С какво имахте проблем?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изберете тип проблем"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запис на екрана"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандартен"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Среден"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Висок"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слухови апарати"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухови апарати"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Сдвояване на ново устройство"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликнете за сдвояване на ново устройство"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Да се отблокира ли микрофонът на устройството?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Да се отблокира ли камерата на устройството?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Да се отблокират ли камерата и микрофонът на устройството?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Превкл. на клавиат. подредба"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"или"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Изчистване на заявката за търсене"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Клавишни комбинации"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Клавишни комбинации"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Търсете комбинации"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Няма клавишни комбинации"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Система"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Отваряне на Асистент"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Заключване на екрана"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Създаване на бележка"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Едновременно изпълняване на няколко задачи в системата"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Преминаване към разделен екран с текущото приложение отдясно"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Преминаване към разделен екран с текущото приложение отляво"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Изпълняване на няколко задачи едновременно"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Използване на разделен екран с текущото приложение вдясно"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Използване на разделен екран с текущото приложение вляво"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Превключване от разделен към цял екран"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Превключване към приложението вдясно/отдолу в режима на разделен екран"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Превключване към приложението вляво/отгоре в режима на разделен екран"</string> @@ -1285,7 +1283,7 @@      <string name="dismiss_dialog" msgid="2195508495854675882">"Отхвърляне"</string>      <string name="connected_display_icon_desc" msgid="6373560639989971997">"Свързан е екран"</string>      <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string> -    <string name="privacy_dialog_summary" msgid="2458769652125995409">"Скорошно използване на приложението"</string> +    <string name="privacy_dialog_summary" msgid="2458769652125995409">"Скорошно използване от приложенията"</string>      <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Вижте скорошния достъп"</string>      <string name="privacy_dialog_done_button" msgid="4504330708531434263">"Готово"</string>      <string name="privacy_dialog_expand_action" msgid="9129262348628331377">"Разгъване и показване на опциите"</string> diff --git a/packages/SystemUI/res/values-bg/tiles_states_strings.xml b/packages/SystemUI/res/values-bg/tiles_states_strings.xml index 381b0f0b2abb..e2fd65360020 100644 --- a/packages/SystemUI/res/values-bg/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-bg/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Изключено"</item>      <item msgid="5137565285664080143">"Включено"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Не е налице"</item> +    <item msgid="3079622119444911877">"Изкл."</item> +    <item msgid="3028994095749238254">"Вкл."</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index f6de0e38228b..36b57ee2975b 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -333,7 +333,7 @@      <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"সূর্যোদয় পর্যন্ত"</string>      <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g> এ চালু হবে"</string>      <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> পর্যন্ত"</string> -    <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"গাঢ় থিম"</string> +    <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"ডার্ক থিম"</string>      <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"ব্যাটারি সেভার"</string>      <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"সূর্যাস্তে চালু হবে"</string>      <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"সূর্যোদয় পর্যন্ত"</string> @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"রেকর্ডিংয়ে সমস্যা"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"শুরু করুন"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"বন্ধ করুন"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ডিভাইস ব্যবহার করার সময় কোথায় অসুবিধা হয়েছিল?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"সমস্যার প্রকার বেছে নিন"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"স্ক্রিন রেকর্ড"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"স্ট্যান্ডার্ড"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"মিডিয়াম"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"হাই"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"হিয়ারিং ডিভাইস"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"হিয়ারিং ডিভাইস"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"নতুন ডিভাইস পেয়ার করুন"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"নতুন ডিভাইস পেয়ার করতে ক্লিক করুন"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ডিভাইসের মাইক্রোফোন আনব্লক করতে চান?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ডিভাইসের ক্যামেরা আনব্লক করতে চান?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ডিভাইসের ক্যামেরা এবং মাইক্রোফোন আনব্লক করতে চান?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"কীবোর্ড লে-আউট পাল্টান"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"অথবা"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"সার্চ কোয়েরি মুছুন"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"শর্টকাট"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"কীবোর্ড শর্টকাট"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"শর্টকাট সার্চ করুন"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"কোনও শর্টকার্ট পাওয়া যায়নি"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"সিস্টেম"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant খুলুন"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"লক স্ক্রিন"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"একটি নোট লিখুন"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"সিস্টেম মাল্টিটাস্কিং"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"ডানদিকে থাকা বর্তমান অ্যাপ ব্যবহার করে \'স্প্লিট স্ক্রিন\' যোগ করুন"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"বাঁদিকে থাকা বর্তমান অ্যাপ ব্যবহার করে \'স্প্লিট স্ক্রিন\' যোগ করুন"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"মাল্টিটাস্কিং"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"ডানদিকে বর্তমান অ্যাপে স্প্লিট স্ক্রিন ব্যবহার করুন"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"বাঁদিকে বর্তমান অ্যাপে স্প্লিট স্ক্রিন ব্যবহার করুন"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"\'স্প্লিট স্ক্রিন\' থেকে ফুল স্ক্রিনে পাল্টান"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"স্প্লিট স্ক্রিন ব্যবহার করার সময় ডানদিকের বা নিচের অ্যাপে পাল্টে নিন"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"স্প্লিট স্ক্রিন ব্যবহার করার সময় বাঁদিকের বা উপরের অ্যাপে পাল্টে নিন"</string> diff --git a/packages/SystemUI/res/values-bn/tiles_states_strings.xml b/packages/SystemUI/res/values-bn/tiles_states_strings.xml index 2eebd97088ab..6e4dfbfbf745 100644 --- a/packages/SystemUI/res/values-bn/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-bn/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"বন্ধ আছে"</item>      <item msgid="5137565285664080143">"চালু আছে"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"উপলভ্য নেই"</item> +    <item msgid="3079622119444911877">"বন্ধ আছে"</item> +    <item msgid="3028994095749238254">"চালু আছে"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 93477575571e..91acfa5b3a2b 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Snimite problem"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Pokrenite"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Zaustavite"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Izvješće o pogrešci"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Koji dio uređaja je imao problem?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Odaberite vrstu problema"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje ekrana"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardno"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednje"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visoko"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni aparati"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni aparati"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparite novi uređaj"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da uparite novi uređaj"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokirati mikrofon uređaja?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblokirati kameru uređaja?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblokirati kameru i mikrofon uređaja?"</string> @@ -448,8 +445,8 @@      <string name="button_to_remove_widget" msgid="3948204829181214098">"Uklanjanje"</string>      <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajte vidžet"</string>      <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string> -    <string name="label_for_button_in_empty_state_cta" msgid="7314975555382055823">"Dodaj widgete"</string> -    <string name="title_for_empty_state_cta" msgid="6161654421223450530">"Brzo pristupajte widgetima omiljenih aplikacija bez otključavanja tableta."</string> +    <string name="label_for_button_in_empty_state_cta" msgid="7314975555382055823">"Dodajte vidžet"</string> +    <string name="title_for_empty_state_cta" msgid="6161654421223450530">"Dobijte brz pristup omiljenim vidžetima aplikacija bez otključavanja tableta."</string>      <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"Dozvoliti bilo koji vidžet na zaključanom ekranu?"</string>      <string name="button_text_to_open_settings" msgid="1987729256950941628">"Otvori postavke"</string>      <string name="work_mode_off_title" msgid="5794818421357835873">"Pokrenuti poslovne aplikacije?"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Zamijeni raspored tastature"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ili"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Brisanje upita za pretraživanje"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Prečice"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Prečice na tastaturi"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Pretraživanje prečica"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nisu pronađene prečice"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistem"</string> @@ -770,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otvaranje Asistenta"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Zaključavanje ekrana"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Pisanje bilješke"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitasking sistema"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Otvaranje podijeljenog ekrana s trenutnom aplikacijom na desnoj strani"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Otvaranje podijeljenog ekrana s trenutnom aplikacijom na lijevoj strani"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Korištenje podijeljenog ekrana s trenutnom aplikacijom na desnoj strani"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Korištenje podijeljenog ekrana s trenutnom aplikacijom na lijevoj strani"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Prebacivanje s podijeljenog ekrana na prikaz preko cijelog ekrana"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Pređite u aplikaciju desno ili ispod dok koristite podijeljeni ekran"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pređite u aplikaciju lijevo ili iznad dok koristite podijeljeni ekran"</string> diff --git a/packages/SystemUI/res/values-bs/tiles_states_strings.xml b/packages/SystemUI/res/values-bs/tiles_states_strings.xml index e09cab50e9bb..df0b78664cba 100644 --- a/packages/SystemUI/res/values-bs/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-bs/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Isključeno"</item>      <item msgid="5137565285664080143">"Uključeno"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Nedostupno"</item> +    <item msgid="3079622119444911877">"Isključeno"</item> +    <item msgid="3028994095749238254">"Uključeno"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 40532ca9f664..14456238cd63 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Registra el problema"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Inicia"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Atura"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"L\'experiència amb el dispositiu s\'ha vist afectada?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona el tipus de problema"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravació de pantalla"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Estàndard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Mitjà"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alt"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Audiòfons"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Audiòfons"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincula un dispositiu nou"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fes clic per vincular un dispositiu nou"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vols desbloquejar el micròfon del dispositiu?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vols desbloquejar la càmera del dispositiu?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vols desbloquejar la càmera i el micròfon del dispositiu?"</string> @@ -745,12 +743,12 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Canvia disposició de teclat"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"o"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Esborra la consulta de cerca"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Dreceres"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tecles de drecera"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Cerca dreceres"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"No s\'ha trobat cap drecera"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistema"</string>      <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"Entrada"</string> -    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Obre aplicacions"</string> +    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Aplicacions obertes"</string>      <string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"Aplicació actual"</string>      <string name="keyboard_shortcut_a11y_show_search_results" msgid="2865241062981833705">"S\'estan mostrant els resultats de la cerca"</string>      <string name="keyboard_shortcut_a11y_filter_system" msgid="7744143131119370483">"S\'estan mostrant les dreceres del sistema"</string> @@ -768,11 +766,11 @@      <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Obre la llista d\'aplicacions"</string>      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Obre la configuració"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Obre l\'Assistent"</string> -    <string name="group_system_lock_screen" msgid="7391191300363416543">"Pantalla de bloqueig"</string> +    <string name="group_system_lock_screen" msgid="7391191300363416543">"Bloqueja la pantalla"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Crea una nota"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitasques del sistema"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Entra al mode de pantalla dividida amb l\'aplicació actual a la dreta"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Entra al mode de pantalla dividida amb l\'aplicació actual a l\'esquerra"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasca"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Utilitza la pantalla dividida amb l\'aplicació actual a la dreta"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Utilitza la pantalla dividida amb l\'aplicació actual a l\'esquerra"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Canvia de pantalla dividida a pantalla completa"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Canvia a l\'aplicació de la dreta o de sota amb la pantalla dividida"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Canvia a l\'aplicació de l\'esquerra o de dalt amb la pantalla dividida"</string> diff --git a/packages/SystemUI/res/values-ca/tiles_states_strings.xml b/packages/SystemUI/res/values-ca/tiles_states_strings.xml index 6a36b6f5b9d8..67eb853c9ee6 100644 --- a/packages/SystemUI/res/values-ca/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ca/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Desactivat"</item>      <item msgid="5137565285664080143">"Activat"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"No disponible"</item> +    <item msgid="3079622119444911877">"Desactivat"</item> +    <item msgid="3028994095749238254">"Activat"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 16c2914e32f7..7b766abc30b5 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Zaznamenat problém"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Spustit"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Ukončit"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Co v zařízení bylo ovlivněno?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vyberte druh problém"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Záznam obrazovky"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardní"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Střední"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Vysoká"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Naslouchátka"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Naslouchátka"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Spárovat nové zařízení"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zařízení"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokovat mikrofon zařízení?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Odblokovat fotoaparát zařízení?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Odblokovat fotoaparát a mikrofon zařízení?"</string> @@ -680,7 +678,7 @@      <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Zobrazuje se v horní části sekce konverzací a na obrazovce uzamčení se objevuje jako profilová fotka, má podobu bubliny"</string>      <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Zobrazuje se v horní části sekce konverzací a na obrazovce uzamčení se objevuje jako profilová fotka, deaktivuje režim Nerušit"</string>      <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Zobrazuje se v horní části sekce konverzací a na obrazovce uzamčení se objevuje jako profilová fotka, má podobu bubliny a deaktivuje režim Nerušit"</string> -    <string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string> +    <string name="notification_priority_title" msgid="2079708866333537093">"Prioritní"</string>      <string name="no_shortcut" msgid="8257177117568230126">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> funkce konverzace nepodporuje"</string>      <string name="notification_unblockable_desc" msgid="2073030886006190804">"Tato oznámení nelze upravit."</string>      <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Upozornění na hovor nelze upravit."</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Přepnout rozložení klávesnice"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"nebo"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Vymazat vyhledávaný dotaz"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Zkratky"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Klávesové zkratky"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Vyhledat zkratky"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Žádné zkratky nenalezeny"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Systém"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otevřít Asistenta"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Uzamknout obrazovku"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Vytvořit poznámku"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Systémový multitasking"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Přepnout na rozdělenou obrazovku s aktuálními aplikacemi napravo"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Přepnout na rozdělenou obrazovku s aktuálními aplikacemi nalevo"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Použít rozdělenou obrazovku se stávající aplikací vpravo"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Použít rozdělenou obrazovku se stávající aplikací vlevo"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Přepnout z rozdělené obrazovky na celou obrazovku"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Přechod na aplikaci vpravo nebo dole v režimu rozdělené obrazovky"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Přechod na aplikaci vlevo nebo nahoře v režimu rozdělené obrazovky"</string> @@ -1147,7 +1145,7 @@      <string name="audio_status" msgid="4237055636967709208">"Poslouchá"</string>      <string name="game_status" msgid="1340694320630973259">"Hraji hru"</string>      <string name="empty_user_name" msgid="3389155775773578300">"Přátelé"</string> -    <string name="empty_status" msgid="5938893404951307749">"Proberem to večer?"</string> +    <string name="empty_status" msgid="5938893404951307749">"Probereme to večer?"</string>      <string name="status_before_loading" msgid="1500477307859631381">"Obsah se brzy zobrazí"</string>      <string name="missed_call" msgid="4228016077700161689">"Zmeškaný hovor"</string>      <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string> @@ -1269,7 +1267,7 @@      <string name="install_dialer_on_work_profile_action" msgid="2014659711597862506">"Nainstalovat pracovní telefonní aplikaci"</string>      <string name="call_from_work_profile_close" msgid="5830072964434474143">"Zrušit"</string>      <string name="lock_screen_settings" msgid="6152703934761402399">"Přizpůsobit obrazovku uzamčení"</string> -    <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Pokud chcete upravit obrazovku uzamčení, odemkněte zařízení"</string> +    <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Obrazovku uzamčení upravíte, když zařízení odemknete"</string>      <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Síť Wi-Fi není dostupná"</string>      <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokována"</string>      <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofon jsou blokovány"</string> diff --git a/packages/SystemUI/res/values-cs/tiles_states_strings.xml b/packages/SystemUI/res/values-cs/tiles_states_strings.xml index 02a0f5f792b0..ae533a8623ec 100644 --- a/packages/SystemUI/res/values-cs/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-cs/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Vypnuto"</item>      <item msgid="5137565285664080143">"Zapnuto"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Není k dispozici"</item> +    <item msgid="3079622119444911877">"Vypnuto"</item> +    <item msgid="3028994095749238254">"Zapnuto"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 4754dbb5cdb3..2100e275ed2a 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Optag problem"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvilken del af din enhedsoplevelse blev påvirket?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vælg problemtype"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skærmoptagelse"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Middel"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Høj"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Høreapparater"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Høreapparater"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Par ny enhed"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik for at parre en ny enhed"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du fjerne blokeringen af enhedens mikrofon?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vil du fjerne blokeringen af enhedens kamera?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vil du fjerne blokeringen af enhedens kamera og mikrofon?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Skift tastaturlayout"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"eller"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Ryd søgeforespørgsel"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Genveje"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tastaturgenveje"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Søg efter genveje"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Ingen genveje blev fundet"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"System"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Åbn Assistent"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Lås skærm"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Skriv en note"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Systemmultitasking"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Start opdelt skærm med aktuel app til højre"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Start opdelt skærm med aktuel app til venstre"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Brug opdelt skærm med aktuel app til højre"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Brug opdelt skærm med aktuel app til venstre"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Skift fra opdelt skærm til fuld skærm"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skift til en app til højre eller nedenfor, når du bruger opdelt skærm"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skift til en app til venstre eller ovenfor, når du bruger opdelt skærm"</string> diff --git a/packages/SystemUI/res/values-da/tiles_states_strings.xml b/packages/SystemUI/res/values-da/tiles_states_strings.xml index 598fcfe40dc8..2c3b0535cb33 100644 --- a/packages/SystemUI/res/values-da/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-da/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Fra"</item>      <item msgid="5137565285664080143">"Til"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Ikke tilgængelig"</item> +    <item msgid="3079622119444911877">"Fra"</item> +    <item msgid="3028994095749238254">"Til"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 2fd26bcd39b9..6c4f4b5f7c91 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Problem aufnehmen"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Aufnahme starten"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Aufnahme beenden"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Welche Bereiche des Geräts waren betroffen?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Art des Problems auswählen"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Bildschirmaufnahme"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Mittel"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Hoch"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hörgeräte"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hörgeräte"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Neues Gerät koppeln"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicken, um neues Gerät zu koppeln"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Blockierung des Gerätemikrofons aufheben?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Blockierung der Gerätekamera aufheben?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Blockierung von Gerätekamera und Gerätemikrofon aufheben?"</string> @@ -448,10 +446,8 @@      <string name="button_to_remove_widget" msgid="3948204829181214098">"Entfernen"</string>      <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget hinzufügen"</string>      <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fertig"</string> -    <!-- no translation found for label_for_button_in_empty_state_cta (7314975555382055823) --> -    <skip /> -    <!-- no translation found for title_for_empty_state_cta (6161654421223450530) --> -    <skip /> +    <string name="label_for_button_in_empty_state_cta" msgid="7314975555382055823">"Widgets hinzufügen"</string> +    <string name="title_for_empty_state_cta" msgid="6161654421223450530">"Greife schnell auf deine App-Widgets zu, ohne das Tablet entsperren zu müssen."</string>      <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"Beliebige Widgets auf Sperrbildschirm zulassen?"</string>      <string name="button_text_to_open_settings" msgid="1987729256950941628">"Einstellungen öffnen"</string>      <string name="work_mode_off_title" msgid="5794818421357835873">"Geschäftliche Apps nicht mehr pausieren?"</string> @@ -747,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Tastaturlayout wechseln"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"oder"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Suchanfrage löschen"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Tastenkombinationen"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tastenkombinationen"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Tastenkombinationen suchen"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Keine gefunden"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"System"</string> @@ -772,16 +768,16 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant öffnen"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Sperrbildschirm"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Notiz machen"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"System-Multitasking"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Splitscreen aktivieren, aktuelle App rechts"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Splitscreen aktivieren, aktuelle App links"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Splitscreen mit der aktuellen App auf der rechten Seite nutzen"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Splitscreen mit der aktuellen App auf der linken Seite nutzen"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Vom Splitscreen zum Vollbild wechseln"</string> -    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Im Splitscreen-Modus rechts oder unten zu einer App wechseln"</string> -    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Im Splitscreen-Modus links oder oben zu einer App wechseln"</string> +    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Im Splitscreen-Modus zu einer App rechts oder unten wechseln"</string> +    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Im Splitscreen-Modus zu einer App links oder oben wechseln"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"Im Splitscreen: eine App durch eine andere ersetzen"</string>      <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Eingabe"</string>      <string name="input_switch_input_language_next" msgid="3782155659868227855">"Zur nächsten Sprache wechseln"</string> -    <string name="input_switch_input_language_previous" msgid="6043341362202336623">"Zu vorheriger Sprache wechseln"</string> +    <string name="input_switch_input_language_previous" msgid="6043341362202336623">"Zur vorherigen Sprache wechseln"</string>      <string name="input_access_emoji" msgid="8105642858900406351">"Auf Emoji zugreifen"</string>      <string name="input_access_voice_typing" msgid="7291201476395326141">"Auf Spracheingabe zugreifen"</string>      <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Apps"</string> @@ -793,7 +789,7 @@      <string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musik"</string>      <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string>      <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Rechner"</string> -    <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Karten"</string> +    <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string>      <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Bitte nicht stören"</string>      <string name="volume_dnd_silent" msgid="4154597281458298093">"Tastenkombination für Lautstärketasten"</string>      <string name="battery" msgid="769686279459897127">"Akku"</string> diff --git a/packages/SystemUI/res/values-de/tiles_states_strings.xml b/packages/SystemUI/res/values-de/tiles_states_strings.xml index 4b4eed53d1f4..0606cc79f2e9 100644 --- a/packages/SystemUI/res/values-de/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-de/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Aus"</item>      <item msgid="5137565285664080143">"An"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Nicht verfügbar"</item> +    <item msgid="3079622119444911877">"Aus"</item> +    <item msgid="3028994095749238254">"An"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 0c3f0d54caad..4c964de521fa 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Εγγραφή προβλήματος"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Έναρξη"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Διακοπή"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ποιο κομμάτι της εμπειρίας συσκευής επηρεάστηκε;"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Επιλογή τύπου προβλήματος"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Εγγραφή οθόνης"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Τυπική"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Μέτρια"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Υψηλή"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Συσκευές ακοής"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Συσκευές ακοής"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Σύζευξη νέας συσκευής"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Κάντε κλικ για σύζευξη νέας συσκευής"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Κατάργηση αποκλεισμού μικροφώνου συσκευής;"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Κατάργηση αποκλεισμού κάμερας συσκευής;"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Κατάργηση αποκλεισμού κάμερας και μικροφώνου συσκευής;"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Αλλαγή διάταξης πληκτρολογίου"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ή"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Διαγραφή ερωτήματος αναζήτησης"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Συντομεύσεις"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Συντομεύσ. πληκτρολογίου"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Αναζήτηση συντομεύσεων"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Δεν βρέθηκαν συντομεύσεις"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Σύστημα"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Άνοιγμα Βοηθού"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Κλείδωμα οθόνης"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Δημιουργία σημείωσης"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Πολυδιεργασία συστήματος"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Ενεργοποίηση διαχωρισμού οθόνης με την τρέχουσα εφαρμογή στα δεξιά"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Ενεργοποίηση διαχωρισμού οθόνης με την τρέχουσα εφαρμογή στα αριστερά"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Πολυδιεργασία"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Χρήση διαχωρισμού οθόνης με την τρέχουσα εφαρμογή στα δεξιά"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Χρήση διαχωρισμού οθόνης με την τρέχουσα εφαρμογή στα αριστερά"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Εναλλαγή από διαχωρισμό οθόνης σε πλήρη οθόνη"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Εναλλαγή στην εφαρμογή δεξιά ή κάτω κατά τη χρήση διαχωρισμού οθόνης"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Εναλλαγή σε εφαρμογή αριστερά ή επάνω κατά τη χρήση διαχωρισμού οθόνης"</string> diff --git a/packages/SystemUI/res/values-el/tiles_states_strings.xml b/packages/SystemUI/res/values-el/tiles_states_strings.xml index e4c6854a2f30..d4545ffa6641 100644 --- a/packages/SystemUI/res/values-el/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-el/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Ανενεργό"</item>      <item msgid="5137565285664080143">"Ενεργό"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Μη διαθέσιμη"</item> +    <item msgid="3079622119444911877">"Ανενεργή"</item> +    <item msgid="3028994095749238254">"Ενεργή"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index a8848a581386..fc27f16f7a88 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Record issue"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string> @@ -551,7 +549,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps that you use, your location and your screen time."</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Device was locked, too many authentication attempts"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Device was locked – too many authentication attempts"</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Device locked\nFailed authentication"</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="accessibility_volume_settings" msgid="1458961116951564784">"Sound settings"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Switch keyboard layout"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"or"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Clear search query"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Shortcuts"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Keyboard shortcuts"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Search shortcuts"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"No shortcuts found"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"System"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Open Assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Take a note"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"System multitasking"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Enter split screen with current app to RHS"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Enter split screen with current app to LHS"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multi-tasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Use split screen with current app on the right"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Use split screen with current app on the left"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Switch from split screen to full screen"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string> diff --git a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml index 304abe108492..39dd7c84b13e 100644 --- a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Off"</item>      <item msgid="5137565285664080143">"On"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Unavailable"</item> +    <item msgid="3079622119444911877">"Off"</item> +    <item msgid="3028994095749238254">"On"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 4b69255b6c96..088f75184889 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Record Issue"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Bug Report"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> @@ -741,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Switch keyboard layout"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"or"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Clear search query"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Shortcuts"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Keyboard Shortcuts"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Search shortcuts"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"No shortcuts found"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"System"</string> @@ -766,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Open assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Take a note"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"System multitasking"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Enter split screen with current app to RHS"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Enter split screen with current app to LHS"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Use split screen with current app on the right"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Use split screen with current app on the left"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Switch from split screen to full screen"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to app on right or below while using split screen"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to app on left or above while using split screen"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index a8848a581386..fc27f16f7a88 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Record issue"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string> @@ -551,7 +549,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps that you use, your location and your screen time."</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Device was locked, too many authentication attempts"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Device was locked – too many authentication attempts"</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Device locked\nFailed authentication"</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="accessibility_volume_settings" msgid="1458961116951564784">"Sound settings"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Switch keyboard layout"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"or"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Clear search query"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Shortcuts"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Keyboard shortcuts"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Search shortcuts"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"No shortcuts found"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"System"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Open Assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Take a note"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"System multitasking"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Enter split screen with current app to RHS"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Enter split screen with current app to LHS"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multi-tasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Use split screen with current app on the right"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Use split screen with current app on the left"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Switch from split screen to full screen"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string> diff --git a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml index 304abe108492..39dd7c84b13e 100644 --- a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Off"</item>      <item msgid="5137565285664080143">"On"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Unavailable"</item> +    <item msgid="3079622119444911877">"Off"</item> +    <item msgid="3028994095749238254">"On"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index a8848a581386..fc27f16f7a88 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Record issue"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medium"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"High"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Unblock device camera?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Unblock device camera and microphone?"</string> @@ -551,7 +549,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"This device is managed by your parent. Your parent can see and manage information such as the apps that you use, your location and your screen time."</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Device was locked, too many authentication attempts"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Device was locked – too many authentication attempts"</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Device locked\nFailed authentication"</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="accessibility_volume_settings" msgid="1458961116951564784">"Sound settings"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Switch keyboard layout"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"or"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Clear search query"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Shortcuts"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Keyboard shortcuts"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Search shortcuts"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"No shortcuts found"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"System"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Open Assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Take a note"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"System multitasking"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Enter split screen with current app to RHS"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Enter split screen with current app to LHS"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multi-tasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Use split screen with current app on the right"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Use split screen with current app on the left"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Switch from split screen to full screen"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to the app on the right or below while using split screen"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to the app on the left or above while using split screen"</string> diff --git a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml index 304abe108492..39dd7c84b13e 100644 --- a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Off"</item>      <item msgid="5137565285664080143">"On"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Unavailable"</item> +    <item msgid="3079622119444911877">"Off"</item> +    <item msgid="3028994095749238254">"On"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 3ed9fc5184df..958c6456cd6f 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Record Issue"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stop"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Bug Report"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"What part of your device experience was affected?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Select issue type"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Screen record"</string> @@ -741,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Switch keyboard layout"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"or"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Clear search query"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Shortcuts"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Keyboard Shortcuts"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Search shortcuts"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"No shortcuts found"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"System"</string> @@ -766,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Open assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Lock screen"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Take a note"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"System multitasking"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Enter split screen with current app to RHS"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Enter split screen with current app to LHS"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Use split screen with current app on the right"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Use split screen with current app on the left"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Switch from split screen to full screen"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Switch to app on right or below while using split screen"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Switch to app on left or above while using split screen"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 3755fb6fde5a..b625dc5cfd09 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Grabar error"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Detener"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"¿Qué parte de tu exp. del disp. se vio afectada?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Seleccionar tipo de problema"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Grabadora de pant."</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Estándar"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medio"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular dispositivo nuevo"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para vincular un dispositivo nuevo"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Quieres desbloquear el micrófono del dispositivo?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"¿Quieres desbloquear la cámara del dispositivo?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"¿Quieres desbloquear la cámara y el micrófono del dispositivo?"</string> @@ -668,7 +666,7 @@      <string name="notification_alert_title" msgid="3656229781017543655">"Predeterminada"</string>      <string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>      <string name="notification_channel_summary_low" msgid="4860617986908931158">"Sin sonido ni vibración"</string> -    <string name="notification_conversation_summary_low" msgid="1734433426085468009">"No suena ni vibra, y aparece en la parte inferior de la sección de conversaciones."</string> +    <string name="notification_conversation_summary_low" msgid="1734433426085468009">"No suena ni vibra, y aparece en la parte inferior de la sección de conversaciones"</string>      <string name="notification_channel_summary_default" msgid="777294388712200605">"Puede sonar o vibrar según la configuración del dispositivo"</string>      <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Puede sonar o vibrar según la configuración del dispositivo. Conversaciones de la burbuja de <xliff:g id="APP_NAME">%1$s</xliff:g> de forma predeterminada."</string>      <string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Dejar que el sistema determine si esta notificación debe emitir un sonido o una vibración"</string> @@ -715,7 +713,7 @@      <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Flecha hacia arriba"</string>      <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Flecha hacia abajo"</string>      <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Flecha a la izquierda"</string> -    <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Flecha hacia la derecha"</string> +    <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Flecha a la derecha"</string>      <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centro"</string>      <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string>      <string name="keyboard_key_space" msgid="6980847564173394012">"Espacio"</string> @@ -743,10 +741,10 @@      <string name="keyboard_shortcut_group_system_notifications" msgid="3615971650562485878">"Notificaciones"</string>      <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4856808328618265589">"Ver combinaciones de teclas"</string>      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Cambiar diseño del teclado"</string> -    <string name="keyboard_shortcut_join" msgid="3578314570034512676">"o bien"</string> +    <string name="keyboard_shortcut_join" msgid="3578314570034512676">"o"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Borrar búsqueda"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Combinaciones de teclas"</string> -    <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Buscar comb. de teclas"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Combinaciones de teclas"</string> +    <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Buscar combinaciones de teclas"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"No hay comb. de teclas"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistema"</string>      <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"Entrada"</string> @@ -770,12 +768,12 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir Asistente"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Bloquear la pantalla"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Crear una nota"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Tareas múltiples del sistema"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Activar pantalla dividida con la app actual en el lado derecho (RHS)"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Activar pantalla dividida con la app actual en el lado izquierdo (LHS)"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Tareas múltiples"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Usar la pantalla dividida con la app actual a la derecha"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Usar la pantalla dividida con la app actual a la izquierda"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Cambiar de pantalla dividida a pantalla completa"</string> -    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Ubica la app a la derecha o abajo cuando usas la pantalla dividida"</string> -    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Ubica la app a la izquierda o arriba cuando usas la pantalla dividida"</string> +    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Ubicar la app a la derecha o abajo cuando usas la pantalla dividida"</string> +    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Ubicar la app a la izquierda o arriba cuando usas la pantalla dividida"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"Durante pantalla dividida: Reemplaza una app con otra"</string>      <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string>      <string name="input_switch_input_language_next" msgid="3782155659868227855">"Cambiar al próximo idioma"</string> @@ -1194,7 +1192,7 @@      <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está activa}many{# apps están activas}other{# apps están activas}}"</string>      <string name="fgs_dot_content_description" msgid="2865071539464777240">"Nueva información"</string>      <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps activas"</string> -    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Estas apps están activas y en ejecución, incluso mientras no las usas. Esto mejora su funcionalidad, pero también afecta la duración de batería."</string> +    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Estas apps están activas y en ejecución, incluso mientras no las usas. Esto mejora su funcionalidad, pero también afecta la duración de la batería."</string>      <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Detener"</string>      <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Detenida"</string>      <string name="clipboard_edit_text_done" msgid="4551887727694022409">"Listo"</string> diff --git a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml index 71efef961b89..869efff07bdf 100644 --- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Desactivado"</item>      <item msgid="5137565285664080143">"Activado"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"No disponibles"</item> +    <item msgid="3079622119444911877">"Desactivados"</item> +    <item msgid="3028994095749238254">"Activados"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 01afa2903bf6..583a18116222 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Problema de grabación"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Detener"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"¿Qué parte de tu experiencia se ha visto afectada?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona el tipo de problema"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Grabar pantalla"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Estándar"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medio"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Audífonos"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Audífonos"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Emparejar nuevo dispositivo"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para emparejar un nuevo dispositivo"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Desbloquear el micrófono del dispositivo?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"¿Desbloquear la cámara del dispositivo?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"¿Desbloquear la cámara y el micrófono del dispositivo?"</string> @@ -714,8 +712,8 @@      <string name="keyboard_key_back" msgid="4185420465469481999">"Atrás"</string>      <string name="keyboard_key_dpad_up" msgid="7199805608386368673">"Flecha hacia arriba"</string>      <string name="keyboard_key_dpad_down" msgid="3354221123220737397">"Flecha hacia abajo"</string> -    <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Flecha hacia la izquierda"</string> -    <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Flecha hacia la derecha"</string> +    <string name="keyboard_key_dpad_left" msgid="144176368026538621">"Flecha izquierda"</string> +    <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"Flecha derecha"</string>      <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Centro"</string>      <string name="keyboard_key_tab" msgid="4592772350906496730">"Tabulador"</string>      <string name="keyboard_key_space" msgid="6980847564173394012">"Espacio"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Cambiar diseño del teclado"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"o"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Borrar la consulta de búsqueda"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Combinaciones de teclas"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Combinaciones de teclas"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Buscar combinaciones de teclas"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Ninguna encontrada"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistema"</string> @@ -769,10 +767,10 @@      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Abrir ajustes"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir el Asistente"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Pantalla de bloqueo"</string> -    <string name="group_system_quick_memo" msgid="3764560265935722903">"Escribe una nota"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Función multitarea del sistema"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Iniciar pantalla dividida con esta aplicación en el lado derecho"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Iniciar pantalla dividida con esta aplicación en el lado izquierdo"</string> +    <string name="group_system_quick_memo" msgid="3764560265935722903">"Escribir una nota"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitarea"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Usar la pantalla dividida con la aplicación actual a la derecha"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Usar la pantalla dividida con la aplicación actual a la izquierda"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Cambiar de pantalla dividida a pantalla completa"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Cambiar a la app de la derecha o de abajo en pantalla dividida"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Cambiar a la app de la izquierda o de arriba en pantalla dividida"</string> diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml index bd90056382e6..5dbb2c132f4c 100644 --- a/packages/SystemUI/res/values-es/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Desactivado"</item>      <item msgid="5137565285664080143">"Activado"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"No disponibles"</item> +    <item msgid="3079622119444911877">"Desactivados"</item> +    <item msgid="3028994095749238254">"Activados"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 52cbb0f56b2c..190c002fb033 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Probleemi salvestamine"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Alusta"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Peata"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Millist seadme kasutuskogemuse osa see mõjutas?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Valige probleemi tüüp"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekraanisalvestus"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Tavaline"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Keskmine"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Kõrge"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Kuuldeseadmed"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Kuuldeseadmed"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uue seadme sidumine"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Uue seadme sidumiseks klõpsake"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kas tühistada seadme mikrofoni blokeerimine?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Kas tühistada seadme kaamera blokeerimine?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Kas tühistada seadme kaamera ja mikrofoni blokeerimine?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Klaviatuuripaigutuse vahetus"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"või"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Otsingupäringu tühjendamine"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Otseteed"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Klaviatuuri otseteed"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Otseteede otsing"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Otseteid ei leitud"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Süsteem"</string> @@ -769,10 +767,10 @@      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Seadete avamine"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistendi avamine"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Lukustuskuva"</string> -    <string name="group_system_quick_memo" msgid="3764560265935722903">"Kirjuta märkus"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Süsteemi multitegumtöö"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Ekraanikuva jagamine, nii et praegune rakendus on paremal"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Ekraanikuva jagamine, nii et praegune rakendus on vasakul"</string> +    <string name="group_system_quick_memo" msgid="3764560265935722903">"Märkme tegemine"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitegumtöö"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Jagatud ekraanikuva kasutamine, praegune rakendus kuvatakse paremal"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Jagatud ekraanikuva kasutamine, praegune rakendus kuvatakse vasakul"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Jagatud ekraanikuvalt täisekraanile lülitamine"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Paremale või alumisele rakendusele lülitamine jagatud ekraani ajal"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Vasakule või ülemisele rakendusele lülitamine jagatud ekraani ajal"</string> diff --git a/packages/SystemUI/res/values-et/tiles_states_strings.xml b/packages/SystemUI/res/values-et/tiles_states_strings.xml index 55bff30d3071..704649e77b86 100644 --- a/packages/SystemUI/res/values-et/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-et/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Väljas"</item>      <item msgid="5137565285664080143">"Sees"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Pole saadaval"</item> +    <item msgid="3079622119444911877">"Välja lülitatud"</item> +    <item msgid="3028994095749238254">"Sisse lülitatud"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index b0056f655ee1..b60df6f99b60 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -329,13 +329,13 @@      <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Laneko aplikazioak"</string>      <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"Pausatuta"</string>      <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Gaueko argia"</string> -    <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Ilunabarrean"</string> +    <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Ilunabarrean aktibatuta"</string>      <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Ilunabarrera arte"</string>      <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Aktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>      <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> arte"</string>      <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Gai iluna"</string>      <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Bateria-aurreztailea"</string> -    <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Ilunabarrean aktibatuko da"</string> +    <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Ilunabarrean aktibatuta"</string>      <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Egunsentira arte"</string>      <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Aktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string>      <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"Desaktibatze-ordua: <xliff:g id="TIME">%s</xliff:g>"</string> @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Arazo bat dago grabaketarekin"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Hasi"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Gelditu"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Gailuaren erabileraren zer alderdiri eragin dio?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Hautatu arazo mota"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Pantaila-grabaketa"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Arrunta"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Tartekoa"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Altua"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Entzumen-gailuak"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Entzumen-gailuak"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parekatu beste gailu bat"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Egin klik beste gailu bat parekatzeko"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Gailuaren mikrofonoa desblokeatu nahi duzu?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Gailuaren kamera desblokeatu nahi duzu?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Gailuaren kamera eta mikrofonoa desblokeatu nahi dituzu?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Aldatu tekl. diseinua"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"edo"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Garbitu bilaketa-kontsulta"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Lasterbideak"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Lasterbideak"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Bilatu lasterbideak"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Ez da aurkitu lasterbiderik"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistema"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Ireki Laguntzailea"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Blokeatu pantaila"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Egin ohar bat"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Zereginen aldibereko sistemaren exekuzioa"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Sartu pantaila zatituaren eskuineko aldean oraingo aplikazioarekin"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Sartu pantaila zatituaren ezkerreko aldean oraingo aplikazioarekin"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Zeregin bat baino gehiago aldi berean exekutatzea"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Erabili pantaila zatitua eta ezarri aplikazio hau eskuinean"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Erabili pantaila zatitua eta ezarri aplikazio hau ezkerrean"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Aldatu pantaila zatitutik pantaila osora"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Aldatu eskuineko edo beheko aplikaziora pantaila zatitua erabiltzean"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Aldatu ezkerreko edo goiko aplikaziora pantaila zatitua erabiltzean"</string> @@ -790,8 +788,8 @@      <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMSak"</string>      <string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musika"</string>      <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> -    <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Ireki Kalkulagailua"</string> -    <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Ireki Maps"</string> +    <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulagailua"</string> +    <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string>      <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ez molestatzeko modua"</string>      <string name="volume_dnd_silent" msgid="4154597281458298093">"Bolumen-botoietarako lasterbidea"</string>      <string name="battery" msgid="769686279459897127">"Bateria"</string> @@ -1125,7 +1123,7 @@      <string name="basic_status" msgid="2315371112182658176">"Elkarrizketa irekia"</string>      <string name="select_conversation_title" msgid="6716364118095089519">"Elkarrizketa-widgetak"</string>      <string name="select_conversation_text" msgid="3376048251434956013">"Sakatu elkarrizketa bat orri nagusian gehitzeko"</string> -    <string name="no_conversations_text" msgid="5354115541282395015">"Azken elkarrizketak agertuko dira hemen"</string> +    <string name="no_conversations_text" msgid="5354115541282395015">"Azkenaldiko elkarrizketak agertuko dira hemen"</string>      <string name="priority_conversations" msgid="3967482288896653039">"Lehentasunezko elkarrizketak"</string>      <string name="recent_conversations" msgid="8531874684782574622">"Azken elkarrizketak"</string>      <string name="days_timestamp" msgid="5821854736213214331">"Duela <xliff:g id="DURATION">%1$s</xliff:g> egun"</string> @@ -1151,7 +1149,7 @@      <string name="status_before_loading" msgid="1500477307859631381">"Laster agertuko da edukia"</string>      <string name="missed_call" msgid="4228016077700161689">"Dei galdua"</string>      <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string> -    <string name="people_tile_description" msgid="8154966188085545556">"Ikusi azken mezuak, dei galduak eta egoerari buruzko informazio eguneratua"</string> +    <string name="people_tile_description" msgid="8154966188085545556">"Ikusi azken mezuak, dei galduak eta egoerei buruzko informazio eguneratua"</string>      <string name="people_tile_title" msgid="6589377493334871272">"Elkarrizketa"</string>      <string name="paused_by_dnd" msgid="7856941866433556428">"Ez molestatzeko moduak pausatu du"</string>      <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak mezu bat bidali du: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-eu/tiles_states_strings.xml b/packages/SystemUI/res/values-eu/tiles_states_strings.xml index 7f38d4486600..13e14e0502c4 100644 --- a/packages/SystemUI/res/values-eu/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-eu/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Desaktibatuta"</item>      <item msgid="5137565285664080143">"Aktibatuta"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Ez daude erabilgarri"</item> +    <item msgid="3079622119444911877">"Desaktibatuta"</item> +    <item msgid="3028994095749238254">"Aktibatuta"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index de97db354f37..0c53fa01d903 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"ضبط مشکل"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"شروع"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"توقف"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"گزارش اشکال"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"کدام بخش تجربه استفاده از دستگاه تحتتأثیر قرار گرفت؟"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"انتخاب نوع مشکل"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ضبط صفحهنمایش"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"استاندارد"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"متوسط"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"بالا"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سمعک"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سمعک"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"جفت کردن دستگاه جدید"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"برای جفت کردن دستگاه جدید، کلیک کنید"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"میکروفون دستگاه لغو انسداد شود؟"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"دوربین دستگاه لغو انسداد شود؟"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"دوربین و میکروفون دستگاه لغو انسداد شود؟"</string> @@ -551,7 +548,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"این دستگاه را ولیتان مدیریت میکند. ولیتان میتواند اطلاعاتی مثل برنامههایی که استفاده میکنید، مکانتان، و مدت تماشای صفحهتان را ببیند و مدیریت کند."</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"با TrustAgent قفل را باز نگهدارید"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"دستگاه قفل شد، تعداد تلاشها برای اصالتسنجی بسیار زیاد بود"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"بهدلیل تلاشهای بیشاز حد برای اصالتسنجی، دستگاه قفل شد"</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"دستگاه قفل شد\nاصالتسنجی ناموفق بود"</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="accessibility_volume_settings" msgid="1458961116951564784">"تنظیمات صدا"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"تغییر جانمایی صفحهکلید"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"یا"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"پاک کردن پُرسمان جستجو"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"میانبرها"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"میانبرهای صفحهکلید"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"جستجوی میانبرها"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"میانبری پیدا نشد"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"سیستم"</string> @@ -770,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"باز کردن «دستیار»"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"قفل صفحه"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"یادداشتبرداری"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"چندوظیفگی سیستم"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"وارد شدن به صفحهٔ دونیمه با برنامه فعلی در سمت راست"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"وارد شدن به صفحهٔ دونیمه با برنامه فعلی در سمت چپ"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"چندوظیفگی"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"استفاده از صفحهٔ دونیمه با برنامه فعلی در سمت راست"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"استفاده از صفحهٔ دونیمه با برنامه فعلی در سمت چپ"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"جابهجایی از صفحهٔ دونیمه به تمام صفحه"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"رفتن به برنامه سمت راست یا پایین درحین استفاده از صفحهٔ دونیمه"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"رفتن به برنامه سمت چپ یا بالا درحین استفاده از صفحهٔ دونیمه"</string> diff --git a/packages/SystemUI/res/values-fa/tiles_states_strings.xml b/packages/SystemUI/res/values-fa/tiles_states_strings.xml index 9a6b1af3ad6b..756b442f5fc4 100644 --- a/packages/SystemUI/res/values-fa/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-fa/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"خاموش"</item>      <item msgid="5137565285664080143">"روشن"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"دردسترس نیست"</item> +    <item msgid="3079622119444911877">"خاموش"</item> +    <item msgid="3028994095749238254">"روشن"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 55413a01695e..3c90847483cc 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -120,7 +120,7 @@      <string name="screenrecord_stop_label" msgid="72699670052087989">"Lopeta"</string>      <string name="screenrecord_share_label" msgid="5025590804030086930">"Jaa"</string>      <string name="screenrecord_save_title" msgid="1886652605520893850">"Näyttötallenne tallennettu"</string> -    <string name="screenrecord_save_text" msgid="3008973099800840163">"Napauta näyttääksesi"</string> +    <string name="screenrecord_save_text" msgid="3008973099800840163">"Katso napauttamalla"</string>      <string name="screenrecord_save_error" msgid="5862648532560118815">"Virhe näyttötallenteen tallentamisessa"</string>      <string name="screenrecord_start_error" msgid="2200660692479682368">"Virhe näytön tallennuksen aloituksessa"</string>      <string name="issuerecord_title" msgid="286627115110121849">"Ongelman tallentaja"</string> @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Tallenna ongelma"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Aloita"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Lopeta"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Mitä osaa käyttökokemuksesta ongelma koski?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Valitse ongelman tyyppi"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Näytön tallentaja"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Tavallinen"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Keskitaso"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Suuri"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Kuulolaitteet"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Kuulolaitteet"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Muodosta uusi laitepari"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Muodosta uusi laitepari klikkaamalla"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kumotaanko laitteen mikrofonin esto?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Kumotaanko laitteen kameran esto?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Kumotaanko laitteen kameran ja mikrofonin esto?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Vaihda näppäimistöasettelu"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"tai"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Tyhjennä hakulauseke"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Pikanäppäimet"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Pikanäppäimet"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Hae pikanäppäimiä"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Pikanäppäimiä ei löytynyt"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Järjestelmä"</string> @@ -770,17 +768,17 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Avaa Assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Lukitusnäyttö"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Tee muistiinpano"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Järjestelmän monikäyttö"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Siirry jaettuun näyttöön (sovellus oikeanpuoleiseen näyttöön)"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Siirry jaettuun näyttöön (sovellus vasemmanpuoleiseen näyttöön)"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitaskaus"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Käytä jaettua näyttöä niin, että nyt käytettävä sovellus on oikealla"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Käytä jaettua näyttöä niin, että nyt käytettävä sovellus on vasemmalla"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Vaihda jaetusta näytöstä koko näyttöön"</string> -    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Vaihda sovellukseen oikealla tai alapuolella jaetun näytön avulla"</string> -    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Vaihda sovellukseen vasemmalla tai yläpuolella jaetun näytön avulla"</string> +    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Vaihda sovellukseen oikealla tai alapuolella jaetussa näytössä"</string> +    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Vaihda sovellukseen vasemmalla tai yläpuolella jaetussa näytössä"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"Jaetun näytön aikana: korvaa sovellus toisella"</string>      <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Syöttötapa"</string>      <string name="input_switch_input_language_next" msgid="3782155659868227855">"Vaihda seuraavaan kieleen"</string>      <string name="input_switch_input_language_previous" msgid="6043341362202336623">"Vaihda aiempaan kieleen"</string> -    <string name="input_access_emoji" msgid="8105642858900406351">"Emojin käyttö"</string> +    <string name="input_access_emoji" msgid="8105642858900406351">"Emojien käyttö"</string>      <string name="input_access_voice_typing" msgid="7291201476395326141">"Puhekirjoituksen käyttö"</string>      <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Sovellukset"</string>      <string name="keyboard_shortcut_group_applications_assist" msgid="6772492350416591448">"Assistant"</string> @@ -1194,7 +1192,7 @@      <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# sovellus on aktiivinen}other{# sovellusta aktiivisena}}"</string>      <string name="fgs_dot_content_description" msgid="2865071539464777240">"Uutta tietoa"</string>      <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktiiviset sovellukset"</string> -    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Nämä sovellukset ovat aktiivisia ja ne ovat käynnissä, vaikka et käyttäisi niitä. Näin sovellusten toimivuus paranee, mutta se voi vaikutta akunkestoon."</string> +    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Nämä sovellukset ovat aktiivisia ja käynnissä, vaikka et käyttäisi niitä. Näin sovellusten toimivuus paranee, mutta ne voivat vaikuttaa akunkestoon."</string>      <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Pysäytä"</string>      <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Pysäytetty"</string>      <string name="clipboard_edit_text_done" msgid="4551887727694022409">"Valmis"</string> @@ -1269,7 +1267,7 @@      <string name="install_dialer_on_work_profile_action" msgid="2014659711597862506">"Asenna työpuhelinsovellus"</string>      <string name="call_from_work_profile_close" msgid="5830072964434474143">"Peruuta"</string>      <string name="lock_screen_settings" msgid="6152703934761402399">"Muokkaa lukitusnäyttöä"</string> -    <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Avaa lukitus muokataksesi lukitusnäyttöä"</string> +    <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Voit muokata lukitusnäyttöä, kun avaat lukituksen"</string>      <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi-yhteys ei ole käytettävissä"</string>      <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera estetty"</string>      <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera ja mikrofoni estetty"</string> diff --git a/packages/SystemUI/res/values-fi/tiles_states_strings.xml b/packages/SystemUI/res/values-fi/tiles_states_strings.xml index f1e3e614cb70..5ecc95956d1c 100644 --- a/packages/SystemUI/res/values-fi/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-fi/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Pois päältä"</item>      <item msgid="5137565285664080143">"Päällä"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Ei saatavilla"</item> +    <item msgid="3079622119444911877">"Pois päältä"</item> +    <item msgid="3028994095749238254">"Päällä"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-fr-feminine/strings.xml b/packages/SystemUI/res/values-fr-feminine/strings.xml index ebdc3fb236aa..16c16e149b9e 100644 --- a/packages/SystemUI/res/values-fr-feminine/strings.xml +++ b/packages/SystemUI/res/values-fr-feminine/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="zen_priority_introduction" msgid="3159291973383796646">"Vous ne serez pas dérangée par des sons ou des vibrations, hormis ceux des alarmes, des rappels, des événements et des appelants de votre choix. Vous entendrez encore les sons que vous choisirez de jouer, notamment la musique, les vidéos et les jeux."</string> -    <string name="zen_alarms_introduction" msgid="3987266042682300470">"Vous ne serez pas dérangée par des sons ou des vibrations, hormis ceux des alarmes. Vous entendrez encore les sons que vous choisirez de jouer, notamment la musique, les vidéos et les jeux."</string> +    <string name="zen_alarms_introduction" msgid="3987266042682300470">"Vous ne serez pas dérangée par des sons ou des vibrations, hormis ceux des alarmes. Vous entendrez encore les sons que vous choisirez de jouer, comme la musique, les vidéos et les jeux."</string>      <string name="guest_wipe_session_title" msgid="7147965814683990944">"Heureux de vous revoir, Invitée"</string>  </resources> diff --git a/packages/SystemUI/res/values-fr-masculine/strings.xml b/packages/SystemUI/res/values-fr-masculine/strings.xml index 6b9497061c56..411af1fecda2 100644 --- a/packages/SystemUI/res/values-fr-masculine/strings.xml +++ b/packages/SystemUI/res/values-fr-masculine/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="zen_priority_introduction" msgid="3159291973383796646">"Vous ne serez pas dérangé par des sons ou des vibrations, hormis ceux des alarmes, des rappels, des événements et des appelants de votre choix. Vous entendrez encore les sons que vous choisirez de jouer, notamment la musique, les vidéos et les jeux."</string> -    <string name="zen_alarms_introduction" msgid="3987266042682300470">"Vous ne serez pas dérangé par des sons ou des vibrations, hormis ceux des alarmes. Vous entendrez encore les sons que vous choisirez de jouer, notamment la musique, les vidéos et les jeux."</string> +    <string name="zen_alarms_introduction" msgid="3987266042682300470">"Vous ne serez pas dérangé par des sons ou des vibrations, hormis ceux des alarmes. Vous entendrez encore les sons que vous choisirez de jouer, comme la musique, les vidéos et les jeux."</string>      <string name="guest_wipe_session_title" msgid="7147965814683990944">"Heureux de vous revoir, Invité"</string>  </resources> diff --git a/packages/SystemUI/res/values-fr-neuter/strings.xml b/packages/SystemUI/res/values-fr-neuter/strings.xml index e9d01914a638..4a4ac5a61eeb 100644 --- a/packages/SystemUI/res/values-fr-neuter/strings.xml +++ b/packages/SystemUI/res/values-fr-neuter/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="zen_priority_introduction" msgid="3159291973383796646">"Vous ne serez pas dérangé·e par des sons ou des vibrations, hormis ceux des alarmes, des rappels, des événements et des appelants de votre choix. Vous entendrez encore les sons que vous choisirez de jouer, notamment la musique, les vidéos et les jeux."</string> -    <string name="zen_alarms_introduction" msgid="3987266042682300470">"Vous ne serez pas dérangé·e par des sons ou des vibrations, hormis ceux des alarmes. Vous entendrez encore les sons que vous choisirez de jouer, notamment la musique, les vidéos et les jeux."</string> +    <string name="zen_alarms_introduction" msgid="3987266042682300470">"Vous ne serez pas dérangé·e par des sons ou des vibrations, hormis ceux des alarmes. Vous entendrez encore les sons que vous choisirez de jouer, comme la musique, les vidéos et les jeux."</string>      <string name="guest_wipe_session_title" msgid="7147965814683990944">"Heureux de vous revoir, Invité·e"</string>  </resources> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 272e00e5c7b3..cb56ba93b2bd 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Rapporter le problème"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Commencer"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Arrêter"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quelle composante de l\'appareil a été affectée?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sélectionner un type"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Enregistrement écran"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Moyen"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Élevé"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Appareils auditifs"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Appareils auditifs"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Associer un nouvel appareil"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquez ici pour associer un nouvel appareil"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le microphone de l\'appareil?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Débloquer l\'appareil photo de l\'appareil?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Débloquer l\'appareil photo et le microphone?"</string> @@ -448,10 +446,8 @@      <string name="button_to_remove_widget" msgid="3948204829181214098">"Retirer"</string>      <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string>      <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Terminé"</string> -    <!-- no translation found for label_for_button_in_empty_state_cta (7314975555382055823) --> -    <skip /> -    <!-- no translation found for title_for_empty_state_cta (6161654421223450530) --> -    <skip /> +    <string name="label_for_button_in_empty_state_cta" msgid="7314975555382055823">"Ajouter des widgets"</string> +    <string name="title_for_empty_state_cta" msgid="6161654421223450530">"Accédez rapidement aux widgets de vos applications préférées sans déverrouiller votre tablette."</string>      <string name="dialog_title_to_allow_any_widget" msgid="1004820948962675644">"Autoriser n\'importe quel widget sur l\'écran de verrouillage?"</string>      <string name="button_text_to_open_settings" msgid="1987729256950941628">"Ouvrir les paramètres"</string>      <string name="work_mode_off_title" msgid="5794818421357835873">"Réactiver les applis pros?"</string> @@ -553,7 +549,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Cet appareil est géré par ton parent. Ton parent peut voir et gérer de l\'information, comme les applications que tu utilises, ta position et ton temps d\'utilisation des écrans."</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"RPV"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Maintenu déverrouillé par TrustAgent"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"L\'appareil a été verrouillé, trop de tentatives d\'authentification"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"L\'appareil a été verrouillé : trop de tentatives d\'authentification"</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Appareil verrouillé\nÉchec de l\'authentification"</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="accessibility_volume_settings" msgid="1458961116951564784">"Paramètres sonores"</string> @@ -747,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Changer la disposition du clavier"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Effacez la requête de recherche"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Raccourcis"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Raccourcis-clavier"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Recherchez des raccourcis"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Aucun raccourci trouvé"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Système"</string> @@ -772,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Ouvrir l\'Assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Écran de verrouillage"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Prendre une note"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitâche du système"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Passer à l\'écran divisé avec l\'application actuelle à droite"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Passer à l\'écran divisé avec l\'application actuelle à gauche"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitâche"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Utiliser l\'Écran divisé avec l\'application actuelle à droite"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Utiliser l\'Écran divisé avec l\'application actuelle à gauche"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Passer de l\'écran divisé au plein écran"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passer à l\'application à droite ou en dessous avec l\'Écran divisé"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passer à l\'application à gauche ou au-dessus avec l\'Écran divisé"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml index dfea45ac8d84..52b763b4028d 100644 --- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Désactivée"</item>      <item msgid="5137565285664080143">"Activée"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Non accessible"</item> +    <item msgid="3079622119444911877">"Désactivé"</item> +    <item msgid="3028994095749238254">"Activé"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 41f9249c0fbc..15235dee3724 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -286,7 +286,7 @@      <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>      <string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>      <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Économiseur d\'écran"</string> -    <string name="quick_settings_camera_label" msgid="5612076679385269339">"Accès à la caméra"</string> +    <string name="quick_settings_camera_label" msgid="5612076679385269339">"Accès à l\'appareil photo"</string>      <string name="quick_settings_mic_label" msgid="8392773746295266375">"Accès au micro"</string>      <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>      <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqué"</string> @@ -298,7 +298,7 @@      <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Réseaux non disponibles"</string>      <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Aucun réseau Wi-Fi disponible"</string>      <string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Activation…"</string> -    <string name="quick_settings_cast_title" msgid="2279220930629235211">"Diffusion de l\'écran"</string> +    <string name="quick_settings_cast_title" msgid="2279220930629235211">"Diffusion écran"</string>      <string name="quick_settings_casting" msgid="1435880708719268055">"Diffusion"</string>      <string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Appareil sans nom"</string>      <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Aucun appareil disponible."</string> @@ -344,12 +344,14 @@      <string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>      <string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>      <string name="quick_settings_nfc_on" msgid="1004976611203202230">"La technologie NFC est activée"</string> -    <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Enregistrement de l\'écran"</string> +    <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Enregistr. écran"</string>      <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string>      <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string>      <string name="qs_record_issue_label" msgid="8166290137285529059">"Enregistrer le problème"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Début"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Arrêter"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quel problème avez-vous rencontré avec votre appareil ?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sélectionnez un type de problème"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Enregistrement de l\'écran"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Moyen"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Élevé"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Prothèses auditives"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Appareils auditifs"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Associer un nouvel appareil"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquer pour associer un nouvel appareil"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le micro de l\'appareil ?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Débloquer la caméra de l\'appareil ?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Débloquer l\'appareil photo et le micro de l\'appareil ?"</string> @@ -400,7 +398,7 @@      <string name="media_seamless_other_device" msgid="4654849800789196737">"Autre appareil"</string>      <string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activer/Désactiver l\'écran Récents"</string>      <string name="zen_priority_introduction" msgid="3159291973383796646">"Vous ne serez pas dérangé par des sons ou des vibrations, hormis ceux des alarmes, des rappels, des événements et des appelants de votre choix. Vous entendrez encore les sons que vous choisirez de jouer, notamment la musique, les vidéos et les jeux."</string> -    <string name="zen_alarms_introduction" msgid="3987266042682300470">"Vous ne serez pas dérangé par des sons ou des vibrations, hormis ceux des alarmes. Vous entendrez encore les sons que vous choisirez de jouer, notamment la musique, les vidéos et les jeux."</string> +    <string name="zen_alarms_introduction" msgid="3987266042682300470">"Vous ne serez pas dérangé par des sons ou des vibrations, hormis ceux des alarmes. Vous entendrez encore les sons que vous choisirez de jouer, comme la musique, les vidéos et les jeux."</string>      <string name="zen_priority_customize_button" msgid="4119213187257195047">"Personnaliser"</string>      <string name="zen_silence_introduction_voice" msgid="853573681302712348">"Cette option permet de bloquer TOUS les sons et les vibrations, y compris pour les alarmes, la musique, les vidéos et les jeux. Vous pourrez encore passer des appels téléphoniques."</string>      <string name="zen_silence_introduction" msgid="6117517737057344014">"Cette option permet de bloquer TOUS les sons et les vibrations, y compris pour les alarmes, la musique, les vidéos et les jeux."</string> @@ -637,7 +635,7 @@      <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Déverrouiller pour utiliser"</string>      <string name="wallet_error_generic" msgid="257704570182963611">"Problème de récupération de vos cartes. Réessayez plus tard"</string>      <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Paramètres de l\'écran de verrouillage"</string> -    <string name="qr_code_scanner_title" msgid="1938155688725760702">"Lecteur de code QR"</string> +    <string name="qr_code_scanner_title" msgid="1938155688725760702">"Lecteur code QR"</string>      <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Mise à jour"</string>      <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string>      <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string> @@ -745,8 +743,8 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Changer disposition du clavier"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Effacer la requête de recherche"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Raccourcis"</string> -    <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Raccourcis de recherche"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Raccourcis clavier"</string> +    <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Rechercher des raccourcis"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Aucun raccourci trouvé"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Système"</string>      <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"Saisie"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Ouvrir l\'Assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Verrouiller l\'écran"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Créer une note"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitâche du système"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Passer en écran partagé avec l\'appli actuelle affichée à droite"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Passer en écran partagé avec l\'appli actuelle affichée à gauche"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitâche"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Utiliser l\'écran partagé avec l\'appli actuelle sur la droite"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Utiliser l\'écran partagé avec l\'appli actuelle sur la gauche"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Passer de l\'écran partagé au plein écran"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passez à l\'appli à droite ou en dessous avec l\'écran partagé"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passez à l\'appli à gauche ou au-dessus avec l\'écran partagé"</string> @@ -1247,7 +1245,7 @@      <string name="home_quick_affordance_unavailable_configure_the_app" msgid="604424593994493281">"• Au moins un appareil ou un panneau de l\'appareil est disponible"</string>      <string name="notes_app_quick_affordance_unavailable_explanation" msgid="4796955161600178530">"Sélectionnez une appli de notes par défaut pour utiliser le raccourci de prise de notes"</string>      <string name="keyguard_affordance_enablement_dialog_notes_app_action" msgid="6821710209675089470">"Sélectionner une appli"</string> -    <string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Appuyez de manière prolongée sur raccourci"</string> +    <string name="keyguard_affordance_press_too_short" msgid="8145437175134998864">"Appuyez de manière prolongée sur le raccourci"</string>      <string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Annuler"</string>      <string name="rear_display_bottom_sheet_confirm" msgid="1507591562761552899">"Changer d\'écran maintenant"</string>      <string name="rear_display_folded_bottom_sheet_title" msgid="3930008746560711990">"Déplier le téléphone"</string> @@ -1269,7 +1267,7 @@      <string name="install_dialer_on_work_profile_action" msgid="2014659711597862506">"Installer une appli professionnelle pour téléphoner"</string>      <string name="call_from_work_profile_close" msgid="5830072964434474143">"Annuler"</string>      <string name="lock_screen_settings" msgid="6152703934761402399">"Personnaliser écran verrouillage"</string> -    <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Déverrouiller pour personnaliser l\'écran de verrouillage"</string> +    <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Déverrouillez pour personnaliser l\'écran de verrouillage"</string>      <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi non disponible"</string>      <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Caméra bloquée"</string>      <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Caméra et micro bloqués"</string> @@ -1284,7 +1282,7 @@      <string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string>      <string name="dismiss_dialog" msgid="2195508495854675882">"Fermer"</string>      <string name="connected_display_icon_desc" msgid="6373560639989971997">"Écran connecté"</string> -    <string name="privacy_dialog_title" msgid="7839968133469098311">"Micro et caméra"</string> +    <string name="privacy_dialog_title" msgid="7839968133469098311">"Micro et appareil photo"</string>      <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilisation récente par les applis"</string>      <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Consulter les accès récents"</string>      <string name="privacy_dialog_done_button" msgid="4504330708531434263">"OK"</string> diff --git a/packages/SystemUI/res/values-fr/tiles_states_strings.xml b/packages/SystemUI/res/values-fr/tiles_states_strings.xml index 34ccb7517615..23c124cce37a 100644 --- a/packages/SystemUI/res/values-fr/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-fr/tiles_states_strings.xml @@ -88,8 +88,8 @@    </string-array>    <string-array name="tile_states_color_correction">      <item msgid="2840507878437297682">"Indisponible"</item> -    <item msgid="1909756493418256167">"Désactivé"</item> -    <item msgid="4531508423703413340">"Activé"</item> +    <item msgid="1909756493418256167">"Désactivée"</item> +    <item msgid="4531508423703413340">"Activée"</item>    </string-array>    <string-array name="tile_states_inversion">      <item msgid="3638187931191394628">"Indisponible"</item> @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Désactivé"</item>      <item msgid="5137565285664080143">"Activé"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Non disponible"</item> +    <item msgid="3079622119444911877">"Désactivé"</item> +    <item msgid="3028994095749238254">"Activé"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 189f048a5c17..7f4ae81e6f6e 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Rexistrar problema"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Deter"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cal foi o problema na experiencia co dispositivo?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona o tipo de problema"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravación de pant."</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Nivel estándar"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Nivel medio"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Nivel alto"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular un dispositivo novo"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic para vincular un novo dispositivo"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Queres desbloquear o micrófono do dispositivo?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Queres desbloquear a cámara do dispositivo?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Queres desbloquear a cámara e o micrófono do dispositivo?"</string> @@ -632,7 +630,7 @@      <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>      <string name="wallet_empty_state_label" msgid="7776761245237530394">"Configura un método de pago para comprar de xeito máis rápido e seguro co teléfono"</string>      <string name="wallet_app_button_label" msgid="7123784239111190992">"Amosar todo"</string> -    <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tocar para abrir"</string> +    <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Toca para abrir"</string>      <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Actualizando"</string>      <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>      <string name="wallet_error_generic" msgid="257704570182963611">"Produciuse un problema ao obter as tarxetas. Téntao de novo máis tarde"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Cambiar deseño do teclado"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Borrar a busca"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Atallos"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Atallos de teclado"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Buscar atallos"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Non se atoparon atallos"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistema"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir Asistente"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Pantalla de bloqueo"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Crear nota"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitarefa do sistema"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Activar pantalla dividida con esta aplicación no lado dereito"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Activar pantalla dividida con esta aplicación no lado esquerdo"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitarefa"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Usar pantalla dividida coa aplicación actual na dereita"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Usar pantalla dividida coa aplicación actual na esquerda"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Cambiar de pantalla dividida a pantalla completa"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Cambiar á aplicación da dereita ou de abaixo coa pantalla dividida"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Cambiar á aplicación da esquerda ou de arriba coa pantalla dividida"</string> diff --git a/packages/SystemUI/res/values-gl/tiles_states_strings.xml b/packages/SystemUI/res/values-gl/tiles_states_strings.xml index de8ee63907aa..03b934eb9cb6 100644 --- a/packages/SystemUI/res/values-gl/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-gl/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Desactivado"</item>      <item msgid="5137565285664080143">"Activado"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Non dispoñibles"</item> +    <item msgid="3079622119444911877">"Desactivados"</item> +    <item msgid="3028994095749238254">"Activados"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 54312e159c62..9425774f47c3 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -333,7 +333,7 @@      <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"સૂર્યોદય સુધી"</string>      <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g> વાગ્યે"</string>      <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> સુધી"</string> -    <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"ઘેરી થીમ"</string> +    <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"ડાર્ક થીમ"</string>      <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"બૅટરી સેવર"</string>      <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"સૂર્યાસ્ત વખતે"</string>      <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"સૂર્યોદય સુધી"</string> @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"રેકોર્ડિંગમાં સમસ્યા"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"શરૂ કરો"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"રોકો"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"બગ રિપોર્ટ"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ડિવાઇસ સંબંધી તમારા અનુભવના કયા ભાગને અસર થઈ હતી?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"સમસ્યાનો પ્રકાર પસંદ કરો"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"સ્ક્રીન રેકોર્ડ કરો"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"સ્ટૅન્ડર્ડ"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"મધ્યમ"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"વધુ"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"સાંભળવામાં મદદ આપતા ડિવાઇસ"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"સાંભળવામાં મદદ આપતા ડિવાઇસ"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"નવા ડિવાઇસ સાથે જોડાણ કરવા માટે ક્લિક કરો"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ડિવાઇસના માઇક્રોફોનને અનબ્લૉક કરીએ?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ડિવાઇસના કૅમેરાને અનબ્લૉક કરીએ?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ડિવાઇસના કૅમેરા અને માઇક્રોફોનને અનબ્લૉક કરીએ?"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"કીબોર્ડ લેઆઉટ સ્વિચ કરો"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"અથવા"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"શોધ ક્વેરી સાફ કરો"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"શૉર્ટકટ"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"કીબોર્ડ શૉર્ટકટ"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"શૉર્ટકટ શોધો"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"કોઈ શૉર્ટકટ મળ્યો નથી"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"સિસ્ટમ"</string> @@ -770,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant ખોલો"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"લૉક સ્ક્રીન"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"નોંધ લો"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"સિસ્ટમ દ્વારા એકથી વધુ કાર્યો કરવા"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"જમણી બાજુ પર હાલની ઍપ સાથે વિભાજિત સ્ક્રીનમાં દાખલ થાઓ"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"ડાબી બાજુ પર હાલની ઍપ સાથે વિભાજિત સ્ક્રીનમાં દાખલ થાઓ"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"એકસાથે એકથી વધુ કાર્યો કરવા"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"જમણી બાજુએ વર્તમાન ઍપ સાથે વિભાજિત સ્ક્રીનનો ઉપયોગ કરો"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"ડાબી બાજુએ વર્તમાન ઍપ સાથે વિભાજિત સ્ક્રીનનો ઉપયોગ કરો"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"વિભાજિત સ્ક્રીનથી પૂર્ણ સ્ક્રીન પર સ્વિચ કરો"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"વિભાજિત સ્ક્રીનનો ઉપયોગ કરતી વખતે જમણી બાજુ કે નીચેની ઍપ પર સ્વિચ કરો"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"વિભાજિત સ્ક્રીનનો ઉપયોગ કરતી વખતે ડાબી બાજુની કે ઉપરની ઍપ પર સ્વિચ કરો"</string> diff --git a/packages/SystemUI/res/values-gu/tiles_states_strings.xml b/packages/SystemUI/res/values-gu/tiles_states_strings.xml index c6a86e550f7a..5c4a4784c13f 100644 --- a/packages/SystemUI/res/values-gu/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-gu/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"બંધ"</item>      <item msgid="5137565285664080143">"ચાલુ"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"અનુપલબ્ધ"</item> +    <item msgid="3079622119444911877">"બંધ છે"</item> +    <item msgid="3028994095749238254">"ચાલુ છે"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index ee3e40b7f6ac..e4291aca6c8a 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"समस्या रिकॉर्ड करें"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"शुरू करें"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"रोकें"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"गड़बड़ी की रिपोर्ट"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"आपके डिवाइस की कौनसी सुविधा पर असर पड़ा था?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्या का टाइप चुनें"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रीन रिकॉर्डर"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"स्टैंडर्ड"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"सामान्य"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"ज़्यादा"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"कान की मशीनें"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"कान की मशीनें"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नया डिवाइस जोड़ें"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नया डिवाइस जोड़ने के लिए क्लिक करें"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"क्या आपको डिवाइस का माइक्रोफ़ोन अनब्लॉक करना है?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"क्या आपको डिवाइस का कैमरा अनब्लॉक करना है?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"क्या आप डिवाइस का कैमरा और माइक्रोफ़ोन अनब्लॉक करना चाहते हैं?"</string> @@ -552,7 +549,7 @@      <string name="legacy_vpn_name" msgid="4174223520162559145">"वीपीएन"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent की वजह से अनलॉक रखा गया है"</string>      <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"कई बार पुष्टि करने की कोशिश की वजह से, डिवाइस लॉक है"</string> -    <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"डिवाइस लॉक है\nपुष्टि नहीं की जा सकी."</string> +    <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"डिवाइस लॉक हो गया है\nपुष्टि नहीं की जा सकी"</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="accessibility_volume_settings" msgid="1458961116951564784">"साउंड सेटिंग"</string>      <string name="volume_odi_captions_tip" msgid="8825655463280990941">"ऑडियो-वीडियो से अपने-आप कैप्शन बनना"</string> @@ -678,7 +675,7 @@      <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>स्थिति:</b> रैंकिंग में नीचे किया गया"</string>      <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"यह कई तरीकों से दिखती है, जैसे कि लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो के तौर पर और बातचीत वाली सूचनाओं में सबसे ऊपर"</string>      <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"यह कई तरीकों से दिखती है, जैसे कि बातचीत वाली सूचनाओं में सबसे ऊपर, बबल के तौर पर, और लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो के तौर पर"</string> -    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"यह कई तरीकों से दिखती है, जैसे कि लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो के तौर पर और बातचीत वाली सूचनाओं में सबसे ऊपर. साथ ही, इसकी वजह से, \'परेशान न करें\' सुविधा में भी रुकावट आती है"</string> +    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"यह लॉक स्क्रीन पर, बातचीत वाली सूचनाओं में सबसे ऊपर और प्रोफ़ाइल फ़ोटो के साथ दिखती है. साथ ही, यह \'परेशान न करें\' मोड को बायपास कर सकती है."</string>      <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"यह कई तरीकों से दिखती है, जैसे कि बातचीत वाली सूचनाओं में सबसे ऊपर, बबल के तौर पर, और लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो के तौर पर. साथ ही, यह \'परेशान न करें\' मोड को बायपास कर सकती है"</string>      <string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>      <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर बातचीत की सुविधाएं काम नहीं करतीं"</string> @@ -745,12 +742,12 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"कीबोर्ड लेआउट बदलें"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"या"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"सर्च क्वेरी साफ़ करें"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"शॉर्टकट"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"कीबोर्ड शॉर्टकट"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"शॉर्टकट खोजें"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"कोई शॉर्टकट नहीं मिला"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"सिस्टम"</string>      <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"इनपुट"</string> -    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"खुले हुए ऐप्लिकेशन"</string> +    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"ऐप्लिकेशन खोलने के लिए"</string>      <string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"मौजूदा ऐप्लिकेशन"</string>      <string name="keyboard_shortcut_a11y_show_search_results" msgid="2865241062981833705">"खोज के नतीजे दिखाए जा रहे हैं"</string>      <string name="keyboard_shortcut_a11y_filter_system" msgid="7744143131119370483">"सिस्टम के शॉर्टकट दिखाए जा रहे हैं"</string> @@ -759,8 +756,8 @@      <string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"मौजूदा ऐप्लिकेशन के लिए शॉर्टकट दिखाए जा रहे हैं"</string>      <string name="group_system_access_notification_shade" msgid="1619028907006553677">"सूचनाएं देखने के लिए"</string>      <string name="group_system_full_screenshot" msgid="5742204844232667785">"स्क्रीनशॉट लेने के लिए"</string> -    <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"शॉर्टकट दिखाने के लिए"</string> -    <string name="group_system_go_back" msgid="2730322046244918816">"वापस पीछे जाने के लिए"</string> +    <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"शॉर्टकट देखने के लिए"</string> +    <string name="group_system_go_back" msgid="2730322046244918816">"वापस जाने के लिए"</string>      <string name="group_system_access_home_screen" msgid="4130366993484706483">"होम स्क्रीन पर जाने के लिए"</string>      <string name="group_system_overview_open_apps" msgid="5659958952937994104">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखने के लिए"</string>      <string name="group_system_cycle_forward" msgid="5478663965957647805">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन के अगले पेज पर जाने के लिए"</string> @@ -768,11 +765,11 @@      <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ऐप्लिकेशन की सूची खोलने के लिए"</string>      <string name="group_system_access_system_settings" msgid="8731721963449070017">"सेटिंग खोलने के लिए"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Google Assistant खोलने के लिए"</string> -    <string name="group_system_lock_screen" msgid="7391191300363416543">"लॉक स्क्रीन"</string> -    <string name="group_system_quick_memo" msgid="3764560265935722903">"नोट करें"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"सिस्टम मल्टीटास्किंग"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"स्प्लिट स्क्रीन का इस्तेमाल करके, मौजूदा ऐप्लिकेशन को दाईं ओर ले जाएं"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"स्प्लिट स्क्रीन का इस्तेमाल करके, मौजूदा ऐप्लिकेशन को बाईं ओर ले जाएं"</string> +    <string name="group_system_lock_screen" msgid="7391191300363416543">"स्क्रीन लॉक करने के लिए"</string> +    <string name="group_system_quick_memo" msgid="3764560265935722903">"नोट करने के लिए"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"मल्टीटास्किंग (एक साथ कई काम करना)"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"मौजूदा ऐप्लिकेशन को दाईं ओर दिखाने वाली स्प्लिट स्क्रीन इस्तेमाल करें"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"मौजूदा ऐप्लिकेशन को बाईं ओर दिखाने वाली स्प्लिट स्क्रीन इस्तेमाल करें"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"स्प्लिट स्क्रीन से फ़ुल स्क्रीन मोड पर स्विच करने के लिए"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रीन इस्तेमाल करते समय दाईं ओर या नीचे के ऐप पर स्विच करें"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रीन इस्तेमाल करते समय बाईं ओर या ऊपर के ऐप पर स्विच करें"</string> @@ -829,7 +826,7 @@      <string name="right_keycode" msgid="2480715509844798438">"दायां कुंजी कोड"</string>      <string name="left_icon" msgid="5036278531966897006">"बायां आइकॉन"</string>      <string name="right_icon" msgid="1103955040645237425">"दायां आइकॉन"</string> -    <string name="drag_to_add_tiles" msgid="8933270127508303672">"टाइल जोड़ने के लिए दबाएं और खींचें"</string> +    <string name="drag_to_add_tiles" msgid="8933270127508303672">"टाइल जोड़ने के लिए दबाकर खींचे और छोड़ें"</string>      <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"टाइल का क्रम फिर से बदलने के लिए उन्हें दबाकर रखें और खींचें"</string>      <string name="drag_to_remove_tiles" msgid="4682194717573850385">"हटाने के लिए यहां खींचें और छोड़ें"</string>      <string name="drag_to_remove_disabled" msgid="933046987838658850">"आपके पास कम से कम <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> टाइलें होनी चाहिए"</string> @@ -1123,7 +1120,7 @@      <string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>      <string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर को क्लिपबोर्ड पर कॉपी किया गया."</string>      <string name="basic_status" msgid="2315371112182658176">"ऐसी बातचीत जिसमें इंटरैक्शन डेटा मौजूद नहीं है"</string> -    <string name="select_conversation_title" msgid="6716364118095089519">"बातचीत विजेट"</string> +    <string name="select_conversation_title" msgid="6716364118095089519">"बातचीत वाला विजेट"</string>      <string name="select_conversation_text" msgid="3376048251434956013">"किसी बातचीत को होम स्क्रीन पर जोड़ने के लिए, उस बातचीत पर टैप करें"</string>      <string name="no_conversations_text" msgid="5354115541282395015">"हाल ही में हुई बातचीत यहां दिखेंगी"</string>      <string name="priority_conversations" msgid="3967482288896653039">"अहम बातचीत"</string> @@ -1286,7 +1283,7 @@      <string name="connected_display_icon_desc" msgid="6373560639989971997">"डिसप्ले कनेक्ट किया गया"</string>      <string name="privacy_dialog_title" msgid="7839968133469098311">"माइक्रोफ़ोन और कैमरा"</string>      <string name="privacy_dialog_summary" msgid="2458769652125995409">"हाल ही में इस्तेमाल करने वाला ऐप्लिकेशन"</string> -    <string name="privacy_dialog_more_button" msgid="7610604080293562345">"हाल में ऐक्सेस करने वाले ऐप"</string> +    <string name="privacy_dialog_more_button" msgid="7610604080293562345">"हाल में ऐक्सेस करने वाला ऐप"</string>      <string name="privacy_dialog_done_button" msgid="4504330708531434263">"हो गया"</string>      <string name="privacy_dialog_expand_action" msgid="9129262348628331377">"बड़ा करें और विकल्प दिखाएं"</string>      <string name="privacy_dialog_collapse_action" msgid="277419962019466347">"छोटा करें"</string> diff --git a/packages/SystemUI/res/values-hi/tiles_states_strings.xml b/packages/SystemUI/res/values-hi/tiles_states_strings.xml index 0cb06c001671..b89eeb3c0f0f 100644 --- a/packages/SystemUI/res/values-hi/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-hi/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"बंद है"</item>      <item msgid="5137565285664080143">"चालू है"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"उपलब्ध नहीं हैं"</item> +    <item msgid="3079622119444911877">"बंद हैं"</item> +    <item msgid="3028994095749238254">"चालू हैं"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index a1d885a30991..e0d2478206c4 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -119,7 +119,7 @@      <string name="screenrecord_taps_label" msgid="1595690528298857649">"Prikaz dodira na zaslonu"</string>      <string name="screenrecord_stop_label" msgid="72699670052087989">"Zaustavi"</string>      <string name="screenrecord_share_label" msgid="5025590804030086930">"Dijeli"</string> -    <string name="screenrecord_save_title" msgid="1886652605520893850">"Snimanje zaslona spremljeno"</string> +    <string name="screenrecord_save_title" msgid="1886652605520893850">"Snimanje zaslona je spremljeno"</string>      <string name="screenrecord_save_text" msgid="3008973099800840163">"Dodirnite za prikaz"</string>      <string name="screenrecord_save_error" msgid="5862648532560118815">"Pogreška prilikom spremanja snimke zaslona"</string>      <string name="screenrecord_start_error" msgid="2200660692479682368">"Pogreška prilikom pokretanja snimanja zaslona"</string> @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Zabilježi poteškoću"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Pokreni"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Zaustavi"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Izvješće o pogrešci"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na koji dio doživljaja na uređaju to utjecalo?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Odaberite vrstu problema"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje zaslona"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardni"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednji"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visoki"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušna pomagala"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni uređaji"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparivanje novog uređaja"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili novi uređaj"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite li deblokirati mikrofon uređaja?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite li deblokirati kameru uređaja?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite li deblokirati kameru i mikrofon uređaja?"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Promjena rasporeda tipkovnice"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ili"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Brisanje upita za pretraživanje"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Prečaci"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tipkovni prečaci"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Pretražite prečace"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nema nijednog prečaca"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sustav"</string> @@ -757,29 +754,29 @@      <string name="keyboard_shortcut_a11y_filter_input" msgid="4589316004510335529">"Prikazuju se prečaci za unos"</string>      <string name="keyboard_shortcut_a11y_filter_open_apps" msgid="6175417687221004059">"Prikazuju se prečaci koji otvaraju aplikacije"</string>      <string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"Prikazuju se prečaci za trenutačnu aplikaciju"</string> -    <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Prikaži obavijesti"</string> -    <string name="group_system_full_screenshot" msgid="5742204844232667785">"Snimi zaslon"</string> +    <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Prikaz obavijesti"</string> +    <string name="group_system_full_screenshot" msgid="5742204844232667785">"Snimanje zaslona"</string>      <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"Prikaži prečace"</string>      <string name="group_system_go_back" msgid="2730322046244918816">"Natrag"</string> -    <string name="group_system_access_home_screen" msgid="4130366993484706483">"Idi na početni zaslon"</string> -    <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Prikaži nedavne aplikacije"</string> -    <string name="group_system_cycle_forward" msgid="5478663965957647805">"Kruži unaprijed kroz nedavne aplikacije"</string> -    <string name="group_system_cycle_back" msgid="8194102916946802902">"Kruži unatrag kroz nedavne aplikacije"</string> -    <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Otvori popis aplikacija"</string> -    <string name="group_system_access_system_settings" msgid="8731721963449070017">"Otvori postavke"</string> -    <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otvori Asistenta"</string> +    <string name="group_system_access_home_screen" msgid="4130366993484706483">"Otvaranje početnog zaslona"</string> +    <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Prikaz nedavnih aplikacija"</string> +    <string name="group_system_cycle_forward" msgid="5478663965957647805">"Kruženje unaprijed kroz nedavne aplikacije"</string> +    <string name="group_system_cycle_back" msgid="8194102916946802902">"Kruženje unatrag kroz nedavne aplikacije"</string> +    <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Otvaranje popisa aplikacija"</string> +    <string name="group_system_access_system_settings" msgid="8731721963449070017">"Otvaranje postavki"</string> +    <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otvaranje asistenta"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Zaključavanje zaslona"</string> -    <string name="group_system_quick_memo" msgid="3764560265935722903">"Zapišite bilješku"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Obavljanje više zadataka sustava"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Otvori podijeljeni zaslon s trenutačnom aplikacijom s desne strane"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Otvori podijeljeni zaslon s trenutačnom aplikacijom s lijeve strane"</string> -    <string name="system_multitasking_full_screen" msgid="336048080383640562">"Prijeđi s podijeljenog zaslona na cijeli zaslon"</string> +    <string name="group_system_quick_memo" msgid="3764560265935722903">"Pisanje bilješke"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Obavljanje više zadataka"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Koristite podijeljeni zaslon s trenutačnom aplikacijom s desne strane"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Koristite podijeljeni zaslon s trenutačnom aplikacijom s lijeve strane"</string> +    <string name="system_multitasking_full_screen" msgid="336048080383640562">"Prelazak s podijeljenog zaslona na cijeli zaslon"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Prijeđite na aplikaciju zdesna ili ispod uz podijeljeni zaslon"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Prijeđite na aplikaciju slijeva ili iznad uz podijeljeni zaslon"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"Tijekom podijeljenog zaslona: zamijeni aplikaciju drugom"</string>      <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Unos"</string> -    <string name="input_switch_input_language_next" msgid="3782155659868227855">"Prijeđi na sljedeći jezik"</string> -    <string name="input_switch_input_language_previous" msgid="6043341362202336623">"Prijeđi na prethodni jezik"</string> +    <string name="input_switch_input_language_next" msgid="3782155659868227855">"Prelazak na sljedeći jezik"</string> +    <string name="input_switch_input_language_previous" msgid="6043341362202336623">"Prelazak na prethodni jezik"</string>      <string name="input_access_emoji" msgid="8105642858900406351">"Pristupanje emojijima"</string>      <string name="input_access_voice_typing" msgid="7291201476395326141">"Pristupanje unosu teksta govorom"</string>      <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Aplikacije"</string> @@ -1297,7 +1294,7 @@      <string name="privacy_dialog_active_call_usage" msgid="7858746847946397562">"Koristi telefonski poziv"</string>      <string name="privacy_dialog_recent_call_usage" msgid="1214810644978167344">"Nedavno korišteno tijekom telefonskog poziva"</string>      <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"Koristi: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> -    <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Nedavno koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> +    <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Nedavno je koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"Koristi: <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Nedavno koristila aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Koristi: <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-hr/tiles_states_strings.xml b/packages/SystemUI/res/values-hr/tiles_states_strings.xml index e09cab50e9bb..df0b78664cba 100644 --- a/packages/SystemUI/res/values-hr/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-hr/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Isključeno"</item>      <item msgid="5137565285664080143">"Uključeno"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Nedostupno"</item> +    <item msgid="3079622119444911877">"Isključeno"</item> +    <item msgid="3028994095749238254">"Uključeno"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index baea2404664e..7acfbe62e950 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Probléma rögzítése"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Indítás"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Leállítás"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Az eszközhasználati élmény mely része érintett?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Problématípus kiválasztása"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Képernyőrögzítés"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Normál"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Közepes"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Nagy"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hallókészülékek"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hallókészülékek"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Új eszköz párosítása"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kattintson új eszköz párosításához"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Feloldja az eszköz mikrofonjának letiltását?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Feloldja az eszköz kamerájának letiltását?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Feloldja az eszköz kamerájának és mikrofonjának letiltását?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Billentyűzetkiosztás váltása"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"vagy"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Keresőkifejezés törlése"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Billentyűparancsok"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Billentyűparancsok"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Billentyűparancs keresése"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nincs billentyűparancs"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Rendszer"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"A Segéd megnyitása"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Lezárási képernyő"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Jegyzetelés"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Rendszermultitasking"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Osztott képernyő aktiválása; az aktuális alkalmazás kerüljön jobbra"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Osztott képernyő aktiválása; az aktuális alkalmazás kerüljön balra"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Osztott képernyő használata, a jelenlegi alkalmazás legyen jobb oldalt"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Osztott képernyő használata, a jelenlegi alkalmazás legyen bal oldalt"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Váltás osztott képernyőről teljes képernyőre"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Váltás a jobb oldalt, illetve lent lévő appra osztott képernyő esetén"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Váltás a bal oldalt, illetve fent lévő appra osztott képernyő esetén"</string> diff --git a/packages/SystemUI/res/values-hu/tiles_states_strings.xml b/packages/SystemUI/res/values-hu/tiles_states_strings.xml index 8f75dc6ebe5c..bbd6bc0ebbbb 100644 --- a/packages/SystemUI/res/values-hu/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-hu/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Ki"</item>      <item msgid="5137565285664080143">"Be"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Nem áll rendelkezésre"</item> +    <item msgid="3079622119444911877">"Ki"</item> +    <item msgid="3028994095749238254">"Be"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 3f88746abf4c..7dc33b604b83 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Ձայնագրել"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Սկսել"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Կանգնեցնել"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Սարքի ո՞ր մասի հետ է կապված խնդիրը։"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Ընտրեք խնդրի տեսակը"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Էկրանի տեսագրում"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Սովորական"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Միջին"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Բարձր"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Լսողական սարքեր"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Լսողական սարքեր"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Նոր սարքի զուգակցում"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Սեղմեք՝ նոր սարք զուգակցելու համար"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Արգելահանե՞լ սարքի խոսափողը"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Արգելահանե՞լ սարքի տեսախցիկը"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Արգելահանե՞լ սարքի տեսախցիկը և խոսափողը"</string> @@ -720,7 +718,7 @@      <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string>      <string name="keyboard_key_space" msgid="6980847564173394012">"Բացատ"</string>      <string name="keyboard_key_enter" msgid="8633362970109751646">"Մուտք"</string> -    <string name="keyboard_key_backspace" msgid="4095278312039628074">"Հետշարժ"</string> +    <string name="keyboard_key_backspace" msgid="4095278312039628074">"Backspace"</string>      <string name="keyboard_key_media_play_pause" msgid="8389984232732277478">"Նվագարկում/դադար"</string>      <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Կանգնեցնել"</string>      <string name="keyboard_key_media_next" msgid="8502476691227914952">"Հաջորդը"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Դասավորության փոխարկում"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"կամ"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Ջնջել որոնման հարցումը"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Դյուրանցումներ"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Ստեղնային դյուրանցումներ"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Դյուրանցումների որոնում"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Դյուրանցումներ չեն գտնվել"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Համակարգ"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Բացել Օգնականը"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Կողպէկրան"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Ստեղծել նշում"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Համակարգի բազմախնդրության ռեժիմ"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Միացնել էկրանի տրոհումը՝ ընթացիկ հավելվածն աջ կողմում"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Միացնել էկրանի տրոհումը՝ ընթացիկ հավելվածը ձախ կողմում"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Բազմախնդրություն"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Աջ մասում օգտագործեք տրոհված էկրանն այս հավելվածի հետ"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Ձախ մասում օգտագործեք տրոհված էկրանն այս հավելվածի հետ"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Տրոհված էկրանից անցնել լիաէկրան ռեժիմ"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Անցեք աջ կողմի կամ ներքևի հավելվածին տրոհված էկրանի միջոցով"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Անցեք աջ կողմի կամ վերևի հավելվածին տրոհված էկրանի միջոցով"</string> diff --git a/packages/SystemUI/res/values-hy/tiles_states_strings.xml b/packages/SystemUI/res/values-hy/tiles_states_strings.xml index 118915d03612..eb77ccf8c1fc 100644 --- a/packages/SystemUI/res/values-hy/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-hy/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Անջատված է"</item>      <item msgid="5137565285664080143">"Միացված է"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Հասանելի չէ"</item> +    <item msgid="3079622119444911877">"Անջատված է"</item> +    <item msgid="3028994095749238254">"Միացված է"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 0b07a32d7017..3da9a9024612 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -119,7 +119,7 @@      <string name="screenrecord_taps_label" msgid="1595690528298857649">"Tampilkan lokasi sentuhan pada layar"</string>      <string name="screenrecord_stop_label" msgid="72699670052087989">"Stop"</string>      <string name="screenrecord_share_label" msgid="5025590804030086930">"Bagikan"</string> -    <string name="screenrecord_save_title" msgid="1886652605520893850">"Perekaman layar disimpan"</string> +    <string name="screenrecord_save_title" msgid="1886652605520893850">"Rekaman layar disimpan"</string>      <string name="screenrecord_save_text" msgid="3008973099800840163">"Ketuk untuk melihat"</string>      <string name="screenrecord_save_error" msgid="5862648532560118815">"Terjadi error saat menyimpan rekaman layar"</string>      <string name="screenrecord_start_error" msgid="2200660692479682368">"Terjadi error saat memulai perekaman layar"</string> @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Mencatat Masalah"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Mulai"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Berhenti"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Laporan Bug"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Bagian pengalaman perangkat mana yang terpengaruh?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pilih jenis masalah"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Perekaman layar"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standar"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Sedang"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Tinggi"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Alat bantu dengar"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Alat bantu dengar"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sambungkan perangkat baru"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menyambungkan perangkat baru"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Berhenti memblokir mikrofon perangkat?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Berhenti memblokir kamera perangkat?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Berhenti memblokir kamera dan mikrofon perangkat?"</string> @@ -594,7 +591,7 @@      <string name="stream_accessibility" msgid="3873610336741987152">"Aksesibilitas"</string>      <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Dering"</string>      <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Getar"</string> -    <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Nonaktifkan"</string> +    <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Bisukan"</string>      <string name="media_device_cast" msgid="4786241789687569892">"Transmisi"</string>      <string name="stream_notification_unavailable" msgid="4313854556205836435">"Tidak tersedia - Volume dering dibisukan"</string>      <string name="stream_alarm_unavailable" msgid="4059817189292197839">"Tidak tersedia - Fitur Jangan Ganggu aktif"</string> @@ -638,7 +635,7 @@      <string name="wallet_error_generic" msgid="257704570182963611">"Terjadi error saat mendapatkan kartu Anda, coba lagi nanti"</string>      <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Setelan layar kunci"</string>      <string name="qr_code_scanner_title" msgid="1938155688725760702">"Pemindai kode QR"</string> -    <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Mengupdate"</string> +    <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Update berlangsung"</string>      <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string>      <string name="status_bar_airplane" msgid="4848702508684541009">"Mode pesawat"</string>      <string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar alarm berikutnya <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -745,8 +742,8 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Ganti tata letak keyboard"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"atau"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Hapus kueri penelusuran"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Pintasan"</string> -    <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Pintasan penelusuran"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Pintasan Keyboard"</string> +    <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Telusuri pintasan"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Tidak ditemukan pintasan"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistem"</string>      <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"Input"</string> @@ -763,16 +760,16 @@      <string name="group_system_go_back" msgid="2730322046244918816">"Kembali"</string>      <string name="group_system_access_home_screen" msgid="4130366993484706483">"Buka layar utama"</string>      <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Lihat aplikasi terbaru"</string> -    <string name="group_system_cycle_forward" msgid="5478663965957647805">"Menavigasi maju pada aplikasi terbaru"</string> -    <string name="group_system_cycle_back" msgid="8194102916946802902">"Menavigasi mundur pada aplikasi terbaru"</string> +    <string name="group_system_cycle_forward" msgid="5478663965957647805">"Berpindah-pindah aplikasi terbaru ke arah kanan"</string> +    <string name="group_system_cycle_back" msgid="8194102916946802902">"Berpindah-pindah aplikasi terbaru ke arah kiri"</string>      <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Buka daftar aplikasi"</string>      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Buka setelan"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Buka Asisten"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Kunci layar"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Buat catatan"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitasking sistem"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Masuk ke layar terpisah dengan aplikasi saat ini ke RHS"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Masuk ke layar terpisah dengan aplikasi saat ini ke LHS"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Gunakan layar terpisah dengan aplikasi saat ini di sebelah kanan"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Gunakan layar terpisah dengan aplikasi saat ini di sebelah kiri"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Beralih dari layar terpisah ke layar penuh"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Beralih ke aplikasi di bagian kanan atau bawah saat menggunakan layar terpisah"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Beralih ke aplikasi di bagian kiri atau atas saat menggunakan layar terpisah"</string> diff --git a/packages/SystemUI/res/values-in/tiles_states_strings.xml b/packages/SystemUI/res/values-in/tiles_states_strings.xml index bd429c147784..a415f644fb48 100644 --- a/packages/SystemUI/res/values-in/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-in/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Nonaktif"</item>      <item msgid="5137565285664080143">"Aktif"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Tidak tersedia"</item> +    <item msgid="3079622119444911877">"Nonaktif"</item> +    <item msgid="3028994095749238254">"Aktif"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 56ea0d50705a..b400f8cec8c0 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Vandamál tengt upptöku"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Byrja"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stöðva"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Villutilkynning"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvað í tækjaupplifuninni varð fyrir áhrifum?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Veldu gerð vandamáls"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skjáupptaka"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Staðlað"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Miðlungs"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Mikið"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Heyrnartæki"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Heyrnartæki"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Para nýtt tæki"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Smelltu til að para nýtt tæki"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Opna fyrir hljóðnema tækisins?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Opna fyrir myndavél tækisins?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Opna fyrir myndavél og hljóðnema tækisins?"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Skipta um lyklaskipan"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"eða"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Hreinsa leitarfyrirspurn"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Flýtileiðir"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Flýtilyklar"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Leita að flýtileiðum"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Engar flýtileiðir fundust"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Kerfi"</string> @@ -770,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Opna Hjálpara"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Lásskjár"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Skrifa glósu"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Fjölvinnsla kerfis"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Opna skjáskiptingu hægra megin með núverandi forriti"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Opna skjáskiptingu vinstra megin með núverandi forriti"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Fjölvinnsla"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Notaðu skjáskiptingu með núverandi forriti til hægri"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Notaðu skjáskiptingu með núverandi forriti til vinstri"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Skipta úr skjáskiptingu yfir á allan skjáinn"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Skiptu í forrit til hægri eða fyrir neðan þegar skjáskipting er notuð"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Skiptu í forrit til vinstri eða fyrir ofan þegar skjáskipting er notuð"</string> diff --git a/packages/SystemUI/res/values-is/tiles_states_strings.xml b/packages/SystemUI/res/values-is/tiles_states_strings.xml index abdc3e7610b1..c9befd6574c4 100644 --- a/packages/SystemUI/res/values-is/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-is/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Slökkt"</item>      <item msgid="5137565285664080143">"Kveikt"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Ekki tiltækt"</item> +    <item msgid="3079622119444911877">"Slökkt"</item> +    <item msgid="3028994095749238254">"Kveikt"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 08f07efb07c8..aa7f15229c95 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Registra problema"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Avvia"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Interrompi"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quali problemi ha l\'esperienza del dispositivo?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Seleziona il tipo di problema"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Regis. dello schermo"</string> @@ -364,12 +366,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medio"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Apparecchi acustici"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Protesi uditive"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Accoppia nuovo dispositivo"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic per accoppiare un nuovo dispositivo"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vuoi sbloccare il microfono del dispositivo?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vuoi sbloccare la fotocamera del dispositivo?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vuoi sbloccare la fotocamera e il microfono del dispositivo?"</string> @@ -550,7 +549,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Questo dispositivo è gestito da uno dei tuoi genitori, il quale può visualizzare e gestire informazioni come le app che usi, la tua posizione e il tuo tempo di utilizzo."</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Sbloccato da TrustAgent"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Dispositivo bloccato, troppi tentativi di autenticazione"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Dispositivo bloccato: troppi tentativi di autenticazione"</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Dispositivo bloccato\nAutenticazione non riuscita"</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="accessibility_volume_settings" msgid="1458961116951564784">"Impostazioni audio"</string> @@ -744,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Cambia layout della tastiera"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"oppure"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Cancella la query di ricerca"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Scorciatoie"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Scorciatoie da tastiera"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Cerca scorciatoie"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Scorciatoie non trovate"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistema"</string> @@ -769,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Apri l\'assistente"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Blocca lo schermo"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Scrivi una nota"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitasking di sistema"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Attiva lo schermo diviso con l\'app corrente a destra"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Attiva lo schermo diviso con l\'app corrente a sinistra"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Utilizza schermo diviso con l\'app corrente a destra"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Utilizza schermo diviso con l\'app corrente a sinistra"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Passa da schermo diviso a schermo intero"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Passa all\'app a destra o sotto mentre usi lo schermo diviso"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Passa all\'app a sinistra o sopra mentre usi lo schermo diviso"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 24ec7853c399..a804271054f9 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"תיעוד הבעיה"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"התחלה"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"עצירה"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"איזה חלק בחוויית השימוש שלך במכשיר הושפע?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"בחירה בסוג הבעיה"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"הקלטת המסך"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"רגילה"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"בינונית"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"גבוהה"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"מכשירי שמיעה"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"מכשירי שמיעה"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"התאמה של מכשיר חדש"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"צריך ללחוץ כדי להתאים מכשיר חדש"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"לבטל את חסימת המיקרופון של המכשיר?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"לבטל את חסימת המצלמה של המכשיר?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"לבטל את חסימת המצלמה והמיקרופון של המכשיר?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"החלפה של פריסת מקלדת"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"או"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ניקוי שאילתת החיפוש"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"מקשי קיצור"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"מקשי קיצור"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"חיפוש מקשי קיצור"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"לא נמצאו מקשי קיצור"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"מערכת"</string> @@ -757,7 +755,7 @@      <string name="keyboard_shortcut_a11y_filter_input" msgid="4589316004510335529">"מוצגים: קיצורי הדרך של הקלט"</string>      <string name="keyboard_shortcut_a11y_filter_open_apps" msgid="6175417687221004059">"מוצגים: קיצורי הדרך לפתיחת אפליקציות"</string>      <string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"מוצגים: קיצורי הדרך של האפליקציה הנוכחית"</string> -    <string name="group_system_access_notification_shade" msgid="1619028907006553677">"הצגת הודעות"</string> +    <string name="group_system_access_notification_shade" msgid="1619028907006553677">"הצגת התראות"</string>      <string name="group_system_full_screenshot" msgid="5742204844232667785">"צילום המסך"</string>      <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"הצגת מקשי הקיצור"</string>      <string name="group_system_go_back" msgid="2730322046244918816">"חזרה"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"לפתיחת Google Assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"מסך הנעילה"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"כתיבת הערה"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"ריבוי משימות מערכת"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"כניסה למסך מפוצל עם האפליקציה הנוכחית ל-RHS"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"כניסה למסך מפוצל עם האפליקציה הנוכחית ל-LHS"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"ריבוי משימות"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"שימוש במסך מפוצל כשהאפליקציה הנוכחית בצד ימין"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"שימוש במסך מפוצל כשהאפליקציה הנוכחית בצד שמאל"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"החלפה ממסך מפוצל למסך מלא"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"מעבר לאפליקציה משמאל או למטה בזמן שימוש במסך מפוצל"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"מעבר לאפליקציה מימין או למעלה בזמן שימוש במסך מפוצל"</string> diff --git a/packages/SystemUI/res/values-iw/tiles_states_strings.xml b/packages/SystemUI/res/values-iw/tiles_states_strings.xml index 196a6c270593..b5cb476484b2 100644 --- a/packages/SystemUI/res/values-iw/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-iw/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"מושבת"</item>      <item msgid="5137565285664080143">"מופעל"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"לא זמינים"</item> +    <item msgid="3079622119444911877">"מצב מושבת"</item> +    <item msgid="3028994095749238254">"מצב פעיל"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 6e2ca403392a..6cd1dcb1cbd7 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"録音に関する問題"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"開始"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"停止"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"デバイスのどの部分が影響を受けましたか?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"問題の種類を選択する"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"スクリーン レコード"</string> @@ -364,12 +366,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"中"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"高"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"補聴器"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"補聴器"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"新しいデバイスとペア設定"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"クリックすると、新しいデバイスをペア設定できます"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"デバイスのマイクのブロックを解除しますか?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"デバイスのカメラのブロックを解除しますか?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"デバイスのカメラとマイクのブロックを解除しますか?"</string> @@ -744,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"キーボード レイアウトの切り替え"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"または"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"検索クエリをクリア"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"ショートカット"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"キーボード ショートカット"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"ショートカットの検索"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"ショートカットがありません"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"システム"</string> @@ -769,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"アシスタントを開く"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"画面をロック"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"メモを入力する"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"システム マルチタスク"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"分割画面にして現在のアプリを右側に設定する"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"分割画面にして現在のアプリを左側に設定する"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"マルチタスク"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"分割画面の使用(現在のアプリを右側に表示)"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"分割画面の使用(現在のアプリを左側に表示)"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"分割画面から全画面に切り替える"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"分割画面の使用時に右側または下部のアプリに切り替える"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"分割画面の使用時に左側または上部のアプリに切り替える"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index b2295f324a45..15bb4fcc0134 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"ჩაწერასთან დაკავშირებული პრობლემა"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"დაწყება"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"გაჩერება"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"თქვენი მოწყობილობის გამოცდილების რა ნაწილზე მოხდა ზეგავლენა?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"აირჩიეთ პრობლემის ტიპი"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ეკრანის ჩანაწერი"</string> @@ -364,12 +366,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"საშუალო"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"მაღალი"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"სმენის აპარატები"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"სმენის აპარატები"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ახალი მოწყობილობის დაწყვილება"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"დააწკაპუნეთ ახალი მოწყობილობის დასაწყვილებლად"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"გსურთ მოწყობილობის მიკროფონის განბლოკვა?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"გსურთ მოწყობილობის კამერის განბლოკვა?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"გსურთ მოწყობილობის კამერის და მიკროფონის განბლოკვა?"</string> @@ -744,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"კლავიატურის განლაგების გადართვა"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ან"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"საძიებო ფრაზის გასუფთავება"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"მალსახმობები"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"კლავიატურის მალსახმობები"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"მალსახმობების ძიება"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"მალსახმობები ვერ მოიძებნა"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"სისტემა"</string> @@ -769,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"ასისტენტის გახსნა"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"ჩაკეტილი ეკრანი"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"ჩაინიშნეთ"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"სისტემის მრავალამოცანიანი რეჟიმი"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"ეკრანის გაყოფის შეყვანა მიმდინარე აპით RHS-ში"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"ეკრანის გაყოფის შეყვანა მიმდინარე აპით LHS-ში"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"მრავალამოცანიანი რეჟიმი"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"ეკრანის გაყოფის გამოყენება მიმდინარე აპზე მარჯვნივ"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"ეკრანის გაყოფის გამოყენება მიმდინარე აპზე მარცხნივ"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"გადართვა ეკრანის გაყოფიდან სრულ ეკრანზე"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ეკრანის გაყოფის გამოყენებისას აპზე მარჯვნივ ან ქვემოთ გადართვა"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ეკრანის გაყოფის გამოყენებისას აპზე მარცხნივ ან ზემოთ გადართვა"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 127e81e19ae4..835a0cabfceb 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -281,7 +281,7 @@      <string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнитура"</string>      <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Кіріс"</string>      <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Есту аппараттары"</string> -    <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Қосылуда…"</string> +    <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Қосылып жатыр…"</string>      <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматты түрде бұру"</string>      <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматты айналатын экран"</string>      <string name="quick_settings_location_label" msgid="2621868789013389163">"Локация"</string> @@ -297,7 +297,7 @@      <string name="quick_settings_networks_available" msgid="1875138606855420438">"Желілер бар"</string>      <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Желілер қолжетімді емес."</string>      <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Қолжетімді Wi-Fi желілері жоқ"</string> -    <string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Қосылуда…"</string> +    <string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Қосылып жатыр…"</string>      <string name="quick_settings_cast_title" msgid="2279220930629235211">"Экранды трансляциялау"</string>      <string name="quick_settings_casting" msgid="1435880708719268055">"Трансляциялануда"</string>      <string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Атаусыз құрылғы"</string> @@ -312,9 +312,9 @@      <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Жабу"</string>      <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_connecting" msgid="2381969772953268809">"Қосылып жатыр…"</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_transient" msgid="7585604088079160564">"Қосылып жатыр…"</string>      <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Трафикті үнемдеу режимі қосулы"</string>      <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{# құрылғы}other{# құрылғы}}"</string>      <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Қолшам"</string> @@ -331,13 +331,13 @@      <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Түнгі жарық"</string>      <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Күн батқанда қосу"</string>      <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Күн шыққанға дейін"</string> -    <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Қосылу уақыты: <xliff:g id="TIME">%s</xliff:g>"</string> +    <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Қосылатын уақыты: <xliff:g id="TIME">%s</xliff:g>"</string>      <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> дейін"</string>      <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Қараңғы режим"</string>      <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Батареяны үнемдеу режимі"</string>      <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Күн батқанда қосу"</string>      <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Күн шыққанға дейін"</string> -    <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Қосылу уақыты: <xliff:g id="TIME">%s</xliff:g>"</string> +    <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Қосылатын уақыты: <xliff:g id="TIME">%s</xliff:g>"</string>      <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> дейін"</string>      <string name="quick_settings_dark_mode_secondary_label_on_at_bedtime" msgid="2274300599408864897">"Ұйқы режимінде"</string>      <string name="quick_settings_dark_mode_secondary_label_until_bedtime_ends" msgid="1790772410777123685">"Ұйқы режимі аяқталғанға дейін"</string> @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Ақауды жазу"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Бастау"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Тоқтату"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Құрылғы қызметінің қандай түріне әсер етті?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Мәселе түрін таңдаңыз."</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Экранды жазу"</string> @@ -364,12 +366,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Орташа"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Жоғары"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Есту құрылғылары"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Есту құрылғылары"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Жаңа құрылғыны жұптау"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Жаңа құрылғыны жұптау үшін басыңыз."</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Құрылғы микрофонын блоктан шығару керек пе?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Құрылғы камерасын блоктан шығару керек пе?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Құрылғы камерасы мен микрофонын блоктан шығару керек пе?"</string> @@ -636,7 +635,7 @@      <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Пайдалану үшін құлыпты ашу"</string>      <string name="wallet_error_generic" msgid="257704570182963611">"Карталарыңыз алынбады, кейінірек қайталап көріңіз."</string>      <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Экран құлпының параметрлері"</string> -    <string name="qr_code_scanner_title" msgid="1938155688725760702">"QR кодының сканері"</string> +    <string name="qr_code_scanner_title" msgid="1938155688725760702">"QR сканері"</string>      <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Жаңартылып жатыр"</string>      <string name="status_bar_work" msgid="5238641949837091056">"Жұмыс профилі"</string>      <string name="status_bar_airplane" msgid="4848702508684541009">"Ұшақ режимі"</string> @@ -744,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Пернетақта форматын ауыстыру"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"немесе"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Іздеу сұрауын өшіру"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Перне тіркесімдері"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Перне тіркесімдері"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Перне тіркесімдерін іздеу"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Перне тіркесімдері табылмады."</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Жүйе"</string> @@ -762,19 +761,19 @@      <string name="group_system_go_back" msgid="2730322046244918816">"Артқа"</string>      <string name="group_system_access_home_screen" msgid="4130366993484706483">"Негізгі экранға өту"</string>      <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Соңғы қолданбаларды көру"</string> -    <string name="group_system_cycle_forward" msgid="5478663965957647805">"Соңғы қолданбаларға алға өту"</string> -    <string name="group_system_cycle_back" msgid="8194102916946802902">"Соңғы қолданбаларға артқа өту"</string> +    <string name="group_system_cycle_forward" msgid="5478663965957647805">"Соңғы қолданбалар тізімінде алға өту"</string> +    <string name="group_system_cycle_back" msgid="8194102916946802902">"Соңғы қолданбалар тізімінде артқа өту"</string>      <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Қолданбалар тізімін ашу"</string>      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Параметрлерді ашу"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant-ті ашу"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Экранды құлыптау"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Ескертпе жазу"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Жүйе мультитаскингі"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Бөлінген экран режиміне кіру (ағымдағы қолданбаны оңға орналастыру)"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Бөлінген экран режиміне кіру (ағымдағы қолданбаны солға орналастыру)"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Мультитаскинг"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Ағымдағы қолданба оң жақта тұратын бөлінген экранды пайдаланыңыз"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Ағымдағы қолданба сол жақта тұратын бөлінген экранды пайдаланыңыз"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Бөлінген экран режимінен толық экран режиміне ауысу"</string> -    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Экранды бөлуді қолданғанда, оң не жоғары жақтағы қолданбаға ауысыңыз"</string> -    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Экранды бөлуді қолданғанда, сол не жоғары жақтағы қолданбаға ауысыңыз"</string> +    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Бөлінген экранда оң не төмен жақтағы қолданбаға ауысу"</string> +    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Бөлінген экранда сол не жоғары жақтағы қолданбаға ауысу"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"Экранды бөлу кезінде: бір қолданбаны басқасымен алмастыру"</string>      <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Енгізу"</string>      <string name="input_switch_input_language_next" msgid="3782155659868227855">"Келесі тілге ауысу"</string> @@ -1261,7 +1260,7 @@      <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Қалған батарея заряды: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>      <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Стилусты зарядтағышқа жалғаңыз."</string>      <string name="stylus_battery_low" msgid="7134370101603167096">"Стилус батареясының заряды аз"</string> -    <string name="video_camera" msgid="7654002575156149298">"Бейнекамера"</string> +    <string name="video_camera" msgid="7654002575156149298">"Бейнекамера"</string>      <string name="call_from_work_profile_title" msgid="5418253516453177114">"Жеке қолданбадан қоңырау шалу мүмкін емес"</string>      <string name="call_from_work_profile_text" msgid="2856337395968118274">"Ұйымыңыз тек жұмыс қолданбаларынан қоңырау шалуға рұқсат етеді."</string>      <string name="call_from_work_profile_action" msgid="2937701298133010724">"Жұмыс профиліне ауысу"</string> @@ -1284,7 +1283,7 @@      <string name="dismiss_dialog" msgid="2195508495854675882">"Жабу"</string>      <string name="connected_display_icon_desc" msgid="6373560639989971997">"Дисплей қосылды"</string>      <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон және камера"</string> -    <string name="privacy_dialog_summary" msgid="2458769652125995409">"Соңғы рет қолданбаның датчикті пайдалануы"</string> +    <string name="privacy_dialog_summary" msgid="2458769652125995409">"Қолданбалардың соңғы рет пайдалануы"</string>      <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Соңғы рет пайдаланғандар"</string>      <string name="privacy_dialog_done_button" msgid="4504330708531434263">"Дайын"</string>      <string name="privacy_dialog_expand_action" msgid="9129262348628331377">"Опцияларды көрсету және жаю"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index f2596dbf5897..d56c20de4692 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"កត់ត្រាបញ្ហា"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"ចាប់ផ្ដើម"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"បញ្ឈប់"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"របាយការណ៍អំពីបញ្ហា"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"តើផ្នែកអ្វីនៃបទពិសោធប្រើប្រាស់ឧបករណ៍របស់អ្នកបានរងការប៉ះពាល់?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ជ្រើសរើសប្រភេទបញ្ហា"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ការថតវីដេអូអេក្រង់"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"មធ្យម"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"ខ្ពស់"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ឧបករណ៍ជំនួយការស្ដាប់"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ឧបករណ៍ជំនួយការស្ដាប់"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ផ្គូផ្គងឧបករណ៍ថ្មី"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ចុច ដើម្បីផ្គូផ្គងឧបករណ៍ថ្មី"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ឈប់ទប់ស្កាត់មីក្រូហ្វូនរបស់ឧបករណ៍ឬ?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ឈប់ទប់ស្កាត់កាមេរ៉ារបស់ឧបករណ៍ឬ?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ឈប់ទប់ស្កាត់កាមេរ៉ា និងមីក្រូហ្វូនរបស់ឧបករណ៍ឬ?"</string> @@ -607,7 +605,7 @@      <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"សំឡេងលំហ"</string>      <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"បិទ"</string>      <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"ថេរ"</string> -    <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ការតាមដានក្បាល"</string> +    <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"រេតាមក្បាល"</string>      <string name="volume_ringer_change" msgid="3574969197796055532">"ចុចដើម្បីប្ដូរមុខងាររោទ៍"</string>      <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"បិទសំឡេង"</string>      <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"បើកសំឡេង"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"ប្ដូរប្លង់ក្ដារចុច"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ឬ"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"សម្អាតសំណួរស្វែងរក"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"ផ្លូវកាត់"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"ផ្លូវកាត់ក្ដារចុច"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"ស្វែងរកផ្លូវកាត់"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"រកផ្លូវកាត់មិនឃើញទេ"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"ប្រព័ន្ធ"</string> @@ -769,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"បើកជំនួយការ"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"ចាក់សោអេក្រង់"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"កត់ចំណាំ"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"ការដំណើរការបានច្រើននៃប្រព័ន្ធ"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"ចូលក្នុងមុខងារបំបែកអេក្រង់ដោយប្រើកម្មវិធីបច្ចុប្បន្ននៅខាងស្ដាំដៃ"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"ចូលក្នុងមុខងារបំបែកអេក្រង់ដោយប្រើកម្មវិធីបច្ចុប្បន្ននៅខាងឆ្វេងដៃ"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"ការដំណើរការបានច្រើន"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"ប្រើមុខងារបំបែកអេក្រង់ជាមួយកម្មវិធីបច្ចុប្បន្ននៅខាងស្ដាំ"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"ប្រើមុខងារបំបែកអេក្រង់ជាមួយកម្មវិធីបច្ចុប្បន្ននៅខាងឆ្វេង"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"ប្ដូរពីមុខងារបំបែកអេក្រង់ទៅជាអេក្រង់ពេញ"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ប្ដូរទៅកម្មវិធីនៅខាងស្ដាំ ឬខាងក្រោម ពេលកំពុងប្រើមុខងារបំបែកអេក្រង់"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ប្ដូរទៅកម្មវិធីនៅខាងឆ្វេង ឬខាងលើ ពេលកំពុងប្រើមុខងារបំបែកអេក្រង់"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 73234507bbce..23bde222e11a 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -329,7 +329,7 @@      <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳು"</string>      <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>      <string name="quick_settings_night_display_label" msgid="8180030659141778180">"ನೈಟ್ ಲೈಟ್"</string> -    <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ಸೂರ್ಯಾಸ್ತದಲ್ಲಿ"</string> +    <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ಸೂರ್ಯಾಸ್ತಕ್ಕೆ ಆನ್"</string>      <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ಸೂರ್ಯೋದಯದವರೆಗೆ"</string>      <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g> ಸಮಯದಲ್ಲಿ"</string>      <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> ವರೆಗೂ"</string> @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"ರೆಕಾರ್ಡ್ ದೋಷ"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"ಪ್ರಾರಂಭಿಸಿ"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"ನಿಲ್ಲಿಸಿ"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ಸಾಧನ ಬಳಸುವಾಗ ನೀವು ಯಾವ ರೀತಿಯ ಸಮಸ್ಯೆ ಎದುರಿಸುತ್ತೀರಿ?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ಸಮಸ್ಯೆಯ ಪ್ರಕಾರವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡ್"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ಪ್ರಮಾಣಿತ"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ಮಧ್ಯಮ"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"ಹೆಚ್ಚು"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ಹಿಯರಿಂಗ್ ಸಾಧನಗಳು"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ಹಿಯರಿಂಗ್ ಸಾಧನಗಳು"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ಸಾಧನದ ಮೈಕ್ರೋಫೋನ್ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ಸಾಧನದ ಕ್ಯಾಮರಾ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ಸಾಧನದ ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ಅನ್ಬ್ಲಾಕ್ ಮಾಡಬೇಕೇ?"</string> @@ -551,7 +549,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ಈ ಸಾಧನವನ್ನು ನಿಮ್ಮ ಪೋಷಕರು ನಿರ್ವಹಿಸುತ್ತಿದ್ದಾರೆ. ನೀವು ಬಳಸುವ ಆ್ಯಪ್ಗಳು, ನಿಮ್ಮ ಸ್ಥಳ ಮತ್ತು ನಿಮ್ಮ ವೀಕ್ಷಣಾ ಅವಧಿಯಂತಹ ಮಾಹಿತಿಯನ್ನು ನಿಮ್ಮ ಪೋಷಕರು ನೋಡಬಹುದು ಮತ್ತು ನಿರ್ವಹಿಸಬಹುದು."</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ನಿಂದ ಅನ್ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡಲಾಗಿದೆ, ಹಲವಾರು ದೃಢೀಕರಣ ಪ್ರಯತ್ನಗಳು"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"ಹಲವಾರು ದೃಢೀಕರಣ ಪ್ರಯತ್ನಗಳನ್ನು ಮಾಡಿರುವ ಕಾರಣ ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡಲಾಗಿದೆ\nದೃಢೀಕರಣ ವಿಫಲವಾಗಿದೆ"</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="accessibility_volume_settings" msgid="1458961116951564784">"ಸೌಂಡ್ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"ಕೀಬೋರ್ಡ್ ಲೇಔಟ್ ಬದಲಾಯಿಸಿ"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ಅಥವಾ"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ಹುಡುಕಾಟದ ಪ್ರಶ್ನೆಯನ್ನು ತೆರವುಗೊಳಿಸಿ"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಹುಡುಕಿ"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"ಯಾವುದೇ ಶಾರ್ಟ್ಕಟ್ಗಳಿಲ್ಲ"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"ಸಿಸ್ಟಂ"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"assistant ಅನ್ನು ತೆರೆಯಿರಿ"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಮಾಡಿ"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"ಟಿಪ್ಪಣಿಯನ್ನು ತೆಗೆದುಕೊಳ್ಳಿ"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"ಸಿಸ್ಟಂ ಮಲ್ಟಿಟಾಸ್ಕಿಂಗ್"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"RHS ಗೆ ಇರುವ ಪ್ರಸ್ತುತ ಆ್ಯಪ್ ಸಹಾಯದಿಂದ ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ನಮೂದಿಸಿ"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"LHS ಗೆ ಇರುವ ಪ್ರಸ್ತುತ ಆ್ಯಪ್ ಸಹಾಯದಿಂದ ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ನಮೂದಿಸಿ"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"ಮಲ್ಟಿಟಾಸ್ಕಿಂಗ್"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"ಬಲಭಾಗದಲ್ಲಿ ಪ್ರಸ್ತುತ ಆ್ಯಪ್ ಮೂಲಕ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಿ"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"ಎಡಭಾಗದಲ್ಲಿ ಪ್ರಸ್ತುತ ಆ್ಯಪ್ ಮೂಲಕ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಿ"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"ಸ್ಕ್ರೀನ್ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ನಿಂದ ಪೂರ್ಣ ಸ್ಕ್ರೀನ್ಗೆ ಬದಲಿಸಿ"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ಪರದೆ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ಬಳಸುವಾಗ ಬಲಭಾಗ ಅಥವಾ ಕೆಳಭಾಗದಲ್ಲಿರುವ ಆ್ಯಪ್ಗೆ ಬದಲಿಸಿ"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ಪರದೆ ಬೇರ್ಪಡಿಸಿ ಮೋಡ್ ಬಳಸುವಾಗ ಎಡಭಾಗ ಅಥವಾ ಮೇಲ್ಭಾಗದಲ್ಲಿರುವ ಆ್ಯಪ್ಗೆ ಬದಲಿಸಿ"</string> diff --git a/packages/SystemUI/res/values-kn/tiles_states_strings.xml b/packages/SystemUI/res/values-kn/tiles_states_strings.xml index 9628323a595f..afc7c1a10e0e 100644 --- a/packages/SystemUI/res/values-kn/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-kn/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"ಆಫ್ ಆಗಿದೆ"</item>      <item msgid="5137565285664080143">"ಆನ್ ಆಗಿದೆ"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"ಲಭ್ಯವಿಲ್ಲ"</item> +    <item msgid="3079622119444911877">"ಆಫ್ ಆಗಿದೆ"</item> +    <item msgid="3028994095749238254">"ಆನ್"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 9a4c60bc67fe..8f8246522b7e 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"문제 기록"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"시작"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"중지"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"기기 경험의 어떤 부분에 영향이 있었나요?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"문제 유형 선택"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"화면 녹화"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"표준"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"보통"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"높음"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"청각 보조 기기"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"청각 보조 기기"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"새 기기와 페어링"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"새 기기와 페어링하려면 클릭하세요"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"기기 마이크를 차단 해제하시겠습니까?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"기기 카메라를 차단 해제하시겠습니까?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"기기 카메라 및 마이크를 차단 해제하시겠습니까?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"키보드 레이아웃 전환"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"또는"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"검색어 삭제"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"단축키"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"단축키"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"단축키 검색"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"단축키 없음"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"시스템"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"어시스턴트 열기"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"잠금 화면"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"메모 작성"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"시스템 멀티태스킹"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"현재 앱을 오른쪽으로 보내는 화면 분할 입력"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"현재 앱을 왼쪽으로 보내는 화면 분할 입력"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"멀티태스킹"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"현재 앱이 오른쪽에 오도록 화면 분할 사용"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"현재 앱이 왼쪽에 오도록 화면 분할 사용"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"화면 분할에서 전체 화면으로 전환"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"화면 분할을 사용하는 중에 오른쪽 또는 아래쪽에 있는 앱으로 전환하기"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"화면 분할을 사용하는 중에 왼쪽 또는 위쪽에 있는 앱으로 전환하기"</string> diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml index d30aff2073f1..bc4740dbc23a 100644 --- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"사용 안함"</item>      <item msgid="5137565285664080143">"사용"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"사용 불가"</item> +    <item msgid="3079622119444911877">"사용 안함"</item> +    <item msgid="3028994095749238254">"사용"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index d893887469e9..40a427cebcb8 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -212,7 +212,7 @@      <string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"Bluetooth түзмөгүнүн сүрөтчөсү"</string>      <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Түзмөктүн чоо-жайын конфигурациялоо үчүн чыкылдатыңыз"</string>      <string name="accessibility_bluetooth_device_settings_see_all" msgid="9111952496905423543">"Бардык түзмөктөрдү көрүү үчүн чыкылдатыңыз"</string> -    <string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="2435184865793496966">"Жаңы түзмөктү жупташтыруу үчүн чыкылдатыңыз"</string> +    <string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="2435184865793496966">"Жаңы түзмөк кошуу үчүн чыкылдатыңыз"</string>      <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея кубатынын деңгээли белгисиз."</string>      <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> менен туташкан."</string>      <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> менен туташты."</string> @@ -266,7 +266,7 @@      <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>      <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Жупташкан түзмөктөр жок"</string>      <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Түзмөктү туташтыруу же ажыратуу үчүн таптаңыз"</string> -    <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Жаңы түзмөктү жупташтыруу"</string> +    <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Жаңы түзмөк кошуу"</string>      <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Баарын көрүү"</string>      <string name="turn_on_bluetooth" msgid="5681370462180289071">"Иштетүү"</string>      <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Туташты"</string> @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Маселени жаздыруу"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Баштоо"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Токтотуу"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Мүчүлүштүк тууралуу кабарлоо"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Түзмөгүңүздүн кайсы бөлүгүнө кедергиси тийди?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Маселенин түрүн тандоо"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Экрандан видео жаздырып алуу"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Кадимки"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Орточо"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Жогору"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Угуу аппараттары"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Угуу аппараттары"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Жаңы түзмөк кошуу"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Жаңы түзмөк кошуу үчүн басыңыз"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Түзмөктүн микрофонун бөгөттөн чыгарасызбы?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Түзмөктүн камерасын бөгөттөн чыгарасызбы?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Түзмөктүн камерасы менен микрофону бөгөттөн чыгарылсынбы?"</string> @@ -551,7 +548,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Бул түзмөктү ата-энең башкарат. Ата-энең сен иштеткен колдонмолорду, кайда жүргөнүңдү жана түзмөктү канча убакыт колдонгонуңду көрүп, башкарып турат."</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ишеним агенти кулпусун ачты"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Түзмөк кулпуланды. Аутентификациядан өтүүгө өтө көп аракет жасалды"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Аутентификациядан өтө албай койгонуңуздан улам, түзмөк кулпуланды"</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Түзмөк кулпуланды\nАутентификациядан өткөн жоксуз"</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="accessibility_volume_settings" msgid="1458961116951564784">"Добуштун параметрлери"</string> @@ -719,7 +716,7 @@      <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Ортолотуу"</string>      <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string>      <string name="keyboard_key_space" msgid="6980847564173394012">"Боштук"</string> -    <string name="keyboard_key_enter" msgid="8633362970109751646">"Киргизүү"</string> +    <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string>      <string name="keyboard_key_backspace" msgid="4095278312039628074">"Артка өчүрүү"</string>      <string name="keyboard_key_media_play_pause" msgid="8389984232732277478">"Ойнотуу/Тындыруу"</string>      <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Токтотуу"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Баскычтоп калыбын которуштуруу"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"же"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Изделген суроону тазалоо"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Ыкчам баскычтар"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Ыкчам баскычтар"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Ыкчам баскычтарды издөө"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Ыкчам баскычтар жок"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Система"</string> @@ -770,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Жардамчыны ачуу"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Экранды кулпулоо"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Кыска жазуу түзүү"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Системанын бир нече тапшырма аткаруусу"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Учурда оң жактагы колдонмо менен экранды бөлүүнү иштетүү"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Учурда сол жактагы колдонмо менен экранды бөлүүнү иштетүү"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Бир нече тапшырма аткаруу"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Учурдагы колдонмону оңго жылдырып, экранды бөлүү"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Учурдагы колдонмону солго жылдырып, экранды бөлүү"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Экранды бөлүү режиминен толук экранга которулуу"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Бөлүнгөн экранды колдонуп жатканда сол же төмөн жактагы колдонмого которулуңуз"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Бөлүнгөн экранды колдонуп жатканда сол же жогору жактагы колдонмого которулуңуз"</string> @@ -1286,21 +1283,21 @@      <string name="connected_display_icon_desc" msgid="6373560639989971997">"Экран туташтырылды"</string>      <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон жана камера"</string>      <string name="privacy_dialog_summary" msgid="2458769652125995409">"Жакында колдонмолордо иштетилген"</string> -    <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Акыркы пайдалануусун көрүү"</string> +    <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Соңку маалыматты көрүү"</string>      <string name="privacy_dialog_done_button" msgid="4504330708531434263">"Бүттү"</string>      <string name="privacy_dialog_expand_action" msgid="9129262348628331377">"Параметрлерди жайып көрсөтүү"</string>      <string name="privacy_dialog_collapse_action" msgid="277419962019466347">"Жыйыштыруу"</string>      <string name="privacy_dialog_close_app_button" msgid="8006250171305878606">"Бул колдонмону жабуу"</string>      <string name="privacy_dialog_close_app_message" msgid="1316408652526310985">"<xliff:g id="APP_NAME">%1$s</xliff:g> жабылды"</string>      <string name="privacy_dialog_manage_service" msgid="8320590856621823604">"Кызматты тескөө"</string> -    <string name="privacy_dialog_manage_permissions" msgid="2543451567190470413">"Кирүү мүмкүнчүлүгүн тескөө"</string> +    <string name="privacy_dialog_manage_permissions" msgid="2543451567190470413">"Жеткиликтүүлүгүн башкаруу"</string>      <string name="privacy_dialog_active_call_usage" msgid="7858746847946397562">"Телефон чалууда колдонулуп жатат"</string>      <string name="privacy_dialog_recent_call_usage" msgid="1214810644978167344">"Акыркы жолу телефон чалууда колдонулду"</string> -    <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда иштетилип жатат"</string> +    <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда иштеп жатат"</string>      <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Акыркы жолу <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда иштетилди"</string> -    <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда иштетилип жатат (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> +    <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда иштеп жатат (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Акыркы жолу <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>) колдонмосунда иштетилди"</string> -    <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда иштетилип жатат (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> +    <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда иштеп жатат (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>      <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Акыркы жолу <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>) колдонмосунда иштетилди"</string>      <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Баскычтоптун жарыгы"</string>      <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ичинен %1$d-деңгээл"</string> diff --git a/packages/SystemUI/res/values-ky/tiles_states_strings.xml b/packages/SystemUI/res/values-ky/tiles_states_strings.xml index 35795b77a32e..694967e3d8d6 100644 --- a/packages/SystemUI/res/values-ky/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ky/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Өчүк"</item>      <item msgid="5137565285664080143">"Күйүк"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Жеткиликсиз"</item> +    <item msgid="3079622119444911877">"Өчүк"</item> +    <item msgid="3028994095749238254">"Күйүк"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 873d75eddc8d..f7dfc7e1c5a1 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"ບັນຫາກ່ຽວກັບການບັນທຶກ"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"ເລີ່ມ"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"ຢຸດ"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"ລາຍງານຂໍ້ຜິດພາດ"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ສ່ວນໃດຂອງປະສົບການອຸປະກອນຂອງທ່ານໄດ້ຮັບຜົນກະທົບ?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ເລືອກປະເພດບັນຫາ"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ບັນທຶກໜ້າຈໍ"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ປານກາງ"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"ສູງ"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ອຸປະກອນຊ່ວຍຟັງ"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ອຸປະກອນຊ່ວຍຟັງ"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ຄລິກເພື່ອຈັບຄູ່ອຸປະກອນໃໝ່"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ປົດບລັອກໄມໂຄຣໂຟນອຸປະກອນບໍ?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ປົດບລັອກກ້ອງຖ່າຍຮູບອຸປະກອນບໍ?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ຍົກເລີກການບລັອກກ້ອງຖ່າຍຮູບ ຫຼື ໄມໂຄຣໂຟນອຸປະກອນບໍ?"</string> @@ -652,7 +650,7 @@      <string name="tuner_warning_title" msgid="7721976098452135267">"ມ່ວນຊື່ນສຳລັບບາງຄົນ ແຕ່ບໍ່ແມ່ນສຳລັບທຸກຄົນ"</string>      <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner ໃຫ້ທ່ານມີວິທີພິເສດຕື່ມອີກໃນການປັບປ່ຽນ ແລະຕົບແຕ່ງສ່ວນຕໍ່ປະສານຜູ້ໃຊ້ຂອງ Android. ຄຸນສົມບັດທົດລອງໃຊ້ເຫຼົ່ານີ້ອາດຈະປ່ຽນແປງ, ຢຸດເຊົາ ຫຼືຫາຍໄປໃນການວາງຈຳໜ່າຍໃນອະນາຄົດ. ຈົ່ງດຳເນີນຕໍ່ດ້ວຍຄວາມລະມັດລະວັງ."</string>      <string name="tuner_persistent_warning" msgid="230466285569307806">"ຄຸນສົມບັດທົດລອງໃຊ້ງານເຫຼົ່ານີ້ອາດຈະປ່ຽນແປງ, ຢຸດເຊົາ ຫຼືຫາຍໄປໃນການອອກຈຳໜ່າຍໃນອະນາຄົດ. ຈົ່ງສືບຕໍ່ດ້ວຍຄວາມລະມັດລະວັງ."</string> -    <string name="got_it" msgid="477119182261892069">"ໄດ້ແລ້ວ"</string> +    <string name="got_it" msgid="477119182261892069">"ເຂົ້າໃຈແລ້ວ"</string>      <string name="tuner_toast" msgid="3812684836514766951">"ຍິນດີດ້ວຍ! System UI Tuner ໄດ້ຖືກເພີ່ມໃສ່ການຕັ້ງຄ່າແລ້ວ"</string>      <string name="remove_from_settings" msgid="633775561782209994">"ເອົາອອກຈາກການຕັ້ງຄ່າ"</string>      <string name="remove_from_settings_prompt" msgid="551565437265615426">"ເອົາ System UI Tuner ອອກຈາກການຕັ້ງຄ່າ ແລະຢຸດການໃຊ້ທຸກຄຸນສົມບັດໃຊ້ງານຂອງມັນ?"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"ສະຫຼັບແປ້ນພິມ"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ຫຼື"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ລຶບລ້າງຄຳຊອກຫາ"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"ທາງລັດ"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"ຄີລັດ"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"ທາງລັດການຊອກຫາ"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"ບໍ່ພົບທາງລັດ"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"ລະບົບ"</string> @@ -769,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"ເປີດຜູ້ຊ່ວຍ"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"ໜ້າຈໍລັອກ"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"ຈົດບັນທຶກ"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"ການເຮັດຫຼາຍໜ້າວຽກພ້ອມກັນຂອງລະບົບ"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"ເຂົ້າສູ່ແບ່ງໜ້າຈໍດ້ວຍແອັບປັດຈຸບັນໄປຫາ RHS"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"ເຂົ້າສູ່ແບ່ງໜ້າຈໍດ້ວຍແອັບປັດຈຸບັນໄປຫາ LHS"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"ການເຮັດຫຼາຍໜ້າວຽກພ້ອມກັນ"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"ໃຊ້ການແບ່ງໜ້າຈໍກັບແອັບປັດຈຸບັນຢູ່ເບື້ອງຂວາ"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"ໃຊ້ການແບ່ງໜ້າຈໍກັບແອັບປັດຈຸບັນຢູ່ເບື້ອງຊ້າຍ"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"ສະຫຼັບຈາກແບ່ງໜ້າຈໍໄປເປັນເຕັມຈໍ"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ສະຫຼັບໄປໃຊ້ແອັບຢູ່ຂວາ ຫຼື ທາງລຸ່ມໃນຂະນະທີ່ໃຊ້ແບ່ງໜ້າຈໍ"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ສະຫຼັບໄປໃຊ້ແອັບຢູ່ຊ້າຍ ຫຼື ທາງເທິງໃນຂະນະທີ່ໃຊ້ແບ່ງໜ້າຈໍ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index d5d7929b9c41..734daf892d63 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Įrašyti problemą"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Pradėti"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stabdyti"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuri įrenginio funkcija buvo paveikta?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pasirinkite problemos tipą"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekrano įrašas"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Įprastas"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Vidutinis"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Aukštas"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Klausos įrenginiai"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Klausos įrenginiai"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Susieti naują įrenginį"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Spustelėkite, kad susietumėte naują įrenginį"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Panaikinti įrenginio mikrofono blokavimą?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Panaikinti įrenginio fotoaparato blokavimą?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Panaikinti įrenginio fotoaparato ir mikrofono blokavimą?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Perjungti klaviat. išdėstymą"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"arba"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Išvalyti paieškos užklausą"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Spartieji klavišai"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Spartieji klavišai"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Ieškoti sparčiųjų klavišų"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Sparčiųjų klavišų nerasta"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistema"</string> @@ -770,16 +768,16 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Atidaryti Padėjėją"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Užrakinti ekraną"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Sukurti pastabą"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Kelių užduočių atlikimas sistemoje"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Eiti į išskaidyto ekrano režimą su dabartine programa dešinėje"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Eiti į išskaidyto ekrano režimą su dabartine programa kairėje"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Kelių užduočių atlikimas"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Naudoti išskaidyto ekrano režimą su dabartine programa dešinėje"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Naudoti išskaidyto ekrano režimą su dabartine programa kairėje"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Perjungti iš išskaidyto ekrano režimo į viso ekrano režimą"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Perjunkite į programą dešinėje arba apačioje išskaidyto ekrano režimu"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Perjunkite į programą kairėje arba viršuje išskaidyto ekrano režimu"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"Išskaidyto ekrano režimu: pakeisti iš vienos programos į kitą"</string>      <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Įvestis"</string>      <string name="input_switch_input_language_next" msgid="3782155659868227855">"Perjungti į kitą kalbą"</string> -    <string name="input_switch_input_language_previous" msgid="6043341362202336623">"Perjungti ankstesnę kalbą"</string> +    <string name="input_switch_input_language_previous" msgid="6043341362202336623">"Perjungti į ankstesnę kalbą"</string>      <string name="input_access_emoji" msgid="8105642858900406351">"Pasiekti jaustuką"</string>      <string name="input_access_voice_typing" msgid="7291201476395326141">"Pasiekti rašymą balsu"</string>      <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Programos"</string> @@ -1297,7 +1295,7 @@      <string name="privacy_dialog_active_call_usage" msgid="7858746847946397562">"Naudotojo telefono skambučio programa"</string>      <string name="privacy_dialog_recent_call_usage" msgid="1214810644978167344">"Neseniai naudojo telefono skambučio programa"</string>      <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"Naudoja <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> -    <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Neseniai naudojo „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string> +    <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Neseniai naudojo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"Naudoja <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Neseniai naudojo „<xliff:g id="APP_NAME">%1$s</xliff:g>“ (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Naudoja <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-lt/tiles_states_strings.xml b/packages/SystemUI/res/values-lt/tiles_states_strings.xml index cfa55522cbf3..c975e7e3cc80 100644 --- a/packages/SystemUI/res/values-lt/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-lt/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Išjungta"</item>      <item msgid="5137565285664080143">"Įjungta"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Nepasiekiama"</item> +    <item msgid="3079622119444911877">"Išjungta"</item> +    <item msgid="3028994095749238254">"Įjungta"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 4413780f684c..74a9239c288a 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Problēmas ierakstīšana"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Sākt"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Apturēt"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuras ierīces funkcijas tika ietekmētas?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Atlasiet problēmas veidu"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekrāna ierakstīšana"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standarta"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Vidējs"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Augsts"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dzirdes aparāti"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dzirdes aparāti"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Savienojiet pārī jaunu ierīci"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Noklikšķiniet, lai savienotu pārī jaunu ierīci"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vai atbloķēt ierīces mikrofonu?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vai vēlaties atbloķēt ierīces kameru?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vai atbloķēt ierīces kameru un mikrofonu?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Mainīt tastatūras izkārtojumu"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"vai"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Notīrīt meklēšanas vaicājumu"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Īsinājumtaustiņi"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Īsinājumtaustiņi"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Meklēt īsinājumtaustiņus"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nav atrasti"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistēma"</string> @@ -769,10 +767,10 @@      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Atvērt iestatījumus"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Atvērt Asistentu"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Bloķēt ekrānu"</string> -    <string name="group_system_quick_memo" msgid="3764560265935722903">"Piezīmes izveide"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Sistēmas vairākuzdevumu režīms"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Pāriet ekrāna sadalīšanas režīmā ar pašreizējo lietotni pa labi"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Pāriet ekrāna sadalīšanas režīmā ar pašreizējo lietotni pa kreisi"</string> +    <string name="group_system_quick_memo" msgid="3764560265935722903">"Izveidot piezīmi"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Vairākuzdevumu režīms"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Izmantot ekrāna sadalīšanu ar pašreizējo lietotni labajā pusē"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Izmantot ekrāna sadalīšanu ar pašreizējo lietotni kreisajā pusē"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Pārslēgties no ekrāna sadalīšanas režīma uz pilnekrāna režīmu"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Pāriet uz lietotni pa labi/lejā, kamēr izmantojat sadalīto ekrānu."</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Pāriet uz lietotni pa kreisi/augšā, kamēr izmantojat sadalīto ekrānu."</string> diff --git a/packages/SystemUI/res/values-lv/tiles_states_strings.xml b/packages/SystemUI/res/values-lv/tiles_states_strings.xml index e6b4deab07ea..c65a1d429492 100644 --- a/packages/SystemUI/res/values-lv/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-lv/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Izslēgts"</item>      <item msgid="5137565285664080143">"Ieslēgts"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Nav pieejams"</item> +    <item msgid="3079622119444911877">"Izslēgts"</item> +    <item msgid="3028994095749238254">"Ieslēgts"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 4f5bf6cfd833..36d49e4241e1 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -276,7 +276,7 @@      <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Автоматски вклучи повторно утре"</string>      <string name="turn_on_bluetooth_auto_info_disabled" msgid="8267380591344023327">"Функциите како „Брзо споделување“, „Најди го мојот уред“ и локација на уредот користат Bluetooth"</string>      <string name="turn_on_bluetooth_auto_info_enabled" msgid="4802071533678400330">"Bluetooth ќе се вклучи утре во 5:00"</string> -    <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> батерија"</string> +    <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батерија: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>      <string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>      <string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Слушалки"</string>      <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Влез"</string> @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Евидентирајте проблем"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Започнете"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Сопрете"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Кој дел од доживувањето на уредот беше засегнат?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изберете тип проблем"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Снимање екран"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандарден"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Среден"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Висок"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слушни апарати"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слушни апарати"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Спари нов уред"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликнете за да спарите нов уред"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Да се одблокира пристапот до микрофонот на уредот?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Да се одблокира пристапот до камерата на уредот?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Да се одблокира пристапот до камерата и микрофонот на уредот?"</string> @@ -669,7 +667,7 @@      <string name="notification_automatic_title" msgid="3745465364578762652">"Автоматски"</string>      <string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звук или вибрации"</string>      <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звук или вибрации и се појавува подолу во делот со разговори"</string> -    <string name="notification_channel_summary_default" msgid="777294388712200605">"Може да ѕвони или вибрира во зависност од поставките на уредот"</string> +    <string name="notification_channel_summary_default" msgid="777294388712200605">"Може да ѕвони или вибрира во зависност од поставките за уредот"</string>      <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Може да ѕвони или вибрира во зависност од поставките на уредот. Стандардно, разговорите од <xliff:g id="APP_NAME">%1$s</xliff:g> се во балончиња."</string>      <string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Дозволете системот да определи дали известувањево треба да испушти звук или да вибрира"</string>      <string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Статус:</b> поставено на „Стандардно“"</string> @@ -719,7 +717,7 @@      <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Центар"</string>      <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string>      <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string> -    <string name="keyboard_key_enter" msgid="8633362970109751646">"Внеси"</string> +    <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string>      <string name="keyboard_key_backspace" msgid="4095278312039628074">"Бришење наназад"</string>      <string name="keyboard_key_media_play_pause" msgid="8389984232732277478">"Пушти/Паузирај"</string>      <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Сопри"</string> @@ -745,13 +743,13 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Промени јазик на тастатура"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"или"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Бришење поим за пребарување"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Кратенки"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Кратенки од тастатура"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Пребарувајте кратенки"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Не се пронајдени кратенки"</string> -    <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Системски"</string> +    <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Систем"</string>      <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"Внесување"</string> -    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Отворени аплик."</string> -    <string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"Тековна аплик."</string> +    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Отворање апликации"</string> +    <string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"Тековна апликација"</string>      <string name="keyboard_shortcut_a11y_show_search_results" msgid="2865241062981833705">"Се прикажуваат резултати од пребарувањето"</string>      <string name="keyboard_shortcut_a11y_filter_system" msgid="7744143131119370483">"Се прикажуваат системски кратенки"</string>      <string name="keyboard_shortcut_a11y_filter_input" msgid="4589316004510335529">"Се прикажуваат кратенки за внесување"</string> @@ -768,14 +766,14 @@      <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Отворете го списокот со апликации"</string>      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Отворете „Поставки“"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Отворете го „Помошникот“"</string> -    <string name="group_system_lock_screen" msgid="7391191300363416543">"Заклучен екран"</string> +    <string name="group_system_lock_screen" msgid="7391191300363416543">"Заклучете го екранот"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Фатете белешка"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Системски мултитаскинг"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Активирајте поделен екран со тековната апликација десно"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Активирајте поделен екран со тековната апликација лево"</string> -    <string name="system_multitasking_full_screen" msgid="336048080383640562">"Префрлете од поделен екран во цел екран"</string> -    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Префрлете на апликацијата десно или долу при користењето поделен екран"</string> -    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Префрлете на апликацијата лево или горе при користењето поделен екран"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Мултитаскинг"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Користете поделен екран со тековната апликација оддесно"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Користете поделен екран со тековната апликација одлево"</string> +    <string name="system_multitasking_full_screen" msgid="336048080383640562">"Префрлете се од поделен екран на цел екран"</string> +    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Префрлете се на апликацијата десно или долу при користењето поделен екран"</string> +    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Префрлете се на апликацијата лево или горе при користењето поделен екран"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"При поделен екран: префрлете ги аплик. од едната на другата страна"</string>      <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Внесување"</string>      <string name="input_switch_input_language_next" msgid="3782155659868227855">"Префрлете на следниот јазик"</string> @@ -1285,7 +1283,7 @@      <string name="dismiss_dialog" msgid="2195508495854675882">"Отфрли"</string>      <string name="connected_display_icon_desc" msgid="6373560639989971997">"Екранот е поврзан"</string>      <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string> -    <string name="privacy_dialog_summary" msgid="2458769652125995409">"Неодамнешно користење на апликација"</string> +    <string name="privacy_dialog_summary" msgid="2458769652125995409">"Неодамнешно користење од апликациите"</string>      <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Видете го скорешниот пристап"</string>      <string name="privacy_dialog_done_button" msgid="4504330708531434263">"Готово"</string>      <string name="privacy_dialog_expand_action" msgid="9129262348628331377">"Проширување и прикажување на опциите"</string> diff --git a/packages/SystemUI/res/values-mk/tiles_states_strings.xml b/packages/SystemUI/res/values-mk/tiles_states_strings.xml index 0d811206a766..a8d96950b6f8 100644 --- a/packages/SystemUI/res/values-mk/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-mk/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Исклучено"</item>      <item msgid="5137565285664080143">"Вклучено"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Недостапно"</item> +    <item msgid="3079622119444911877">"Исклучено"</item> +    <item msgid="3028994095749238254">"Вклучено"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 8ce379627d9c..b20faa9af6e4 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"പ്രശ്നം റെക്കോർഡ് ചെയ്യുക"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"ആരംഭിക്കുക"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"നിർത്തുക"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"ബഗ് റിപ്പോർട്ട്"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"നിങ്ങളുടെ ഉപകരണ അനുഭവത്തിന്റെ ഏത് ഭാഗമാണ് ബാധിച്ചത്?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"പ്രശ്ന തരം തിരഞ്ഞെടുക്കുക"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"സ്ക്രീൻ റെക്കോർഡ്"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ഇടത്തരം"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"കൂടുതൽ"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"കേൾവിക്കുള്ള ഉപകരണങ്ങൾ"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"കേൾവിക്കുള്ള ഉപകരണങ്ങൾ"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"പുതിയ ഉപകരണം ജോടിയാക്കുക"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"പുതിയ ഉപകരണം ജോടിയാക്കാൻ ക്ലിക്ക് ചെയ്യുക"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ഉപകരണ മൈക്രോഫോൺ അൺബ്ലോക്ക് ചെയ്യണോ?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ഉപകരണ ക്യാമറ അൺബ്ലോക്ക് ചെയ്യണോ?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ഉപകരണ ക്യാമറയോ മൈക്രോഫോണോ അൺബ്ലോക്ക് ചെയ്യണോ?"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"കീബോർഡ് ലേഔട്ട് മാറുക"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"അല്ലെങ്കിൽ"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"തിരയൽ ചോദ്യം മായ്ക്കുക"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"കുറുക്കുവഴികൾ"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"കീബോർഡ് കുറുക്കുവഴികൾ"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"കുറുക്കുവഴികൾ തിരയുക"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"കുറുക്കുവഴി കണ്ടെത്തിയില്ല"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"സിസ്റ്റം"</string> @@ -769,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant തുറക്കുക"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"ലോക്ക് സ്ക്രീൻ"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"ഒരു കുറിപ്പെടുക്കുക"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"സിസ്റ്റം മൾട്ടിടാസ്കിംഗ്"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"നിലവിലെ ആപ്പ് വലതുവശത്ത് വരുന്ന രീതിയിൽ സ്ക്രീൻ വിഭജന മോഡിൽ കടക്കുക"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"നിലവിലെ ആപ്പ് ഇടതുവശത്ത് വരുന്ന രീതിയിൽ സ്ക്രീൻ വിഭജന മോഡിൽ കടക്കുക"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"മൾട്ടിടാസ്കിംഗ്"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"വലതുവശത്തുള്ള നിലവിലെ ആപ്പിനൊപ്പം സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുക"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"ഇടതുവശത്തുള്ള നിലവിലെ ആപ്പിനൊപ്പം സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുക"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"സ്ക്രീൻ വിഭജന മോഡിൽ നിന്ന് പൂർണ്ണ സ്ക്രീനിലേക്ക് മാറുക"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുമ്പോൾ വലതുവശത്തെ/താഴത്തെ ആപ്പിലേക്ക് മാറൂ"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കുമ്പോൾ ഇടതുവശത്തെ/മുകളിലെ ആപ്പിലേക്ക് മാറൂ"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 1a2e4b1f8c78..333ab55b6485 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Асуудлыг бичих"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Эхлүүлэх"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Зогсоох"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Таны төхөөрөмжийн хэрэглээний аль хэсэгт нөлөөлсөн бэ?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Асуудлын төрөл сонгоно уу"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Дэлгэцийн бичлэг"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандарт"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Дунд зэрэг"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Өндөр"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Сонсголын төхөөрөмжүүд"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Сонсголын төхөөрөмжүүд"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Шинэ төхөөрөмж хослуулах"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Шинэ төхөөрөмж хослуулахын тулд товшино уу"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Төхөөрөмжийн микрофоныг блокоос гаргах уу?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Төхөөрөмжийн камерыг блокоос гаргах уу?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Төхөөрөмжийн камер болон микрофоныг блокоос гаргах уу?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Гарын бүдүүвч рүү сэлгэх"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"эсвэл"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Хайлтын асуулгыг арилгах"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Товчлолууд"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Товчлуурын шууд холбоос"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Товчлолууд хайх"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Ямар ч товчлол олдсонгүй"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Систем"</string> @@ -770,12 +768,12 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Туслахыг нээх"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Түгжээтэй дэлгэц"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Тэмдэглэл хөтлөх"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Систем олон ажил зэрэг хийх"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Одоогийн аппаар баруун гар талд дэлгэц хуваахад орох"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Одоогийн аппаар зүүн гар талд дэлгэц хуваахад орох"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Олон ажил зэрэг хийх"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Одоогийн аппыг баруун талд байгаагаар дэлгэцийг хуваахыг ашиглах"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Одоогийн аппыг зүүн талд байгаагаар дэлгэцийг хуваахыг ашиглах"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Дэлгэц хуваахаас бүтэн дэлгэц рүү сэлгэх"</string> -    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Дэлгэц хуваахыг ашиглаж байхдаа баруун эсвэл доор байх апп руу сэлгэ"</string> -    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Дэлгэц хуваахыг ашиглаж байхдаа зүүн эсвэл дээр байх апп руу сэлгэ"</string> +    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Дэлгэц хуваахыг ашиглаж байхдаа баруун талд эсвэл доор байх апп руу сэлгэ"</string> +    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Дэлгэц хуваахыг ашиглаж байхдаа зүүн талд эсвэл дээр байх апп руу сэлгэ"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"Дэлгэц хуваах үеэр: аппыг нэгээс нөгөөгөөр солих"</string>      <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Оролт"</string>      <string name="input_switch_input_language_next" msgid="3782155659868227855">"Дараагийн хэл рүү сэлгэх"</string> @@ -1268,7 +1266,7 @@      <string name="call_from_work_profile_action" msgid="2937701298133010724">"Ажлын профайл руу сэлгэх"</string>      <string name="install_dialer_on_work_profile_action" msgid="2014659711597862506">"Ажлын гар утасны апп суулгах"</string>      <string name="call_from_work_profile_close" msgid="5830072964434474143">"Цуцлах"</string> -    <string name="lock_screen_settings" msgid="6152703934761402399">"Түгжигдсэн дэлгэцийг өөрчлөх"</string> +    <string name="lock_screen_settings" msgid="6152703934761402399">"Түгжээтэй дэлгэцийг өөрчлөх"</string>      <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Түгжээтэй дэлгэцийг өөрчлөхийн тулд түгжээг тайлна уу"</string>      <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi-Fi боломжгүй байна"</string>      <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Камерыг блоклосон"</string> diff --git a/packages/SystemUI/res/values-mn/tiles_states_strings.xml b/packages/SystemUI/res/values-mn/tiles_states_strings.xml index cfaf693ccd4c..a3f54541880d 100644 --- a/packages/SystemUI/res/values-mn/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-mn/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Унтраалттай"</item>      <item msgid="5137565285664080143">"Асаалттай"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Боломжгүй"</item> +    <item msgid="3079622119444911877">"Унтраалттай"</item> +    <item msgid="3028994095749238254">"Асаалттай"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 2e21fd078785..5bed1b432909 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"समस्या रेकॉर्ड करा"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"सुरुवात करा"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"थांबवा"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"तुमच्या डिव्हाइसबाबत कोणत्या अनुभवावर परिणाम झाला?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्येचा प्रकार निवडा"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रीन रेकॉर्ड"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"साधारण"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"मध्यम"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"उच्च"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"श्रवणयंत्रे"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"श्रवणयंत्रे"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नवीन डिव्हाइस पेअर करा"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नवीन डिव्हाइस पेअर करण्यासाठी क्लिक करा"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"डिव्हाइसचा मायक्रोफोन अनब्लॉक करायचा आहे का?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"डिव्हाइसचा कॅमेरा अनब्लॉक करायचा आहे का?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"डिव्हाइसचा कॅमेरा आणि मायक्रोफोन अनब्लॉक करायचा आहे का?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"कीबोर्ड लेआउट स्विच करा"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"किंवा"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"शोध क्वेरी साफ करा"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"शॉर्टकट"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"कीबोर्ड शॉर्टकट"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"शॉर्टकट शोधा"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"एकही शॉर्टकट आढळला नाहीत"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"सिस्टीम"</string> @@ -757,7 +755,7 @@      <string name="keyboard_shortcut_a11y_filter_input" msgid="4589316004510335529">"इनपुट शॉर्टकट दाखवत आहे"</string>      <string name="keyboard_shortcut_a11y_filter_open_apps" msgid="6175417687221004059">"ॲप्स उघडणारे शॉर्टकट दाखवत आहे"</string>      <string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"सद्य अॅपसाठी शॉर्टकट दाखवत आहे"</string> -    <string name="group_system_access_notification_shade" msgid="1619028907006553677">"सूचना पहा"</string> +    <string name="group_system_access_notification_shade" msgid="1619028907006553677">"नोटिफिकेशन पहा"</string>      <string name="group_system_full_screenshot" msgid="5742204844232667785">"स्क्रीनशॉट घ्या"</string>      <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"शॉर्टकट दाखवा"</string>      <string name="group_system_go_back" msgid="2730322046244918816">"मागे जा"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant उघडा"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"लॉक स्क्रीन"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"नोंद घ्या"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"सिस्टीम मल्टिटास्किंग"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"उजव्या बाजूला सध्याचे अॅप असलेल्या स्प्लिट स्क्रीनवर जा"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"डाव्या बाजूला सध्याचे अॅप असलेल्या स्प्लिट स्क्रीनवर जा"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"मल्टिटास्किंग"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"सद्य ॲप उजवीकडे ठेवून स्प्लिट स्क्रीन वापरा"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"सद्य ॲप डावीकडे ठेवून स्प्लिट स्क्रीन वापरा"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"स्प्लिट स्क्रीनवरून फुल स्क्रीनवर स्विच करा"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रीन वापरताना उजवीकडील किंवा खालील अॅपवर स्विच करा"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रीन वापरताना डावीकडील किंवा वरील अॅपवर स्विच करा"</string> diff --git a/packages/SystemUI/res/values-mr/tiles_states_strings.xml b/packages/SystemUI/res/values-mr/tiles_states_strings.xml index abb7aceec4e2..54c320c953d5 100644 --- a/packages/SystemUI/res/values-mr/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-mr/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"बंद आहे"</item>      <item msgid="5137565285664080143">"सुरू आहे"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"उपलब्ध नाही"</item> +    <item msgid="3079622119444911877">"बंद आहे"</item> +    <item msgid="3028994095749238254">"सुरू आहे"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 9ae774f511f9..4df6540c617e 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Rekodkan masalah"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Mula"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Hentikan"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Laporan Pepijat"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Pengalaman peranti yang manakah yang terjejas?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pilih jenis masalah"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rakam skrin"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Sederhana"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Tinggi"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Peranti pendengaran"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Peranti pendengaran"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Gandingkan peranti baharu"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menggandingkan peranti baharu"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Nyahsekat mikrofon peranti?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Nyahsekat kamera peranti?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Nyahsekat kamera dan mikrofon peranti?"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Tukar reka letak papan kekunci"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"atau"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Kosongkan pertanyaan carian"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Pintasan"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Pintasan Papan Kekunci"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Cari pintasan"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Tiada pintasan ditemukan"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistem"</string> @@ -762,16 +760,16 @@      <string name="group_system_go_back" msgid="2730322046244918816">"Kembali"</string>      <string name="group_system_access_home_screen" msgid="4130366993484706483">"Akses skrin utama"</string>      <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Lihat apl terbaharu"</string> -    <string name="group_system_cycle_forward" msgid="5478663965957647805">"Kitar ke hadapan menerusi apl terbaharu"</string> -    <string name="group_system_cycle_back" msgid="8194102916946802902">"Kitar ke belakang menerusi apl terbaharu"</string> +    <string name="group_system_cycle_forward" msgid="5478663965957647805">"Navigasi apl terbaharu ke arah kanan"</string> +    <string name="group_system_cycle_back" msgid="8194102916946802902">"Navigasi apl terbaharu ke arah kiri"</string>      <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Buka senarai apl"</string>      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Buka tetapan"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Buka Assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Kunci skrin"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Catat nota"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Berbilang tugas sistem"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Masuk skrin pisah dengan apl semasa pada sisi kanan"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Masuk skrin pisah dengan apl semasa pada sisi kiri"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Berbilang tugas"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Gunakan skrin pisah dengan apl semasa pada sebelah kanan"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Gunakan skrin pisah dengan apl semasa pada sebelah kiri"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Beralih daripada skrin pisah kepada skrin penuh"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Tukar kepada apl di sebelah kanan/bawah semasa menggunakan skrin pisah"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Tukar kepada apl di sebelah kiri/atas semasa menggunakan skrin pisah"</string> @@ -1124,7 +1122,7 @@      <string name="basic_status" msgid="2315371112182658176">"Buka perbualan"</string>      <string name="select_conversation_title" msgid="6716364118095089519">"Widget perbualan"</string>      <string name="select_conversation_text" msgid="3376048251434956013">"Ketik perbualan untuk menambahkan perbualan itu pada skrin Utama anda"</string> -    <string name="no_conversations_text" msgid="5354115541282395015">"Perbualan terbaharu anda akan dipaparkan di sini"</string> +    <string name="no_conversations_text" msgid="5354115541282395015">"Perbualan terbaharu akan dipaparkan di sini"</string>      <string name="priority_conversations" msgid="3967482288896653039">"Perbualan keutamaan"</string>      <string name="recent_conversations" msgid="8531874684782574622">"Perbualan terbaharu"</string>      <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> hari lalu"</string> @@ -1193,7 +1191,7 @@      <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# apl aktif}other{# apl aktif}}"</string>      <string name="fgs_dot_content_description" msgid="2865071539464777240">"Maklumat baharu"</string>      <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apl aktif"</string> -    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Apl ini aktif dan berfungsi walaupun anda tidak menggunakannya. Ini meningkatkan kefungsian apl tetapi mungkin akan memberikan kesan kepada hayat bateri."</string> +    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Apl ini aktif dan berfungsi walaupun anda tidak menggunakannya. Hal ini meningkatkan kefungsian apl tetapi akan memberikan kesan kepada hayat bateri."</string>      <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Berhenti"</string>      <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Dihentikan"</string>      <string name="clipboard_edit_text_done" msgid="4551887727694022409">"Selesai"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 12498851a449..a1894b04277b 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -235,7 +235,7 @@      <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"အကြောင်းကြားစာအကွက်"</string>      <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"အမြန်လုပ် အပြင်အဆင်"</string>      <string name="accessibility_desc_qs_notification_shade" msgid="8327226953072700376">"‘အမြန်ဆက်တင်များ’ နှင့် ‘အကြောင်းကြားစာအကွက်’။"</string> -    <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"မျက်နှာပြင် သော့ပိတ်ရန်"</string> +    <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"လော့ခ်မျက်နှာပြင်"</string>      <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"အလုပ်သုံး လော့ခ်မျက်နှာပြင်"</string>      <string name="accessibility_desc_close" msgid="8293708213442107755">"ပိတ်ရန်"</string>      <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"လုံးဝ အသံပိတ်ထားရန်"</string> @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"ပြဿနာကို မှတ်တမ်းတင်ခြင်း"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"စတင်ပါ"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"ရပ်ပါ"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"စက်အသုံးပြုမှု၏ မည်သည့်အပိုင်းကို သက်ရောက်သလဲ။"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ပြဿနာအမျိုးအစား ရွေးရန်"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ဖန်သားပြင်ရိုက်ကူးရန်"</string> @@ -364,12 +366,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"အသင့်အတင့်"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"များ"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"နားကြားကိရိယာ"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"နားကြားကိရိယာ"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"စက်အသစ်တွဲချိတ်ရန်"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"စက်အသစ် တွဲချိတ်ရန် နှိပ်ပါ"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"စက်၏မိုက်ခရိုဖုန်းကို ပြန်ဖွင့်မလား။"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"စက်၏ကင်မရာကို ပြန်ဖွင့်မလား။"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"စက်၏ကင်မရာနှင့် မိုက်ခရိုဖုန်းကို ပြန်ဖွင့်မလား။"</string> @@ -550,7 +549,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ဤစက်ပစ္စည်းကို သင့်မိဘက စီမံခန့်ခွဲသည်။ သင့်မိဘက သင်သုံးသောအက်ပ်များ၊ သင်၏တည်နေရာနှင့် အသုံးပြုချိန် ကဲ့သို့သော အချက်အလက်များကို မြင်နိုင်ပြီး စီမံခန့်ခွဲနိုင်သည်။"</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ဖြင့် ဆက်ဖွင့်ထားရန်"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"စက်လော့ခ်ကျနေသည်၊ အထောက်အထားစိစစ်ရန် ကြိုးပမ်းမှုအကြိမ်ရေ များလွန်းသည်"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"လော့ခ်ကျနေသည်၊ အထောက်အထားစိစစ်ရန် ကြိုးပမ်းကြိမ် များလွန်းသည်"</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"စက်လော့ခ်ကျနေသည်\nအထောက်အထားစိစစ်၍ မရပါ"</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="accessibility_volume_settings" msgid="1458961116951564784">"အသံဆက်တင်များ"</string> @@ -593,7 +592,7 @@      <string name="stream_accessibility" msgid="3873610336741987152">"အများသုံးနိုင်မှု"</string>      <string name="volume_ringer_status_normal" msgid="1339039682222461143">"အသံမြည်သည်"</string>      <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"တုန်ခါသည်"</string> -    <string name="volume_ringer_status_silent" msgid="3691324657849880883">"အသံတိတ်သည်"</string> +    <string name="volume_ringer_status_silent" msgid="3691324657849880883">"အသံပိတ်ရန်"</string>      <string name="media_device_cast" msgid="4786241789687569892">"ကာစ်လုပ်ရန်"</string>      <string name="stream_notification_unavailable" msgid="4313854556205836435">"ဖုန်းမြည်သံပိတ်ထားသဖြင့် မရနိုင်ပါ"</string>      <string name="stream_alarm_unavailable" msgid="4059817189292197839">"‘မနှောင့်ယှက်ရ’ ဖွင့်ထားသောကြောင့် မရနိုင်ပါ"</string> @@ -744,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"ကီးဘုတ်အပြင်အဆင် ပြောင်းခြင်း"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"သို့မဟုတ်"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ရှာဖွေစာလုံး ရှင်းထုတ်ရန်"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"ဖြတ်လမ်းလင့်ခ်များ"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"လက်ကွက်ဖြတ်လမ်းများ"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"ဖြတ်လမ်းလင့်ခ်များ ရှာပါ"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"ဖြတ်လမ်းလင့်ခ် မတွေ့ပါ"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"စနစ်"</string> @@ -769,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant ဖွင့်ရန်"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"လော့ခ်မျက်နှာပြင်"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"မှတ်စုရေးရန်"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"စနစ်က တစ်ပြိုင်နက် များစွာလုပ်ခြင်း"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"လက်ရှိအက်ပ်ကို မျက်နှာပြင် ခွဲ၍ပြသမှု၏ ညာဘက်တွင်ထည့်ရန်"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"လက်ရှိအက်ပ်ကို မျက်နှာပြင် ခွဲ၍ပြသမှု၏ ဘယ်ဘက်တွင်ထည့်ရန်"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"တစ်ပြိုင်နက် များစွာလုပ်ခြင်း"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"လက်ရှိအက်ပ်ကို ညာ၌ထားကာ မျက်နှာပြင် ခွဲ၍ပြသခြင်း သုံးရန်"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"လက်ရှိအက်ပ်ကို ဘယ်၌ထားကာ မျက်နှာပြင် ခွဲ၍ပြသခြင်း သုံးရန်"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"မျက်နှာပြင် ခွဲ၍ပြသမှုမှ မျက်နှာပြင်အပြည့်သို့ ပြောင်းရန်"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"မျက်နှာပြင်ခွဲ၍ပြသခြင်း သုံးစဉ် ညာ (သို့) အောက်ရှိအက်ပ်သို့ ပြောင်းရန်"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးစဉ် ဘယ် (သို့) အထက်ရှိအက်ပ်သို့ ပြောင်းရန်"</string> @@ -867,7 +866,7 @@      <string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ဆက်တင်များ၏ အစီအစဉ်ကို တည်းဖြတ်ပါ။"</string>      <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ပါဝါမီနူး"</string>      <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string> -    <string name="tuner_lock_screen" msgid="2267383813241144544">"လော့ခ်ချထားချိန် မျက်နှာပြင်"</string> +    <string name="tuner_lock_screen" msgid="2267383813241144544">"လော့ခ်မျက်နှာပြင်"</string>      <string name="finder_active" msgid="7907846989716941952">"ပါဝါပိတ်ထားသော်လည်း Find My Device ဖြင့် ဤဖုန်းကို ရှာနိုင်သည်"</string>      <string name="shutdown_progress" msgid="5464239146561542178">"စက်ပိတ်နေသည်…"</string>      <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 0f9bb464f21f..5039150d06eb 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Registrer problem"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Start"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stopp"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvilken del av enhetsopplevelsen din ble påvirket?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Velg problemtype"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skjermopptak"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Middels"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Høy"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Høreapparater"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Høreapparater"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Koble til en ny enhet"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klikk for å koble til en ny enhet"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du oppheve blokkeringen av enhetsmikrofonen?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vil du oppheve blokkeringen av enhetskameraet?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vil du oppheve blokkeringen av enhetskameraet og -mikrofonen?"</string> @@ -551,7 +549,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Denne enheten administreres av forelderen din. Forelderen din kan se og administrere informasjon, for eksempel appene du bruker, posisjonen din og skjermtiden din."</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Holdes opplåst med TrustAgent"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Enheten var låst – for mange autentiseringsforsøk"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Enheten er låst – for mange autentiseringsforsøk"</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Enheten er låst\nKunne ikke autentisere"</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="accessibility_volume_settings" msgid="1458961116951564784">"Lydinnstillinger"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Bytt tastaturoppsett"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"eller"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Fjern søket"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Hurtigtaster"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Hurtigtaster"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Søk etter hurtigtaster"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Fant ingen hurtigtaster"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"System"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Åpne assistenten"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Låseskjerm"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Ta et notat"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitasking på systemet"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Åpne delt skjerm med den aktive appen til høyre"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Åpne delt skjerm med den aktive appen til venstre"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Bruk delt skjerm med den nåværende appen til høyre"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Bruk delt skjerm med den nåværende appen til venstre"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Bytt fra delt skjerm til fullskjerm"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bytt til appen til høyre eller under mens du bruker delt skjerm"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bytt til appen til venstre eller over mens du bruker delt skjerm"</string> diff --git a/packages/SystemUI/res/values-nb/tiles_states_strings.xml b/packages/SystemUI/res/values-nb/tiles_states_strings.xml index af0042395127..a9efd1d95a7d 100644 --- a/packages/SystemUI/res/values-nb/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-nb/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Av"</item>      <item msgid="5137565285664080143">"På"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Ikke tilgjengelig"</item> +    <item msgid="3079622119444911877">"Av"</item> +    <item msgid="3028994095749238254">"På"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 5f51a9136a3f..28c7b05a290f 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -62,7 +62,7 @@      <string name="share_wifi_button_text" msgid="1285273973812029240">"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\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_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="9085779370142222881">"हालैमा यस डिभाइसमा साइन इन भएका प्रयोगकर्ताले USB डिबगिङ सक्रिय गर्न सक्दैनन्। यो सुविधा प्रयोग गर्न कृपया खाताका एड्मिनका रूपमा साइन इन गर्नुहोस्।"</string> @@ -108,7 +108,7 @@      <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="4152602778470789965">"तपाईंले रेकर्ड गर्दै गर्दा Android ले तपाईंको स्क्रिनमा देखिने वा डिभाइसमा प्ले गरिने सबै कुरा हेर्न तथा प्रयोग गर्न सक्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>      <string name="screenrecord_permission_dialog_warning_single_app" msgid="6818309727772146138">"तपाईंले कुनै एप रेकर्ड गर्दै गर्दा Android ले उक्त एपमा देखाइने वा प्ले गरिने सबै कुरा हेर्न तथा प्रयोग गर्न सक्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>      <string name="screenrecord_permission_dialog_continue" msgid="5811122652514424967">"रेकर्ड गर्न थाल्नुहोस्"</string> -    <string name="screenrecord_audio_label" msgid="6183558856175159629">"अडियो रेकर्ड गरियोस्"</string> +    <string name="screenrecord_audio_label" msgid="6183558856175159629">"अडियो रेकर्ड गर्नुहोस्"</string>      <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"डिभाइसको अडियो"</string>      <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"तपाईंको डिभाइसका सङ्गीत, कल र रिङटोन जस्ता साउन्ड"</string>      <string name="screenrecord_mic_label" msgid="2111264835791332350">"माइक्रोफोन"</string> @@ -116,7 +116,7 @@      <string name="screenrecord_continue" msgid="4055347133700593164">"सुरु गर्नुहोस्"</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> +    <string name="screenrecord_taps_label" msgid="1595690528298857649">"स्पर्श गरिएका स्थानहरू देखाउनुहोस्"</string>      <string name="screenrecord_stop_label" msgid="72699670052087989">"रोक्नुहोस्"</string>      <string name="screenrecord_share_label" msgid="5025590804030086930">"सेयर गर्नुहोस्"</string>      <string name="screenrecord_save_title" msgid="1886652605520893850">"स्क्रिन रेकर्डिङ सेभ गरियो"</string> @@ -273,14 +273,14 @@      <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"सेभ गरिएको छ"</string>      <string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"डिस्कनेक्ट गर्नुहोस्"</string>      <string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"एक्टिभेट गर्नुहोस्"</string> -    <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"भोलि फेरि स्वतः अन गरियोस्"</string> +    <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"भोलि फेरि स्वतः अन गर्नुहोस्"</string>      <string name="turn_on_bluetooth_auto_info_disabled" msgid="8267380591344023327">"क्विक सेयर, Find My Device र डिभाइसको लोकेसन जस्ता सुविधाहरूले ब्लुटुथ प्रयोग गर्छन्"</string>      <string name="turn_on_bluetooth_auto_info_enabled" msgid="4802071533678400330">"ब्लुटुथ भोलि बिहान ५ बजे अन हुने छ"</string>      <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ब्याट्री"</string>      <string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"अडियो"</string>      <string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>      <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string> -    <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"श्रवण यन्त्रहरू"</string> +    <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"हियरिङ डिभाइसहरू"</string>      <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"सक्रिय गर्दै…"</string>      <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"अटो रोटेट"</string>      <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रिन स्वतःघुम्ने"</string> @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"समस्या रेकर्ड गर्नुहोस्"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"सुरु गर्नुहोस्"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"रोक्नुहोस्"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"त्रुटिको रिपोर्ट"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"तपाईंको डिभाइसको कुन चाहिँ सुविधा प्रभावित भएको छ?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्याको प्रकार चयन गर्नुहोस्"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रिन रेकर्ड"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"डिफल्ट"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"मध्यम"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"उच्च"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"हियरिङ डिभाइसहरू"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"हियरिङ डिभाइसहरू"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नयाँ डिभाइसमा कनेक्ट गर्न क्लिक गर्नुहोस्"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"डिभाइसको माइक्रोफोन अनब्लक गर्ने हो?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"डिभाइसको क्यामेरा अनब्लक गर्ने हो?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"डिभाइसको क्यामेरा र माइक्रोफोन अनब्लक गर्ने हो?"</string> @@ -551,7 +548,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"यो डिभाइस तपाईंका अभिभावक व्यवस्थापन गर्नुहुन्छ। तपाईंका अभिभावक तपाईंले प्रयोग गर्ने एप, तपाईंको स्थान र तपाईंले यन्त्र चलाएर बिताउने समय जस्ता जानकारी हेर्न तथा व्यवस्थापन गर्न सक्नुहुन्छ।"</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ले खुला राखेको"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"डिभाइस लक गरिएको छ, प्रमाणीकरण गर्ने निकै धेरै प्रयास गरिएका छन्"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"डिभाइस लक गरिएको छ, निकै धेरै पटक प्रमाणीकरण गर्ने प्रयास भएको छ"</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"डिभाइस लक गरिएको छ\nप्रमाणीकरण गर्न सकिएन"</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="accessibility_volume_settings" msgid="1458961116951564784">"ध्वनिसम्बन्धी सेटिङहरू"</string> @@ -631,7 +628,7 @@      <string name="status_bar_alarm" msgid="87160847643623352">"अलार्म"</string>      <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>      <string name="wallet_empty_state_label" msgid="7776761245237530394">"फोनमार्फत अझ छिटो र थप सुरक्षित तरिकाले खरिद गर्न भुक्तानी विधि सेटअप गर्नुहोस्"</string> -    <string name="wallet_app_button_label" msgid="7123784239111190992">"सबै देखाइयोस्"</string> +    <string name="wallet_app_button_label" msgid="7123784239111190992">"सबै देखाउनुहोस्"</string>      <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"खोल्न ट्याप गर्नुहोस्"</string>      <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"अपडेट गरिँदै छ"</string>      <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"यो वालेट प्रयोग गर्न डिभाइस अनलक गर्नुहोस्"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"किबोर्डको लेआउट बदल्नुहोस्"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"वा"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"किवर्ड हटाउनुहोस्"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"सर्टकटहरू"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"किबोर्डका सर्टकटहरू"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"सर्टकटहरू खोज्नुहोस्"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"कुनै पनि सर्टकट भेटिएन"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"सिस्टम"</string> @@ -759,7 +756,7 @@      <string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"हालको एपका लागि सर्टकटहरू देखाइँदै छ"</string>      <string name="group_system_access_notification_shade" msgid="1619028907006553677">"सूचनाहरू हेर्नुहोस्"</string>      <string name="group_system_full_screenshot" msgid="5742204844232667785">"स्क्रिनसट खिच्नुहोस्"</string> -    <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"सर्टकटहरू देखाइऊन्"</string> +    <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"सर्टकटहरू देखाउनुहोस्"</string>      <string name="group_system_go_back" msgid="2730322046244918816">"पछाडि जानुहोस्"</string>      <string name="group_system_access_home_screen" msgid="4130366993484706483">"होम स्क्रिनमा जानुहोस्"</string>      <string name="group_system_overview_open_apps" msgid="5659958952937994104">"हालसालै चलाइएका एपहरू हेर्ने तरिका"</string> @@ -769,10 +766,10 @@      <string name="group_system_access_system_settings" msgid="8731721963449070017">"सेटिङ खोल्नुहोस्"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"एसिस्टेन्ट खोल्नुहोस्"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"स्क्रिन लक गर्नुहोस्"</string> -    <string name="group_system_quick_memo" msgid="3764560265935722903">"नोट लेख"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"सिस्टम मल्टिटास्किङ"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"हालको एप दायाँतर्फ रहने गरी स्प्लिट स्क्रिन मोड सुरु गर्नुहोस्"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"हालको एप बायाँतर्फ रहने गरी स्प्लिट स्क्रिन मोड सुरु गर्नुहोस्"</string> +    <string name="group_system_quick_memo" msgid="3764560265935722903">"नोट लेख्नुहोस्"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"एकै पटक एकभन्दा बढी एप चलाउन मिल्ने सुविधा"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"हालको एप दायाँ भागमा पारेर स्प्लिट स्क्रिन प्रयोग गर्नुहोस्"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"हालको एप बायाँ भागमा पारेर स्प्लिट स्क्रिन प्रयोग गर्नुहोस्"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"स्प्लिट स्क्रिनको साटो फुल स्क्रिन प्रयोग गर्नुहोस्"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"स्प्लिट स्क्रिन प्रयोग गर्दै गर्दा दायाँ वा तलको एप चलाउनुहोस्"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"स्प्लिट स्क्रिन प्रयोग गर्दै गर्दा बायाँ वा माथिको एप चलाउनुहोस्"</string> @@ -1288,7 +1285,7 @@      <string name="privacy_dialog_summary" msgid="2458769652125995409">"एपको हालसालैको प्रयोग"</string>      <string name="privacy_dialog_more_button" msgid="7610604080293562345">"हालसालै एक्सेस गर्ने एप हेर्नुहोस्"</string>      <string name="privacy_dialog_done_button" msgid="4504330708531434263">"पूरा भयो"</string> -    <string name="privacy_dialog_expand_action" msgid="9129262348628331377">"एक्स्पान्ड गरियोस् र विकल्पहरू देखाइयोस्"</string> +    <string name="privacy_dialog_expand_action" msgid="9129262348628331377">"एक्स्पान्ड गर्नुहोस् र विकल्पहरू देखाउनुहोस्"</string>      <string name="privacy_dialog_collapse_action" msgid="277419962019466347">"कोल्याप्स गर्नुहोस्"</string>      <string name="privacy_dialog_close_app_button" msgid="8006250171305878606">"यो एप बन्द गर्नुहोस्"</string>      <string name="privacy_dialog_close_app_message" msgid="1316408652526310985">"<xliff:g id="APP_NAME">%1$s</xliff:g> बन्द गरिएको छ"</string> diff --git a/packages/SystemUI/res/values-ne/tiles_states_strings.xml b/packages/SystemUI/res/values-ne/tiles_states_strings.xml index 005a473a79c1..c1b2f3420a40 100644 --- a/packages/SystemUI/res/values-ne/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ne/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"अफ छ"</item>      <item msgid="5137565285664080143">"अन छ"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"उपलब्ध छैन"</item> +    <item msgid="3079622119444911877">"अफ छ"</item> +    <item msgid="3028994095749238254">"अन छ"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 1f780b3bff4e..d0500c04568e 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -145,7 +145,7 @@      <string name="accessibility_phone_button" msgid="4256353121703100427">"Telefoon"</string>      <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"Spraakassistent"</string>      <string name="accessibility_wallet_button" msgid="1458258783460555507">"Portemonnee"</string> -    <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"QR-codescanner"</string> +    <string name="accessibility_qr_code_scanner_button" msgid="7521277927692910795">"QR-codescanner"</string>      <string name="accessibility_unlock_button" msgid="3613812140816244310">"Ontgrendeld"</string>      <string name="accessibility_lock_icon" msgid="661492842417875775">"Apparaat vergrendeld"</string>      <string name="accessibility_scanning_face" msgid="3093828357921541387">"Gezicht scannen"</string> @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Probleem vastleggen"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Starten"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stoppen"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Op welk onderdeel van de apparaatfunctionaliteit had dit effect?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Probleemtype selecteren"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Schermopname"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standaard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Gemiddeld"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Hoog"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hoortoestellen"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hoortoestellen"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Nieuw apparaat koppelen"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nieuw apparaat te koppelen"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Microfoon van apparaat niet meer blokkeren?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Apparaatcamera niet meer blokkeren?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Blokkeren van apparaatcamera en -microfoon opheffen?"</string> @@ -551,7 +549,7 @@      <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Dit apparaat wordt beheerd door je ouder. Je ouder kan informatie bekijken en beheren, zoals de apps die je gebruikt, je locatie en je schermtijd."</string>      <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>      <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ontgrendeld gehouden door TrustAgent"</string> -    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Het apparaat is vergrendeld na te veel verificatiepogingen"</string> +    <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"Te veel pogingen. Apparaat vergrendeld."</string>      <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"Apparaat vergrendeld\nVerificatie mislukt"</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="accessibility_volume_settings" msgid="1458961116951564784">"Geluidsinstellingen"</string> @@ -637,7 +635,7 @@      <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontgrendelen om te gebruiken"</string>      <string name="wallet_error_generic" msgid="257704570182963611">"Er is een probleem opgetreden bij het ophalen van je kaarten. Probeer het later opnieuw."</string>      <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Instellingen voor vergrendelscherm"</string> -    <string name="qr_code_scanner_title" msgid="1938155688725760702">"QR-codescanner"</string> +    <string name="qr_code_scanner_title" msgid="1938155688725760702">"QR-codescanner"</string>      <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Updaten"</string>      <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string>      <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Toetsenbordindeling wisselen"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"of"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Zoekopdracht wissen"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Sneltoetsen"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Sneltoetsen"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Sneltoetsen zoeken"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Geen sneltoetsen gevonden"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Systeem"</string> @@ -770,12 +768,12 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistent openen"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Scherm vergrendelen"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Notitie maken"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Systeem-multitasking"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Gesplitst scherm openen met huidige app rechts"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Gesplitst scherm openen met huidige app links"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasken"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Gesplitst scherm gebruiken met de huidige app aan de rechterkant"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Gesplitst scherm gebruiken met de huidige app aan de linkerkant"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Van gesplitst scherm naar volledig scherm schakelen"</string> -    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Ga naar de app rechts of onderaan als je een gesplitst scherm gebruikt"</string> -    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Ga naar de app links of bovenaan als je een gesplitst scherm gebruikt"</string> +    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Naar de app rechts of onderaan gaan als je een gesplitst scherm gebruikt"</string> +    <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Naar de app links of bovenaan gaan als je een gesplitst scherm gebruikt"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"Tijdens gesplitst scherm: een app vervangen door een andere"</string>      <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Invoer"</string>      <string name="input_switch_input_language_next" msgid="3782155659868227855">"Overschakelen naar volgende taal"</string> @@ -829,8 +827,8 @@      <string name="right_keycode" msgid="2480715509844798438">"Toetscode rechts"</string>      <string name="left_icon" msgid="5036278531966897006">"Icoon links"</string>      <string name="right_icon" msgid="1103955040645237425">"Icoon rechts"</string> -    <string name="drag_to_add_tiles" msgid="8933270127508303672">"Houd vast en sleep om tegels toe te voegen"</string> -    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Houd vast en sleep om tegels opnieuw in te delen"</string> +    <string name="drag_to_add_tiles" msgid="8933270127508303672">"Houd een tegel ingedrukt en sleep om die toe te voegen"</string> +    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Houd een tegel ingedrukt en sleep om die te verplaatsen"</string>      <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Sleep hier naartoe om te verwijderen"</string>      <string name="drag_to_remove_disabled" msgid="933046987838658850">"Je hebt minimaal <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tegels nodig"</string>      <string name="qs_edit" msgid="5583565172803472437">"Bewerken"</string> @@ -1262,7 +1260,7 @@      <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Nog <xliff:g id="PERCENTAGE">%s</xliff:g> batterijlading"</string>      <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Verbind je stylus met een oplader"</string>      <string name="stylus_battery_low" msgid="7134370101603167096">"Batterij van stylus bijna leeg"</string> -    <string name="video_camera" msgid="7654002575156149298">"Videocamera"</string> +    <string name="video_camera" msgid="7654002575156149298">"Videocamera"</string>      <string name="call_from_work_profile_title" msgid="5418253516453177114">"Kan niet bellen vanuit een app voor persoonlijke doeleinden"</string>      <string name="call_from_work_profile_text" msgid="2856337395968118274">"Je organisatie staat je alleen toe om te bellen vanuit werk-apps"</string>      <string name="call_from_work_profile_action" msgid="2937701298133010724">"Overschakelen naar werkprofiel"</string> diff --git a/packages/SystemUI/res/values-nl/tiles_states_strings.xml b/packages/SystemUI/res/values-nl/tiles_states_strings.xml index 1b286f33d583..c5d93610fb87 100644 --- a/packages/SystemUI/res/values-nl/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-nl/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Uit"</item>      <item msgid="5137565285664080143">"Aan"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Niet beschikbaar"</item> +    <item msgid="3079622119444911877">"Uit"</item> +    <item msgid="3028994095749238254">"Aan"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 9a602b86bf33..eb6865ea4111 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"ସମସ୍ୟାର ରେକର୍ଡ କରନ୍ତୁ"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"ଆରମ୍ଭ କରନ୍ତୁ"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"ବନ୍ଦ କରନ୍ତୁ"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"ବଗ୍ ରିପୋର୍ଟ୍"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ଆପଣଙ୍କ ଡିଭାଇସ ଅନୁଭୂତିର କେଉଁ ଅଂଶ ପ୍ରଭାବିତ ହୋଇଛି?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ସମସ୍ୟାର ପ୍ରକାର ଚୟନ କରନ୍ତୁ"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ସ୍କ୍ରିନ ରେକର୍ଡ"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ଷ୍ଟାଣ୍ଡାର୍ଡ"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ମଧ୍ୟମ"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"ଅଧିକ"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ହିଅରିଂ ଡିଭାଇସଗୁଡ଼ିକ"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ହିଅରିଂ ଡିଭାଇସଗୁଡ଼ିକ"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ନୂଆ ଡିଭାଇସ ପେୟାର କର"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ନୂଆ ଡିଭାଇସ ପେୟାର କରିବାକୁ କ୍ଲିକ କରନ୍ତୁ"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ଡିଭାଇସର ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ କରିବେ?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ଡିଭାଇସର କେମେରାକୁ ଅନବ୍ଲକ କରିବେ?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ଡିଭାଇସର କ୍ୟାମେରା ଏବଂ ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ୍ କରିବେ?"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"କୀ\'ବୋର୍ଡ୍ର ଲେଆଉଟ୍କୁ ବଦଳାନ୍ତୁ"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"କିମ୍ବା"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ସର୍ଚ୍ଚ କ୍ୱେରୀକୁ ଖାଲି କରନ୍ତୁ"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"ସର୍ଟକଟଗୁଡ଼ିକ"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"କୀବୋର୍ଡ ସର୍ଟକଟ"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"ସର୍ଟକଟ ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"କୌଣସି ସର୍ଟକଟ ମିଳିଲା ନାହିଁ"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"ସିଷ୍ଟମ"</string> @@ -770,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant ଖୋଲନ୍ତୁ"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"ଲକ ସ୍କ୍ରିନ"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"ଏକ ନୋଟ ଲେଖନ୍ତୁ"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"ସିଷ୍ଟମ ମଲ୍ଟିଟାସ୍କିଂ"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"RHSରେ ବର୍ତ୍ତମାନର ଆପ ସହ ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନକୁ ପ୍ରବେଶ କରାନ୍ତୁ"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"LHSରେ ବର୍ତ୍ତମାନର ଆପ ସହ ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନକୁ ପ୍ରବେଶ କରାନ୍ତୁ"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"ମଲ୍ଟିଟାସ୍କିଂ"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"ଡାହାଣରେ ବର୍ତ୍ତମାନର ଆପ ସହିତ ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନକୁ ବ୍ୟବହାର କରନ୍ତୁ"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"ବାମରେ ବର୍ତ୍ତମାନର ଆପ ସହିତ ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନକୁ ବ୍ୟବହାର କରନ୍ତୁ"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନରୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନକୁ ସୁଇଚ କରନ୍ତୁ"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବା ସମୟରେ ଡାହାଣପଟର ବା ତଳର ଆପକୁ ସୁଇଚ କରନ୍ତୁ"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବା ସମୟରେ ବାମପଟର ବା ଉପରର ଆପକୁ ସୁଇଚ କରନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-or/tiles_states_strings.xml b/packages/SystemUI/res/values-or/tiles_states_strings.xml index fd727bfbfe07..fe187c2ff082 100644 --- a/packages/SystemUI/res/values-or/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-or/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"ବନ୍ଦ ଅଛି"</item>      <item msgid="5137565285664080143">"ଚାଲୁ ଅଛି"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"ଅନୁପଲବ୍ଧ"</item> +    <item msgid="3079622119444911877">"ବନ୍ଦ ଅଛି"</item> +    <item msgid="3028994095749238254">"ଚାଲୁ ଅଛି"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 40efd0bd716a..3066c1d3e00a 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -328,7 +328,7 @@      <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਚਿਤਾਵਨੀ"</string>      <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ"</string>      <string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"ਰੋਕਿਆ ਗਿਆ"</string> -    <string name="quick_settings_night_display_label" msgid="8180030659141778180">"ਰਾਤ ਦੀ ਰੋਸ਼ਨੀ"</string> +    <string name="quick_settings_night_display_label" msgid="8180030659141778180">"ਨਾਈਟ ਲਾਈਟ"</string>      <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ਸੂਰਜ ਛਿਪਣ \'ਤੇ ਚਾਲੂ"</string>      <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ਸੂਰਜ ਚੜ੍ਹਨ ਤੱਕ"</string>      <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g> ਵਜੇ ਚਾਲੂ"</string> @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"ਸਮੱਸਿਆ ਰਿਕਾਰਡ ਕਰੋ"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"ਸ਼ੁਰੂ ਕਰੋ"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"ਬੰਦ ਕਰੋ"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਕਿਹੜੀ ਸੁਵਿਧਾ ਪ੍ਰਭਾਵਿਤ ਹੋਈ ਸੀ?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ਸਮੱਸਿਆ ਦੀ ਕਿਸਮ ਚੁਣੋ"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ਮਿਆਰੀ"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ਦਰਮਿਆਨਾ"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"ਜ਼ਿਆਦਾ"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"\'ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ\' \'ਤੇ ਕਲਿੱਕ ਕਰੋ"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ਕੀ ਡੀਵਾਈਸ ਦੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੂੰ ਅਣਬਲਾਕ ਕਰਨਾ ਹੈ?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ਕੀ ਡੀਵਾਈਸ ਦੇ ਕੈਮਰੇ ਨੂੰ ਅਣਬਲਾਕ ਕਰਨਾ ਹੈ?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ਕੀ ਡੀਵਾਈਸ ਦੇ ਕੈਮਰੇ ਅਤੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੂੰ ਅਣਬਲਾਕ ਕਰਨਾ ਹੈ?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"ਕੀ-ਬੋਰਡ ਖਾਕਾ ਬਦਲੋ"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ਜਾਂ"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ਖੋਜ ਪੁੱਛਗਿੱਛ ਕਲੀਅਰ ਕਰੋ"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"ਸ਼ਾਰਟਕੱਟ"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"ਸ਼ਾਰਟਕੱਟਾਂ ਨੂੰ ਖੋਜੋ"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਨਹੀਂ ਮਿਲਿਆ"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"ਸਿਸਟਮ"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant ਖੋਲ੍ਹੋ"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"ਲਾਕ ਸਕ੍ਰੀਨ"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"ਨੋਟ ਲਿਖੋ"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"ਸਿਸਟਮ ਮਲਟੀਟਾਸਕਿੰਗ"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"RHS ਲਈ ਮੌਜੂਦਾ ਐਪ ਨਾਲ ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"LHS ਲਈ ਮੌਜੂਦਾ ਐਪ ਨਾਲ ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"ਮਲਟੀਟਾਸਕਿੰਗ"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"ਸੱਜੇ ਪਾਸੇ ਦਿੱਤੀ ਮੌਜੂਦਾ ਐਪ ਨਾਲ ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"ਖੱਬੇ ਪਾਸੇ ਦਿੱਤੀ ਮੌਜੂਦਾ ਐਪ ਨਾਲ ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਤੋਂ ਪੂਰੀ ਸਕ੍ਰੀਨ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਵੇਲੇ ਸੱਜੇ ਜਾਂ ਹੇਠਾਂ ਮੌਜੂਦ ਐਪ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਵੇਲੇ ਖੱਬੇ ਜਾਂ ਉੱਪਰ ਮੌਜੂਦ ਐਪ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string> diff --git a/packages/SystemUI/res/values-pa/tiles_states_strings.xml b/packages/SystemUI/res/values-pa/tiles_states_strings.xml index afb1e8bb3695..62dc05ad67bb 100644 --- a/packages/SystemUI/res/values-pa/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-pa/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"ਬੰਦ"</item>      <item msgid="5137565285664080143">"ਚਾਲੂ"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"ਉਪਲਬਧ ਨਹੀਂ"</item> +    <item msgid="3079622119444911877">"ਬੰਦ ਹੈ"</item> +    <item msgid="3028994095749238254">"ਚਾਲੂ ਹੈ"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 48262a0de391..6ff18b9319ee 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Zarejestruj problem"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Rozpocznij"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Zatrzymaj"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Raport o błędzie"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Którego aspektu korzystania z urządzenia dotyczył problem?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Wybierz typ problemu"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Nagrywanie ekranu"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardowy"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Średni"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Wysoki"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Urządzenia słuchowe"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Urządzenia słuchowe"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sparuj nowe urządzenie"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknij, aby sparować nowe urządzenie"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokować mikrofon urządzenia?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Odblokować aparat urządzenia?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Odblokować aparat i mikrofon urządzenia?"</string> @@ -670,15 +667,15 @@      <string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez dźwięku i wibracji"</string>      <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Brak dźwięku i wibracji, wyświetlają się niżej w sekcji rozmów"</string>      <string name="notification_channel_summary_default" msgid="777294388712200605">"Mogą włączać dzwonek lub wibracje w zależności od ustawień urządzenia"</string> -    <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Mogą włączyć dzwonek lub wibracje w zależności od ustawień urządzenia. Rozmowy z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> są domyślnie wyświetlane jako dymki."</string> +    <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Mogą włączać dzwonek lub wibracje w zależności od ustawień urządzenia. Rozmowy z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> są domyślnie wyświetlane jako dymki."</string>      <string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Pozwól systemowi decydować, czy o powiadomieniu powinien informować dźwięk czy wibracja"</string>      <string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Stan:</b> zmieniony na Domyślny"</string>      <string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stan:</b> zmieniono na Ciche"</string>      <string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"<b>Stan:</b> podniesiono ważność"</string>      <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Stan:</b> obniżono ważność"</string> -    <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady"</string> -    <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady, jako dymek"</string> -    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady, przerywa działanie trybu Nie przeszkadzać"</string> +    <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Wyświetlają się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady"</string> +    <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Wyświetlają się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady, jako dymek"</string> +    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Wyświetlają się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady, przerywają działanie trybu Nie przeszkadzać"</string>      <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady, jako dymek, przerywa działanie trybu Nie przeszkadzać"</string>      <string name="notification_priority_title" msgid="2079708866333537093">"Priorytetowe"</string>      <string name="no_shortcut" msgid="8257177117568230126">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje funkcji rozmów"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Przełącz układ klawiatury"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"lub"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Wyczyść wyszukiwanie hasło"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Skróty"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Skróty klawiszowe"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Wyszukiwanie skrótów"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nie znaleziono skrótów"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"System"</string> @@ -757,29 +754,29 @@      <string name="keyboard_shortcut_a11y_filter_input" msgid="4589316004510335529">"Pokazuję skróty dotyczące danych wejściowych"</string>      <string name="keyboard_shortcut_a11y_filter_open_apps" msgid="6175417687221004059">"Pokazuję skróty otwierające aplikacje"</string>      <string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"Pokazuję skróty dotyczące bieżącej aplikacji"</string> -    <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Wyświetlanie powiadomień"</string> -    <string name="group_system_full_screenshot" msgid="5742204844232667785">"Robienie zrzutu ekranu"</string> -    <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"Pokazywanie skrótów"</string> -    <string name="group_system_go_back" msgid="2730322046244918816">"Przechodzenie wstecz"</string> -    <string name="group_system_access_home_screen" msgid="4130366993484706483">"Wyświetlanie ekranu głównego"</string> -    <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Wyświetlanie ostatnich aplikacji"</string> -    <string name="group_system_cycle_forward" msgid="5478663965957647805">"Przełączanie się do przodu między ostatnimi aplikacjami"</string> -    <string name="group_system_cycle_back" msgid="8194102916946802902">"Przełączanie się wstecz między ostatnimi aplikacjami"</string> -    <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Otwieranie listy aplikacji"</string> -    <string name="group_system_access_system_settings" msgid="8731721963449070017">"Otwieranie ustawień"</string> -    <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otwieranie asystenta"</string> -    <string name="group_system_lock_screen" msgid="7391191300363416543">"Blokada ekranu"</string> +    <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Wyświetl powiadomienia"</string> +    <string name="group_system_full_screenshot" msgid="5742204844232667785">"Zapisz zrzut ekranu"</string> +    <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"Pokaż skróty"</string> +    <string name="group_system_go_back" msgid="2730322046244918816">"Przejdź wstecz"</string> +    <string name="group_system_access_home_screen" msgid="4130366993484706483">"Wyświetl ekran główny"</string> +    <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Wyświetl ostatnie aplikacje"</string> +    <string name="group_system_cycle_forward" msgid="5478663965957647805">"Przełącz się do przodu między ostatnimi aplikacjami"</string> +    <string name="group_system_cycle_back" msgid="8194102916946802902">"Przełącz się wstecz między ostatnimi aplikacjami"</string> +    <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Otwórz listę aplikacji"</string> +    <string name="group_system_access_system_settings" msgid="8731721963449070017">"Otwórz ustawienia"</string> +    <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otwórz asystenta"</string> +    <string name="group_system_lock_screen" msgid="7391191300363416543">"Zablokuj ekran"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Zanotuj"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Wielozadaniowość w systemie"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Uruchamianie trybu podzielonego ekranu z bieżącą aplikacją po prawej"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Uruchamianie trybu podzielonego ekranu z bieżącą aplikacją po lewej"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Wielozadaniowość"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Podziel ekran z bieżącą aplikacją widoczną po prawej"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Podziel ekran z bieżącą aplikacją widoczną po lewej"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Przełącz podzielony ekran na pełny ekran"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Przełącz się na aplikację po prawej lub poniżej na podzielonym ekranie"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Przełącz się na aplikację po lewej lub powyżej na podzielonym ekranie"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"Podczas podzielonego ekranu: zastępowanie aplikacji"</string>      <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Wprowadzanie"</string> -    <string name="input_switch_input_language_next" msgid="3782155659868227855">"Przełączanie na następny język"</string> -    <string name="input_switch_input_language_previous" msgid="6043341362202336623">"Przełączanie na poprzedni język"</string> +    <string name="input_switch_input_language_next" msgid="3782155659868227855">"Przełącz na następny język"</string> +    <string name="input_switch_input_language_previous" msgid="6043341362202336623">"Przełącz na poprzedni język"</string>      <string name="input_access_emoji" msgid="8105642858900406351">"Otwieranie emotikonów"</string>      <string name="input_access_voice_typing" msgid="7291201476395326141">"Otwieranie pisania głosowego"</string>      <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Aplikacje"</string> diff --git a/packages/SystemUI/res/values-pl/tiles_states_strings.xml b/packages/SystemUI/res/values-pl/tiles_states_strings.xml index 5d1c02e1bc5f..5aa719f2ea75 100644 --- a/packages/SystemUI/res/values-pl/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-pl/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Wyłączono"</item>      <item msgid="5137565285664080143">"Włączono"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Niedostępne"</item> +    <item msgid="3079622119444911877">"Wyłączono"</item> +    <item msgid="3028994095749238254">"Włączone"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 04bdf14eac78..4d8156b6fa37 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Problema na gravação"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Parar"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da sua experiência no dispositivo foi afetada?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecionar tipo de problema"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de tela"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Padrão"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Médio"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparelhos auditivos"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparelhos auditivos"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parear novo dispositivo"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmera do dispositivo?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Desbloquear a câmera e o microfone do dispositivo?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Alterar layout do teclado"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Limpar a consulta de pesquisa"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Atalhos"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Atalhos do teclado"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Atalhos de pesquisa"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nenhum atalho encontrado"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistema"</string> @@ -769,10 +767,10 @@      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Abrir configurações"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir o Google Assistente"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Tela de bloqueio"</string> -    <string name="group_system_quick_memo" msgid="3764560265935722903">"Crie uma nota"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitarefa do sistema"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Usar a tela dividida com o app atual à direita"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Usar a tela dividida com o app atual à esquerda"</string> +    <string name="group_system_quick_memo" msgid="3764560265935722903">"Criar nota"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitarefas"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Usar a tela dividida com o aplicativo atual à direita"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Usar a tela dividida com o app atual à esquerda"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Mudar da tela dividida para a tela cheia"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mude para o app à direita ou abaixo ao usar a tela dividida"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mude para o app à esquerda ou acima ao usar a tela dividida"</string> @@ -830,7 +828,7 @@      <string name="left_icon" msgid="5036278531966897006">"Ícone à esquerda"</string>      <string name="right_icon" msgid="1103955040645237425">"Ícone à direita"</string>      <string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantenha pressionado e arraste para adicionar blocos"</string> -    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Para reorganizar, toque no bloco sem soltar e arraste."</string> +    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Para reorganizar, toque no bloco sem soltar e arraste"</string>      <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arraste aqui para remover"</string>      <string name="drag_to_remove_disabled" msgid="933046987838658850">"É preciso haver pelo menos <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> blocos"</string>      <string name="qs_edit" msgid="5583565172803472437">"Editar"</string> @@ -1297,7 +1295,7 @@      <string name="privacy_dialog_active_call_usage" msgid="7858746847946397562">"Em uso pela ligação telefônica"</string>      <string name="privacy_dialog_recent_call_usage" msgid="1214810644978167344">"Usado recentemente em uma ligação telefônica"</string>      <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"Em uso pelo app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> -    <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Usado recentemente pelo app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> +    <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Uso recente pelo app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"Em uso pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Usado recentemente pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Em uso pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml index 453d8139bd48..3526c77d1e24 100644 --- a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Desativado"</item>      <item msgid="5137565285664080143">"Ativado"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Indisponível"</item> +    <item msgid="3079622119444911877">"Desativar"</item> +    <item msgid="3028994095749238254">"Ativar"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index b6270906eb7f..3c7578f5e756 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Registar problema"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Parar"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Relatório de erro"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da experiência do disposit. foi afetada?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecione o tipo de problema"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de ecrã"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Médio"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sincronizar novo dispositivo"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para sincronizar um novo dispositivo"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmara do dispositivo?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Quer desbloquear a câmara e o microfone?"</string> @@ -667,7 +665,7 @@      <string name="notification_alert_title" msgid="3656229781017543655">"Predefinição"</string>      <string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>      <string name="notification_channel_summary_low" msgid="4860617986908931158">"Sem som ou vibração"</string> -    <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sem som ou vibração e aparece na parte inferior na secção de conversas."</string> +    <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sem som ou vibração e aparece na parte inferior na secção de conversas"</string>      <string name="notification_channel_summary_default" msgid="777294388712200605">"Pode tocar ou vibrar com base nas definições do dispositivo"</string>      <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Pode tocar ou vibrar com base nas definições do dispositivo. As conversas da app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecem como um balão por predefinição."</string>      <string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Faça com que o sistema determine se esta notificação deve emitir um som ou uma vibração"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Alterar esquema de teclado"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Limpar consulta de pesquisa"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Atalhos"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Atalhos de teclado"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Pesquise atalhos"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nenhum atalho encontrado"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistema"</string> @@ -768,12 +766,12 @@      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Abrir definições"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir Assistente"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Ecrã de bloqueio"</string> -    <string name="group_system_quick_memo" msgid="3764560265935722903">"Tire uma nota"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Execução de várias tarefas em simultâneo no sistema"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Aceder ao ecrã dividido com a app atual para RHS"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Aceder ao ecrã dividido com a app atual para LHS"</string> +    <string name="group_system_quick_memo" msgid="3764560265935722903">"Tire notas"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Execução de várias tarefas em simultâneo"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Use o ecrã dividido com a app atual à direita"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Use o ecrã dividido com a app atual à esquerda"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Mudar de ecrã dividido para ecrã inteiro"</string> -    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mude para a app à direita ou abaixo enquanto usa o ecrã dividido"</string> +    <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mudar para a app à direita ou abaixo enquanto usa o ecrã dividido"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mude para a app à esquerda ou acima enquanto usa o ecrã dividido"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"Durante o ecrã dividido: substituir uma app por outra"</string>      <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Entrada"</string> @@ -798,7 +796,7 @@      <string name="accessibility_long_click_tile" msgid="210472753156768705">"Abrir as definições"</string>      <string name="accessibility_status_bar_headphones" msgid="1304082414912647414">"Auscultadores ligados"</string>      <string name="accessibility_status_bar_headset" msgid="2699275863720926104">"Auscultadores com microfone integrado ligados"</string> -    <string name="data_saver" msgid="3484013368530820763">"Poup. dados"</string> +    <string name="data_saver" msgid="3484013368530820763">"Poupança de dados"</string>      <string name="accessibility_data_saver_on" msgid="5394743820189757731">"Poupança de dados ativada"</string>      <string name="switch_bar_on" msgid="1770868129120096114">"Ativado"</string>      <string name="switch_bar_off" msgid="5669805115416379556">"Desativado"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 04bdf14eac78..4d8156b6fa37 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Problema na gravação"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Iniciar"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Parar"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da sua experiência no dispositivo foi afetada?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecionar tipo de problema"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de tela"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Padrão"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Médio"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Alto"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparelhos auditivos"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparelhos auditivos"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parear novo dispositivo"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Desbloquear a câmera do dispositivo?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Desbloquear a câmera e o microfone do dispositivo?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Alterar layout do teclado"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ou"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Limpar a consulta de pesquisa"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Atalhos"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Atalhos do teclado"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Atalhos de pesquisa"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nenhum atalho encontrado"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistema"</string> @@ -769,10 +767,10 @@      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Abrir configurações"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Abrir o Google Assistente"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Tela de bloqueio"</string> -    <string name="group_system_quick_memo" msgid="3764560265935722903">"Crie uma nota"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitarefa do sistema"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Usar a tela dividida com o app atual à direita"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Usar a tela dividida com o app atual à esquerda"</string> +    <string name="group_system_quick_memo" msgid="3764560265935722903">"Criar nota"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitarefas"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Usar a tela dividida com o aplicativo atual à direita"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Usar a tela dividida com o app atual à esquerda"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Mudar da tela dividida para a tela cheia"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Mude para o app à direita ou abaixo ao usar a tela dividida"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Mude para o app à esquerda ou acima ao usar a tela dividida"</string> @@ -830,7 +828,7 @@      <string name="left_icon" msgid="5036278531966897006">"Ícone à esquerda"</string>      <string name="right_icon" msgid="1103955040645237425">"Ícone à direita"</string>      <string name="drag_to_add_tiles" msgid="8933270127508303672">"Mantenha pressionado e arraste para adicionar blocos"</string> -    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Para reorganizar, toque no bloco sem soltar e arraste."</string> +    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Para reorganizar, toque no bloco sem soltar e arraste"</string>      <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arraste aqui para remover"</string>      <string name="drag_to_remove_disabled" msgid="933046987838658850">"É preciso haver pelo menos <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> blocos"</string>      <string name="qs_edit" msgid="5583565172803472437">"Editar"</string> @@ -1297,7 +1295,7 @@      <string name="privacy_dialog_active_call_usage" msgid="7858746847946397562">"Em uso pela ligação telefônica"</string>      <string name="privacy_dialog_recent_call_usage" msgid="1214810644978167344">"Usado recentemente em uma ligação telefônica"</string>      <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"Em uso pelo app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> -    <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Usado recentemente pelo app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> +    <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Uso recente pelo app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"Em uso pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Usado recentemente pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Em uso pelo app <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-pt/tiles_states_strings.xml b/packages/SystemUI/res/values-pt/tiles_states_strings.xml index 453d8139bd48..3526c77d1e24 100644 --- a/packages/SystemUI/res/values-pt/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-pt/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Desativado"</item>      <item msgid="5137565285664080143">"Ativado"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Indisponível"</item> +    <item msgid="3079622119444911877">"Desativar"</item> +    <item msgid="3028994095749238254">"Ativar"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 7d65f96a493a..172ee12ad9c9 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Problemă legată de înregistrare"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Începe"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Oprește"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ce parte a experienței pe dispozitiv a fost afectată?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selectează tipul problemei"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Înregistrarea ecranului"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Mediu"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Ridicat"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparate auditive"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparate auditive"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Asociază un nou dispozitiv"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Dă clic pentru a asocia un nou dispozitiv"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblochezi microfonul dispozitivului?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblochezi camera dispozitivului?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblochezi camera și microfonul dispozitivului?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Schimbă aspectul tastaturii"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"sau"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Șterge termenul de căutare"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Comenzi rapide"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Comenzi rapide de la tastatură"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Caută comenzi rapide"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nu există comenzi rapide"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistem"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Deschide Asistentul"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Ecranul de blocare"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Creează o notă"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitasking pe sistem"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Accesează ecranul împărțit cu aplicația actuală în dreapta"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Accesează ecranul împărțit cu aplicația actuală în stânga"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Folosește ecranul împărțit cu aplicația curentă în dreapta"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Folosește ecranul împărțit cu aplicația curentă în stânga"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Comută de la ecranul împărțit la ecranul complet"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Treci la aplicația din dreapta sau de mai jos cu ecranul împărțit"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Treci la aplicația din stânga sau de mai sus cu ecranul împărțit"</string> diff --git a/packages/SystemUI/res/values-ro/tiles_states_strings.xml b/packages/SystemUI/res/values-ro/tiles_states_strings.xml index 5b9661884709..a68f1408dd83 100644 --- a/packages/SystemUI/res/values-ro/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ro/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Dezactivat"</item>      <item msgid="5137565285664080143">"Activat"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Indisponibil"</item> +    <item msgid="3079622119444911877">"Dezactivat"</item> +    <item msgid="3028994095749238254">"Activat"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 5e47464dc924..249be7fec750 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Запись неисправности"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Начать"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Остановить"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Отчет об ошибке"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"С чем связана проблема, с которой вы столкнулись?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Выберите тип проблемы"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запись экрана"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандартная"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Средняя"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Высокая"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слуховые аппараты"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слуховые аппараты"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Подключить новое устройство"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Нажмите, чтобы подключить новое устройство"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Разблокировать микрофон устройства?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Разблокировать камеру устройства?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Разблокировать камеру и микрофон устройства?"</string> @@ -678,7 +675,7 @@      <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>Статус:</b> уровень важности понижен"</string>      <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Появляется в верхней части уведомлений о сообщениях, а также в качестве фото профиля на заблокированном экране"</string>      <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Появляется в верхней части уведомлений о сообщениях, в виде всплывающего чата, а также в качестве фото профиля на заблокированном экране."</string> -    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Появляется в верхней части уведомлений о сообщениях, а также в качестве фото профиля на заблокированном экране, прерывает режим \"Не беспокоить\"."</string> +    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Появляется в верхней части уведомлений о сообщениях, а также в виде фото профиля на заблокированном экране, прерывает режим \"Не беспокоить\"."</string>      <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Появляется в верхней части уведомлений о сообщениях, в виде всплывающего чата, а также в качестве фото профиля на заблокированном экране, прерывает режим \"Не беспокоить\"."</string>      <string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>      <string name="no_shortcut" msgid="8257177117568230126">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает функции разговоров."</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Переключение раскладки"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"или"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Удалить поисковый запрос"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Сочетания клавиш"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Быстрые клавиши"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Поиск сочетаний клавиш"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Нет сочетаний клавиш."</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Система"</string> @@ -770,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Открыть Ассистента"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Заблокировать экран"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Создать заметку"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Режим многозадачности"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Включить разделение экрана с текущим приложением справа"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Включить разделение экрана с текущим приложением слева"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Многозадачность"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Разделить экран и поместить это приложение справа"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Разделить экран и поместить это приложение слева"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Изменить режим разделения экрана на полноэкранный режим"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Перейти к приложению справа или внизу на разделенном экране"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Перейти к приложению слева или вверху на разделенном экране"</string> @@ -783,7 +780,7 @@      <string name="input_access_emoji" msgid="8105642858900406351">"Открыть список эмодзи"</string>      <string name="input_access_voice_typing" msgid="7291201476395326141">"Активировать голосовой ввод"</string>      <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Приложения"</string> -    <string name="keyboard_shortcut_group_applications_assist" msgid="6772492350416591448">"Открыть Ассистента"</string> +    <string name="keyboard_shortcut_group_applications_assist" msgid="6772492350416591448">"Ассистент"</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_email" msgid="7852376788894975192">"Эл. почта"</string> @@ -1123,8 +1120,8 @@      <string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер сборки"</string>      <string name="build_number_copy_toast" msgid="877720921605503046">"Номер сборки скопирован в буфер обмена."</string>      <string name="basic_status" msgid="2315371112182658176">"Открытый чат"</string> -    <string name="select_conversation_title" msgid="6716364118095089519">"Виджеты чатов"</string> -    <string name="select_conversation_text" msgid="3376048251434956013">"Нажмите на чат, чтобы добавить его на главный экран"</string> +    <string name="select_conversation_title" msgid="6716364118095089519">"Виджеты разговоров"</string> +    <string name="select_conversation_text" msgid="3376048251434956013">"Нажмите на разговор, чтобы добавить его на главный экран"</string>      <string name="no_conversations_text" msgid="5354115541282395015">"Здесь появятся ваши недавние разговоры."</string>      <string name="priority_conversations" msgid="3967482288896653039">"Важные разговоры"</string>      <string name="recent_conversations" msgid="8531874684782574622">"Недавние разговоры"</string> @@ -1291,7 +1288,7 @@      <string name="privacy_dialog_expand_action" msgid="9129262348628331377">"Развернуть и показать параметры"</string>      <string name="privacy_dialog_collapse_action" msgid="277419962019466347">"Свернуть"</string>      <string name="privacy_dialog_close_app_button" msgid="8006250171305878606">"Закрыть это приложение"</string> -    <string name="privacy_dialog_close_app_message" msgid="1316408652526310985">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" закрыто."</string> +    <string name="privacy_dialog_close_app_message" msgid="1316408652526310985">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" закрыто"</string>      <string name="privacy_dialog_manage_service" msgid="8320590856621823604">"Настроить сервис"</string>      <string name="privacy_dialog_manage_permissions" msgid="2543451567190470413">"Настроить доступ"</string>      <string name="privacy_dialog_active_call_usage" msgid="7858746847946397562">"Сейчас используется для телефонного звонка"</string> diff --git a/packages/SystemUI/res/values-ru/tiles_states_strings.xml b/packages/SystemUI/res/values-ru/tiles_states_strings.xml index cdc4a982dff4..592937c7b9f6 100644 --- a/packages/SystemUI/res/values-ru/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ru/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Выключено"</item>      <item msgid="5137565285664080143">"Включено"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Недоступны"</item> +    <item msgid="3079622119444911877">"Отключены"</item> +    <item msgid="3028994095749238254">"Включены"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 5eea02c2e702..90c87f06be68 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"පටිගත කිරීමේ ගැටලුව"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"අරඹන්න"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"නවත්වන්න"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ඔබේ උපාංග අත්දැකීමේ කුමන කොටසට බලපෑවේ ද?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ගැටලු වර්ගය තෝරන්න"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"තිර පටිගත කිරීම"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"සම්මත"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"මධ්යම"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"ඉහළ"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ශ්රවණ උපාංග"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ශ්රවණ උපාංග"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"නව උපාංගය යුගල කරන්න"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"නව උපාංගය යුගල කිරීමට ක්ලික් කරන්න"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"උපාංග මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"උපාංග කැමරාව අවහිර කිරීම ඉවත් කරන්නද?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"උපාංග කැමරාව සහ මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"යතුරුපුවරු පිරිසැලසුම මාරු කරන්න"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"හෝ"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"සෙවීම් විමසුම හිස් කරන්න"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"කෙටිමං"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"යතුරු පුවරු කෙටිමං"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"කෙටිමං සොයන්න"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"කෙටිමං හමු නොවුණි"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"පද්ධතිය"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"සහායක විවෘත කරන්න"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"තිරය අගුළු දමන්න"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"සටහනක් ගන්න"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"පද්ධති බහු කාර්ය"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"RHS වෙත වත්මන් යෙදුම සමග බෙදුම් තිරයට ඇතුළු වන්න"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"LHS වෙත වත්මන් යෙදුම සමග බෙදුම් තිරයට ඇතුළු වන්න"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"බහුකාර්ය"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"දකුණේ වත්මන් යෙදුම සමග බෙදීම් තිරය භාවිතා කරන්න"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"වම් පැත්තේ වත්මන් යෙදුම සමග බෙදීම් තිරය භාවිතා කරන්න"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"බෙදුම් තිරයේ සිට පූර්ණ තිරයට මාරු වන්න"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"බෙදුම් තිරය භාවිත කරන අතරතුර දකුණේ හෝ පහළින් ඇති යෙදුමට මාරු වන්න"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"බෙදුම් තිරය භාවිත කරන අතරතුර වමේ හෝ ඉහළ ඇති යෙදුමට මාරු වන්න"</string> diff --git a/packages/SystemUI/res/values-si/tiles_states_strings.xml b/packages/SystemUI/res/values-si/tiles_states_strings.xml index e7e90341ecb9..681f3d52bc09 100644 --- a/packages/SystemUI/res/values-si/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-si/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"ක්රියාවිරහිතයි"</item>      <item msgid="5137565285664080143">"ක්රියාත්මකයි"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"නොමැත"</item> +    <item msgid="3079622119444911877">"ක්රියාවිරහිතයි"</item> +    <item msgid="3028994095749238254">"ක්රියාත්මකයි"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index ea1a8f860a1e..7751c6d09d34 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Problém s nahrávaním"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Začnite"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Zastavte"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Hlásenie chyby"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Čo v zariadení bolo ovplyvnené?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vyberte typ problému"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rekordér obrazovky"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Stredný"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Vysoký"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Načúvacie zariadenia"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Načúvacie zariadenia"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Párovanie nového zariadenia"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zariadenie"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Chcete odblokovať mikrofón zariadenia?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Chcete odblokovať kameru zariadenia?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Chcete odblokovať fotoaparát a mikrofón zariadenia?"</string> @@ -679,7 +677,7 @@      <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Zobrazuje sa ako bublina v hornej časti upozornení konverzácie a profilová fotka na uzamknutej obrazovke"</string>      <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Zobrazuje sa v hornej časti upozornení konverzácie a ako profilová fotka na uzamknutej obrazovke, preruší režim bez vyrušení"</string>      <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Zobrazuje sa ako bublina v hornej časti upozornení konverzácie a profilová fotka na uzamknutej obrazovke, preruší režim bez vyrušení"</string> -    <string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string> +    <string name="notification_priority_title" msgid="2079708866333537093">"Prioritné"</string>      <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje funkcie konverzácie"</string>      <string name="notification_unblockable_desc" msgid="2073030886006190804">"Tieto upozornenia sa nedajú upraviť."</string>      <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Upozornenia na hovory sa nedajú upraviť."</string> @@ -744,12 +742,12 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Prepnúť rozloženie klávesnice"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"alebo"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Vymazať vyhľadávací dopyt"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Skratky"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Klávesové skratky"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Hľadajte skratky"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nenašli sa žiadne skratky"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Systém"</string>      <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"Vstup"</string> -    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Otvorenie apl."</string> +    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Otvorené aplikácie"</string>      <string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"Aktuálna aplik."</string>      <string name="keyboard_shortcut_a11y_show_search_results" msgid="2865241062981833705">"Zobrazujú sa výsledky vyhľadávania"</string>      <string name="keyboard_shortcut_a11y_filter_system" msgid="7744143131119370483">"Zobrazujú sa skratky systému"</string> @@ -767,11 +765,11 @@      <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Otvorenie zoznamu aplikácií"</string>      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Otvorenie nastavení"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Otvorenie Asistenta"</string> -    <string name="group_system_lock_screen" msgid="7391191300363416543">"Zamknúť obrazovku"</string> +    <string name="group_system_lock_screen" msgid="7391191300363416543">"Uzamknutie obrazovky"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Napísanie poznámky"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitasking systému"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Rozdelenie obrazovky s aktuálnou aplikáciou vpravo"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Rozdelenie obrazovky s aktuálnou aplikáciou vľavo"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multitasking"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Použite rozdelenú obrazovku s aktuálnou aplikáciou vpravo"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Použite rozdelenú obrazovku s aktuálnou aplikáciou vľavo"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Prepnutie rozdelenej obrazovky na celú"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Prechod na aplikáciu vpravo alebo dole pri rozdelenej obrazovke"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Prechod na aplikáciu vľavo alebo hore pri rozdelenej obrazovke"</string> @@ -1268,7 +1266,7 @@      <string name="install_dialer_on_work_profile_action" msgid="2014659711597862506">"Inštalovať pracovnú telefónnu aplikáciu"</string>      <string name="call_from_work_profile_close" msgid="5830072964434474143">"Zrušiť"</string>      <string name="lock_screen_settings" msgid="6152703934761402399">"Prispôsobiť uzamknutú obrazovku"</string> -    <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Ak chcete prispôsobiť uzamknutú obrazovku, odomknite ju"</string> +    <string name="keyguard_unlock_to_customize_ls" msgid="2068542308086253819">"Uzamknutú obrazovku môžete prispôsobiť po odomknutí"</string>      <string name="wifi_unavailable_dream_overlay_content_description" msgid="2024166212194640100">"Wi‑Fi nie je k dispozícii"</string>      <string name="camera_blocked_dream_overlay_content_description" msgid="4074759493559418130">"Kamera je blokovaná"</string>      <string name="camera_and_microphone_blocked_dream_overlay_content_description" msgid="7891078093416249764">"Kamera a mikrofón sú blokované"</string> @@ -1284,7 +1282,7 @@      <string name="dismiss_dialog" msgid="2195508495854675882">"Zavrieť"</string>      <string name="connected_display_icon_desc" msgid="6373560639989971997">"Obrazovka je pripojená"</string>      <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofón a fotoaparát"</string> -    <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedávne využitie aplikácie"</string> +    <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedávne použitie aplikáciami"</string>      <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Zobraziť nedávny prístup"</string>      <string name="privacy_dialog_done_button" msgid="4504330708531434263">"Hotovo"</string>      <string name="privacy_dialog_expand_action" msgid="9129262348628331377">"Rozbaliť a zobraziť možnosti"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 514d2f9d42d1..53be1bde3369 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Snemanje težave"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Začetek"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Ustavitev"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Poročilo o napakah"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na kateri del izkušnje z napravo je to vplivalo?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Izberite vrsto težave"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snemanje zaslona"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standardni"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednji"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visok"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni pripomočki"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni pripomočki"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Seznanitev nove naprave"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite za seznanitev nove naprave"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite odblokirati mikrofon v napravi?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Želite odblokirati fotoaparat v napravi?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Želite odblokirati fotoaparat in mikrofon v napravi?"</string> @@ -745,12 +742,12 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Preklop postavitve tipkovnice"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ali"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Čiščenje iskalne poizvedbe"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Bližnjice"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Bližnjične tipke"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Iskanje bližnjic"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Ni najdenih bližnjic."</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistem"</string>      <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"Vnos"</string> -    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Odprte aplikacije"</string> +    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"Odpiranje aplikacij"</string>      <string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"Trenutna aplikacija"</string>      <string name="keyboard_shortcut_a11y_show_search_results" msgid="2865241062981833705">"Prikaz rezultatov iskanja"</string>      <string name="keyboard_shortcut_a11y_filter_system" msgid="7744143131119370483">"Prikaz sistemskih bližnjic"</string> @@ -770,14 +767,14 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Odpiranje Pomočnika"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Zaklepanje zaslona"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Ustvarjanje zapiska"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Sistemska večopravilnost"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Vklop razdeljenega zaslona s trenutno aplikacijo na desni"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Vklop razdeljenega zaslona s trenutno aplikacijo na levi"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Večopravilnost"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Uporaba razdeljenega zaslona s trenutno aplikacijo na desni"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Uporaba razdeljenega zaslona s trenutno aplikacijo na levi"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Preklop iz razdeljenega zaslona v celozaslonski način"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Preklop na aplikacijo desno ali spodaj med uporabo razdeljenega zaslona"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Preklop na aplikacijo levo ali zgoraj med uporabo razdeljenega zaslona"</string>      <string name="system_multitasking_replace" msgid="7410071959803642125">"Pri razdeljenem zaslonu: medsebojna zamenjava aplikacij"</string> -    <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Vnosna naprava"</string> +    <string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Vnos"</string>      <string name="input_switch_input_language_next" msgid="3782155659868227855">"Preklop na naslednji jezik"</string>      <string name="input_switch_input_language_previous" msgid="6043341362202336623">"Preklop na prejšnji jezik"</string>      <string name="input_access_emoji" msgid="8105642858900406351">"Dostop do emodžijev"</string> diff --git a/packages/SystemUI/res/values-sl/tiles_states_strings.xml b/packages/SystemUI/res/values-sl/tiles_states_strings.xml index 9f9175e7bd0e..5f60ffdaebf7 100644 --- a/packages/SystemUI/res/values-sl/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-sl/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Izklopljeno"</item>      <item msgid="5137565285664080143">"Vklopljeno"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Ni na voljo"</item> +    <item msgid="3079622119444911877">"Izklopljeno"</item> +    <item msgid="3028994095749238254">"Vklopljeno"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index c13d76b974b7..7e75984a4c35 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Regjistro problemin"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Nis"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Ndalo"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cila pjesë e përvojës me pajisjen është prekur?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Zgjidh llojin e problemit"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Regjistrim i ekranit"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Mesatar"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"I lartë"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Pajisje ndihmëse për dëgjimin"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Pajisjet e dëgjimit"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Çifto pajisje të re"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliko për të çiftuar një pajisje të re"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Të zhbllokohet mikrofoni i pajisjes?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Të zhbllokohet kamera e pajisjes?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Të zhbllokohen kamera dhe mikrofoni i pajisjes?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Ndërro strukturën e tastierës"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"ose"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Pastro pyetjen e kërkimit"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Shkurtoret"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Shkurtoret e tastierës"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Kërko shkurtoret"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Nuk u gjet shkurtore"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistemi"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Hap \"Asistentin\""</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Ekrani i kyçjes"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Mbaj një shënim"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Kryerja e shumë detyrave nga sistemi"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Hyr në ekranin e ndarë me aplikacionin aktual në anën e djathtë"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Hyr në ekranin e ndarë me aplikacionin aktual në anën e majtë"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Kryerja e shumë detyrave"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Përdor ekranin e ndarë me aplikacionin aktual në të djathtë"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Përdor ekranin e ndarë me aplikacionin aktual në të majtë"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Kalo nga ekrani i ndarë në ekranin e plotë"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Kalo tek aplikacioni djathtas ose poshtë kur përdor ekranin e ndarë"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Kalo tek aplikacioni në të majtë ose sipër kur përdor ekranin e ndarë"</string> diff --git a/packages/SystemUI/res/values-sq/tiles_states_strings.xml b/packages/SystemUI/res/values-sq/tiles_states_strings.xml index aa4832d62b43..9b5032eecbd8 100644 --- a/packages/SystemUI/res/values-sq/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-sq/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Joaktive"</item>      <item msgid="5137565285664080143">"Aktive"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Nuk ofrohen"</item> +    <item msgid="3079622119444911877">"Joaktive"</item> +    <item msgid="3028994095749238254">"Aktive"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index bc6642af913a..2b1882dbcf64 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Евидентирајте проблем"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Покрени"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Заустави"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Извештај о грешци"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"На који део доживљаја на уређају је ово утицало?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изаберите тип проблема"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Снимање екрана"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Средње"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Високо"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слушни апарати"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слушни апарати"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Упари нови уређај"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликните да бисте упарили нов уређај"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Желите да одблокирате микрофон уређаја?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Желите да одблокирате камеру уређаја?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Желите да одблокирате камеру и микрофон уређаја?"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Промени распоред тастатуре"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"или"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Обриши упит за претрагу"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Пречице"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Тастерске пречице"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Претражите пречице"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Нису пронађене пречице"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Систем"</string> @@ -768,10 +766,10 @@      <string name="group_system_access_system_settings" msgid="8731721963449070017">"Отвори подешавања"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Отвори помоћника"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Закључавање екрана"</string> -    <string name="group_system_quick_memo" msgid="3764560265935722903">"Направите белешку"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Обављање више задатака система истовремено"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Покрени подељени екран за актуелну апликацију на десној страни"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Покрени подељени екран за актуелну апликацију на левој страни"</string> +    <string name="group_system_quick_memo" msgid="3764560265935722903">"Направи белешку"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Обављање више задатака истовремено"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Користите подељени екран са актуелном апликацијом с десне стране"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Користите подељени екран са актуелном апликацијом с леве стране"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Пређи са подељеног екрана на цео екран"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Пређите у апликацију здесна или испод док користите подељени екран"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Пређите у апликацију слева или изнад док користите подељени екран"</string> @@ -1295,9 +1293,9 @@      <string name="privacy_dialog_manage_permissions" msgid="2543451567190470413">"Управљај приступом"</string>      <string name="privacy_dialog_active_call_usage" msgid="7858746847946397562">"Користи телефонски позив"</string>      <string name="privacy_dialog_recent_call_usage" msgid="1214810644978167344">"Недавно коришћено у телефонском позиву"</string> -    <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"Користе <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> +    <string name="privacy_dialog_active_app_usage" msgid="631997836335929880">"Користи <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>      <string name="privacy_dialog_recent_app_usage" msgid="4883417856848222450">"Недавно користила апликација <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> -    <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"Користе <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string> +    <string name="privacy_dialog_active_app_usage_1" msgid="9047570143069220911">"Користи <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_recent_app_usage_1" msgid="2551340497722370109">"Недавно користила апликација <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g>)"</string>      <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"Користе <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string>      <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"Недавно користила апликација <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 15c370c6b73e..f075c8c94cb7 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Registrera problem"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Starta"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Stoppa"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Vilken enhetsupplevelse påverkades?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Välj problemtyp"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skärminspelning"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Standard"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Medelhög"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Hög"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hörhjälpmedel"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hörhjälpmedel"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parkoppla en ny enhet"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicka för att parkoppla en ny enhet"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vill du återaktivera enhetens mikrofon?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vill du återaktivera enhetens kamera?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vill du återaktivera enhetens kamera och mikrofon?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Byt tangentbordslayout"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"eller"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Rensa sökfråga"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Kortkommandon"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Kortkommandon"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Sök efter kortkommando"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Inga resultat"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"System"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Öppna assistenten"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Lås skärmen"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Anteckna"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Systemets multikörning"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Öppna delad skärm med aktuell app till höger"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Öppna delad skärm med aktuell app till vänster"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multikörning"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Anänd delad skärm med den aktuella appen till höger"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Använd delad skärm med den aktuella appen till vänster"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Byt mellan delad skärm och helskärm"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Byt till appen till vänster eller nedanför när du använder delad skärm"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Byt till appen till vänster eller ovanför när du använder delad skärm"</string> diff --git a/packages/SystemUI/res/values-sv/tiles_states_strings.xml b/packages/SystemUI/res/values-sv/tiles_states_strings.xml index 522538a79c07..cf49f8db2606 100644 --- a/packages/SystemUI/res/values-sv/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-sv/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Av"</item>      <item msgid="5137565285664080143">"På"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Inte tillgänglig"</item> +    <item msgid="3079622119444911877">"Av"</item> +    <item msgid="3028994095749238254">"På"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 41bac7b4fbb7..102926b0246c 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Hitilafu ya Kurekodi"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Anza"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Simamisha"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Ripoti ya Hitilafu"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ni sehemu gani ya matumizi ya kifaa iliathiriwa?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Chagua aina ya tatizo"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rekodi ya skrini"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Wastani"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Juu"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Vifaa vya kusikilizia"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Vifaa vya kusikilizia"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Unganisha kifaa kipya"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Bofya ili uunganishe kifaa kipya"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Ungependa kuwacha kuzuia maikrofoni ya kifaa?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Ungependa kuacha kuzuia kamera ya kifaa?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Ungependa kuwacha kuzuia kamera na maikrofoni ya kifaa?"</string> @@ -636,7 +634,7 @@      <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Fungua ili utumie"</string>      <string name="wallet_error_generic" msgid="257704570182963611">"Hitilafu imetokea wakati wa kuleta kadi zako, tafadhali jaribu tena baadaye"</string>      <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Mipangilio ya kufunga skrini"</string> -    <string name="qr_code_scanner_title" msgid="1938155688725760702">"Kichanganuzi cha msimbo wa QR"</string> +    <string name="qr_code_scanner_title" msgid="1938155688725760702">"Kichanganuzi cha QR"</string>      <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Inasasisha"</string>      <string name="status_bar_work" msgid="5238641949837091056">"Wasifu wa kazini"</string>      <string name="status_bar_airplane" msgid="4848702508684541009">"Hali ya ndegeni"</string> @@ -719,7 +717,7 @@      <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string>      <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string>      <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> -    <string name="keyboard_key_backspace" msgid="4095278312039628074">"Nafasinyuma"</string> +    <string name="keyboard_key_backspace" msgid="4095278312039628074">"Backspace"</string>      <string name="keyboard_key_media_play_pause" msgid="8389984232732277478">"Cheza/Sitisha"</string>      <string name="keyboard_key_media_stop" msgid="1509943745250377699">"Simamisha"</string>      <string name="keyboard_key_media_next" msgid="8502476691227914952">"Inayofuata"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Badili mkao wa kibodi"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"au"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Futa hoja ya utafutaji"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Njia za mkato"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Mikato ya Kibodi"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Tafuta njia za mkato"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Hakuna njia za mkato zilizopatikana"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Mfumo"</string> @@ -769,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Fungua programu ya Mratibu wa Google"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Funga skrini"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Andika dokezo"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Majukumu mengi ya mfumo"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Tumia programu kwenye skrini iliyogawanywa upande wa kulia"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Tumia programu kwenye skrini iliyogawanywa upande wa kushoto"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Majukumu mengi"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Tumia hali ya kugawa skrini na programu ya sasa iwe upande wa kulia"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Tumia hali ya kugawa skrini na programu ya sasa iwe upande wa kushoto"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Badilisha kutoka skrini iliyogawanywa utumie skrini nzima"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Badilisha ili uende kwenye programu iliyo kulia au chini unapotumia hali ya kugawa skrini"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Badilisha uende kwenye programu iliyo kushoto au juu unapotumia hali ya kugawa skrini"</string> @@ -1261,7 +1259,7 @@      <string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Chaji ya betri imesalia <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>      <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Unganisha stylus yako kwenye chaja"</string>      <string name="stylus_battery_low" msgid="7134370101603167096">"Chaji ya betri ya Stylus imepungua"</string> -    <string name="video_camera" msgid="7654002575156149298">"Kamera ya kuchukulia video"</string> +    <string name="video_camera" msgid="7654002575156149298">"Kamera ya video"</string>      <string name="call_from_work_profile_title" msgid="5418253516453177114">"Huwezi kupiga simu kwa kutumia programu ya binafsi"</string>      <string name="call_from_work_profile_text" msgid="2856337395968118274">"Shirika lako linakuruhusu upige simu ukitumia programu za kazini pekee"</string>      <string name="call_from_work_profile_action" msgid="2937701298133010724">"Tumia wasifu wa kazini"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 019dddcda6e4..9afa0d1db9eb 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"சிக்கலை ரெக்கார்டு செய்தல்"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"தொடங்குங்கள்"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"நிறுத்துங்கள்"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"சாதன அனுபவத்தின் எந்தப் பகுதி பாதிக்கப்பட்டது?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"சிக்கல் வகையைத் தேர்வுசெய்க"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ஸ்கிரீன் ரெக்கார்டு"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"இயல்புநிலை"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"நடுத்தரம்"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"அதிகம்"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"செவித்துணைக் கருவிகள்"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"செவித்துணைக் கருவிகள்"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"புதிய சாதனத்தை இணை"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"புதிய சாதனத்தை இணைக்க கிளிக் செய்யலாம்"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"சாதனத்தின் மைக்ரோஃபோனுக்கான தடுப்பை நீக்கவா?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"சாதனத்தின் கேமராவுக்கான தடுப்பை நீக்கவா?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"சாதனத்தின் கேமராவுக்கும் மைக்ரோஃபோனுக்குமான தடுப்பை நீக்கவா?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"கீபோர்டு லே அவுட்டை மாற்று"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"அல்லது"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"தேடல் வினவலை அழிக்கும்"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"ஷார்ட்கட்கள்"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"கீபோர்டு ஷார்ட்கட்கள்"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"ஷார்ட்கட்களைத் தேடுக"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"ஷார்ட்கட்கள் எதுவுமில்லை"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"சிஸ்டம்"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistantடைத் திறத்தல்"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"பூட்டுத் திரை"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"குறிப்பெடுத்தல்"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"சிஸ்டம் பல வேலைகளைச் செய்தல்"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"வலதுபுறத்தில் தற்போதைய ஆப்ஸ் தோன்றுமாறு திரைப் பிரிப்பை அமைத்தல்"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"இடதுபுறத்தில் தற்போதைய ஆப்ஸ் தோன்றுமாறு திரைப் பிரிப்பை அமைத்தல்"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"பல வேலைகளைச் செய்தல்"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"தற்போது உள்ள ஆப்ஸுடன் வலதுபுறத்தில் திரைப் பிரிப்பைப் பயன்படுத்துதல்"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"தற்போது உள்ள ஆப்ஸுடன் இடதுபுறத்தில் திரைப் பிரிப்பைப் பயன்படுத்துதல்"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"திரைப் பிரிப்பு பயன்முறையிலிருந்து முழுத்திரைக்கு மாற்றுதல்"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"திரைப் பிரிப்பைப் பயன்படுத்தும்போது வலது/கீழ் உள்ள ஆப்ஸுக்கு மாறுங்கள்"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"திரைப் பிரிப்பைப் பயன்படுத்தும்போது இடது/மேலே உள்ள ஆப்ஸுக்கு மாறுங்கள்"</string> diff --git a/packages/SystemUI/res/values-ta/tiles_states_strings.xml b/packages/SystemUI/res/values-ta/tiles_states_strings.xml index cacde5ebe57b..a3b9538f891c 100644 --- a/packages/SystemUI/res/values-ta/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ta/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"முடக்கப்பட்டுள்ளது"</item>      <item msgid="5137565285664080143">"இயக்கப்பட்டுள்ளது"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"கிடைக்கவில்லை"</item> +    <item msgid="3079622119444911877">"முடக்கப்பட்டுள்ளது"</item> +    <item msgid="3028994095749238254">"இயக்கப்பட்டுள்ளது"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 1b3c5e2e339c..7f82ebf46a71 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -118,7 +118,7 @@      <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"స్క్రీన్, ఆడియో రికార్డింగ్ చేయబడుతున్నాయి"</string>      <string name="screenrecord_taps_label" msgid="1595690528298857649">"స్క్రీన్పై తాకే స్థానాలను చూపండి"</string>      <string name="screenrecord_stop_label" msgid="72699670052087989">"ఆపివేయి"</string> -    <string name="screenrecord_share_label" msgid="5025590804030086930">"షేర్ చేయి"</string> +    <string name="screenrecord_share_label" msgid="5025590804030086930">"షేర్ చేయండి"</string>      <string name="screenrecord_save_title" msgid="1886652605520893850">"స్క్రీన్ రికార్డింగ్ సేవ్ చేయబడింది"</string>      <string name="screenrecord_save_text" msgid="3008973099800840163">"చూడటానికి ట్యాప్ చేయండి"</string>      <string name="screenrecord_save_error" msgid="5862648532560118815">"స్క్రీన్ రికార్డింగ్ను సేవ్ చేయడంలో ఎర్రర్ ఏర్పడింది"</string> @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"సమస్యను రికార్డ్ చేయడం"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"ప్రారంభించండి"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"ఆపివేయండి"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"బగ్ రిపోర్ట్"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"మీ పరికర అనుభవంలో ఏ భాగం ప్రభావితమైంది?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"సమస్య రకాన్ని ఎంచుకోండి"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"స్క్రీన్ రికార్డ్"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"స్టాండర్డ్"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"మధ్యస్థం"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"అధికం"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"వినికిడి పరికరాలు"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"వినికిడి పరికరం"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"కొత్త పరికరాన్ని పెయిర్ చేయడానికి క్లిక్ చేయండి"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"పరికరం మైక్రోఫోన్ను అన్బ్లాక్ చేయమంటారా?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"పరికరంలోని కెమెరాను అన్బ్లాక్ చేయమంటారా?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"పరికరంలోని కెమెరా, మైక్రోఫోన్లను అన్బ్లాక్ చేయమంటారా?"</string> @@ -678,7 +675,7 @@      <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>స్టేటస్:</b> తక్కువ ర్యాంక్కు సర్దుబాటు చేయబడింది"</string>      <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"సంభాషణ నోటిఫికేషన్ల ఎగువున, లాక్ స్క్రీన్లో ప్రొఫైల్ ఫోటోగా చూపిస్తుంది"</string>      <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"సంభాషణ నోటిఫికేషన్ల ఎగువున, లాక్ స్క్రీన్లో ప్రొఫైల్ ఫోటోగా చూపిస్తుంది, బబుల్గా కనిపిస్తుంది"</string> -    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"సంభాషణ నోటిఫికేషన్ల ఎగువున, లాక్ స్క్రీన్లో ప్రొఫైల్ ఫోటోగా చూపిస్తుంది, \'అంతరాయం కలిగించవద్దు\'ను అంతరాయం కలిగిస్తుంది"</string> +    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"సంభాషణ నోటిఫికేషన్ల ఎగువున, అలాగే లాక్ స్క్రీన్లో ప్రొఫైల్ ఫోటో రూపంలో కనబడుతుంది. \'అంతరాయం కలిగించవద్దు\' మోడ్లో ఉన్నా దాన్ని అధిగమిస్తుంది"</string>      <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"సంభాషణ నోటిఫికేషన్ల ఎగువున, లాక్ స్క్రీన్లో ప్రొఫైల్ ఫోటోగా చూపిస్తుంది, బబుల్గా కనిపిస్తుంది, \'అంతరాయం కలిగించవద్దు\'ను అంతరాయం కలిగిస్తుంది"</string>      <string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string>      <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> సంభాషణ ఫీచర్లను సపోర్ట్ చేయదు"</string> @@ -718,7 +715,7 @@      <string name="keyboard_key_dpad_right" msgid="8485763312139820037">"కుడి వైపు బాణం"</string>      <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"మధ్య"</string>      <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> -    <string name="keyboard_key_space" msgid="6980847564173394012">"అంతరం"</string> +    <string name="keyboard_key_space" msgid="6980847564173394012">"Space"</string>      <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string>      <string name="keyboard_key_backspace" msgid="4095278312039628074">"Backspace"</string>      <string name="keyboard_key_media_play_pause" msgid="8389984232732277478">"ప్లే చేయి/పాజ్ చేయి"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"కీబోర్డ్ లేఅవుట్ను మార్చండి"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"లేదా"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"సెర్చ్ క్వెరీని క్లియర్ చేయండి"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"షార్ట్కట్లు"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"కీబోర్డ్ షార్ట్కట్లు"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"షార్ట్కట్స్ సెర్చ్ చేయండి"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"షార్ట్కట్లు ఏవీ లేవు"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"సిస్టమ్"</string> @@ -770,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"అసిస్టెంట్ను తెరవండి"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"లాక్ స్క్రీన్"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"గమనికను రాయండి"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"సిస్టమ్ మల్టీ-టాస్కింగ్"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"RHSకు ప్రస్తుత యాప్తో స్ప్లిట్ స్క్రీన్ను ఎంటర్ చేయండి"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"LHSకు ప్రస్తుత యాప్తో స్ప్లిట్ స్క్రీన్ను ఎంటర్ చేయండి"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"మల్టీ-టాస్కింగ్"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"కుడివైపు ప్రస్తుత యాప్తో స్ప్లిట్ స్క్రీన్ను ఉపయోగించండి"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"ఎడమవైపు ప్రస్తుత యాప్తో స్ప్లిట్ స్క్రీన్ను ఉపయోగించండి"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"స్ప్లిట్ స్క్రీన్ను ఫుల్ స్క్రీన్కు మార్చండి"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"స్ప్లిట్ స్క్రీన్ ఉపయోగిస్తున్నప్పుడు కుడి లేదా పైన యాప్నకు మారండి"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"స్ప్లిట్ స్క్రీన్ ఉపయోగిస్తున్నప్పుడు ఎడమ లేదా పైన యాప్నకు మారండి"</string> @@ -802,7 +799,7 @@      <string name="data_saver" msgid="3484013368530820763">"డేటా సేవర్"</string>      <string name="accessibility_data_saver_on" msgid="5394743820189757731">"డేటా సేవర్ ఆన్లో ఉంది"</string>      <string name="switch_bar_on" msgid="1770868129120096114">"ఆన్"</string> -    <string name="switch_bar_off" msgid="5669805115416379556">"ఆఫ్ చేయి"</string> +    <string name="switch_bar_off" msgid="5669805115416379556">"ఆఫ్"</string>      <string name="tile_unavailable" msgid="3095879009136616920">"అందుబాటులో లేదు"</string>      <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"మరింత తెలుసుకోండి"</string>      <string name="nav_bar" msgid="4642708685386136807">"నావిగేషన్ బార్"</string> @@ -1066,7 +1063,7 @@      <string name="controls_media_button_next" msgid="6662636627525947610">"తర్వాతి ట్రాక్"</string>      <string name="controls_media_button_connecting" msgid="3138354625847598095">"కనెక్ట్ అవుతోంది"</string>      <string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"ప్లే చేయండి"</string> -    <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"<xliff:g id="APP_LABEL">%1$s</xliff:g>ను తెరవండి"</string> +    <string name="controls_media_smartspace_rec_description" msgid="4136242327044070732">"\'<xliff:g id="APP_LABEL">%1$s</xliff:g>\'ను తెరవండి"</string>      <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"<xliff:g id="APP_LABEL">%3$s</xliff:g> నుండి <xliff:g id="ARTIST_NAME">%2$s</xliff:g> పాడిన <xliff:g id="SONG_NAME">%1$s</xliff:g>ను ప్లే చేయండి"</string>      <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"<xliff:g id="APP_LABEL">%2$s</xliff:g> నుండి <xliff:g id="SONG_NAME">%1$s</xliff:g>ను ప్లే చేయండి"</string>      <string name="controls_media_smartspace_rec_header" msgid="5053461390357112834">"మీ కోసం"</string> @@ -1194,7 +1191,7 @@      <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# యాప్ యాక్టివ్గా ఉంది}other{# యాప్లు యాక్టివ్గా ఉన్నాయి}}"</string>      <string name="fgs_dot_content_description" msgid="2865071539464777240">"కొత్త సమాచారం"</string>      <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"యాక్టివ్గా ఉన్న యాప్లు"</string> -    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"మీరు ఈ యాప్లను ఉపయోగించపోయినా కూడా అవి యాక్టివ్గా ఉండి, రన్ అవుతూ ఉంటాయి. దీని వల్ల వాటి ఫంక్షనాలిటీ మెరుగవుతుంది. అయితే ఇది బ్యాటరీ లైఫ్ను కూడా ప్రభావితం చేయవచ్చు."</string> +    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"మీరు ఈ యాప్లను ఉపయోగించపోయినా కూడా అవి యాక్టివ్గా ఉండి, రన్ అవుతూ ఉంటాయి. తద్వారా వాటి ఫంక్షనాలిటీ మెరుగవుతుంది. అయితే దీనివల్ల బ్యాటరీ లైఫ్ ప్రభావితం అయ్యే అవకాశం ఉంది."</string>      <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ఆపివేయండి"</string>      <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ఆపివేయబడింది"</string>      <string name="clipboard_edit_text_done" msgid="4551887727694022409">"పూర్తయింది"</string> @@ -1240,7 +1237,7 @@      <string name="log_access_confirmation_body" msgid="6883031912003112634">"మీ పరికరంలో జరిగే దాన్ని పరికర లాగ్లు రికార్డ్ చేస్తాయి. సమస్యలను కనుగొని, పరిష్కరించడానికి యాప్లు ఈ లాగ్లను ఉపయోగిస్తాయి.\n\nకొన్ని లాగ్లలో గోప్యమైన సమాచారం ఉండవచ్చు, కాబట్టి మీరు విశ్వసించే యాప్లను మాత్రమే అన్ని పరికర లాగ్లను యాక్సెస్ చేయడానికి అనుమతించండి. \n\nఅన్ని పరికర లాగ్లను యాక్సెస్ చేయడానికి మీరు ఈ యాప్ను అనుమతించకపోతే, అది తన స్వంత లాగ్లను ఇప్పటికి యాక్సెస్ చేయగలదు. మీ పరికర తయారీదారు ఇప్పటికీ మీ పరికరంలో కొన్ని లాగ్లు లేదా సమాచారాన్ని యాక్సెస్ చేయగలరు."</string>      <string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"మరింత తెలుసుకోండి"</string>      <string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"<xliff:g id="URL">%s</xliff:g>లో మరింత తెలుసుకోండి"</string> -    <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"<xliff:g id="APPNAME">%1$s</xliff:g>ను తెరవండి"</string> +    <string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"\'<xliff:g id="APPNAME">%1$s</xliff:g>\'ను తెరవండి"</string>      <string name="wallet_quick_affordance_unavailable_install_the_app" msgid="7298552910007208368">"Wallet యాప్ను షార్ట్కట్గా జోడించడానికి, యాప్ ఇన్స్టాల్ చేయబడిందని నిర్ధారించుకోండి"</string>      <string name="wallet_quick_affordance_unavailable_configure_the_app" msgid="4387433357429873258">"Wallet యాప్ను షార్ట్కట్గా జోడించడానికి, కనీసం ఒక కార్డ్ జోడించబడిందని నిర్ధారించుకోండి"</string>      <string name="home_quick_affordance_unavailable_install_the_app" msgid="6187820778998446168">"Home యాప్ను షార్ట్కట్గా జోడించడానికి, యాప్ ఇన్స్టాల్ చేయబడిందని నిర్ధారించుకోండి"</string> diff --git a/packages/SystemUI/res/values-te/tiles_states_strings.xml b/packages/SystemUI/res/values-te/tiles_states_strings.xml index a1ee29f5f724..6584cdd59282 100644 --- a/packages/SystemUI/res/values-te/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-te/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"ఆఫ్లో ఉంది"</item>      <item msgid="5137565285664080143">"ఆన్లో ఉంది"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"అందుబాటులో లేదు"</item> +    <item msgid="3079622119444911877">"ఆఫ్లో ఉంది"</item> +    <item msgid="3028994095749238254">"ఆన్లో ఉంది"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index e8d376dba34c..dece9c1ffeb5 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -119,7 +119,7 @@      <string name="screenrecord_taps_label" msgid="1595690528298857649">"แสดงการแตะบนหน้าจอ"</string>      <string name="screenrecord_stop_label" msgid="72699670052087989">"หยุด"</string>      <string name="screenrecord_share_label" msgid="5025590804030086930">"แชร์"</string> -    <string name="screenrecord_save_title" msgid="1886652605520893850">"บันทึกการบันทึกหน้าจอแล้ว"</string> +    <string name="screenrecord_save_title" msgid="1886652605520893850">"จัดเก็บการบันทึกหน้าจอไว้แล้ว"</string>      <string name="screenrecord_save_text" msgid="3008973099800840163">"แตะเพื่อดู"</string>      <string name="screenrecord_save_error" msgid="5862648532560118815">"เกิดข้อผิดพลาดในการบันทึกหน้าจอ"</string>      <string name="screenrecord_start_error" msgid="2200660692479682368">"เกิดข้อผิดพลาดขณะเริ่มบันทึกหน้าจอ"</string> @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"ปัญหาการบันทึก"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"เริ่ม"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"หยุด"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"รายงานข้อบกพร่อง"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ประสบการณ์การใช้งานอุปกรณ์ส่วนใดที่ได้รับผลกระทบ"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"เลือกประเภทปัญหา"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"บันทึกหน้าจอ"</string> @@ -363,14 +364,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"มาตรฐาน"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ปานกลาง"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"สูง"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"เครื่องช่วยฟัง"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"เครื่องช่วยฟัง"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"จับคู่อุปกรณ์ใหม่"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"คลิกเพื่อจับคู่อุปกรณ์ใหม่"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"เลิกบล็อกไมโครโฟนของอุปกรณ์ใช่ไหม"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"เลิกบล็อกกล้องของอุปกรณ์ใช่ไหม"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"เลิกบล็อกกล้องและไมโครโฟนของอุปกรณ์ใช่ไหม"</string> @@ -745,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"สลับรูปแบบแป้นพิมพ์"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"หรือ"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"ล้างคำค้นหา"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"แป้นพิมพ์ลัด"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"แป้นพิมพ์ลัด"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"ค้นหาแป้นพิมพ์ลัด"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"ไม่พบแป้นพิมพ์ลัด"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"ระบบ"</string> @@ -770,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"เปิด Assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"ล็อกหน้าจอ"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"จดโน้ต"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"การทํางานหลายอย่างพร้อมกันของระบบ"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"เข้าสู่โหมดแยกหน้าจอโดยแอปปัจจุบันอยู่ด้านขวา"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"เข้าสู่โหมดแยกหน้าจอโดยแอปปัจจุบันอยู่ด้านซ้าย"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"การทํางานหลายอย่างพร้อมกัน"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"ใช้โหมดแยกหน้าจอโดยแอปปัจจุบันอยู่ด้านขวา"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"ใช้โหมดแยกหน้าจอโดยแอปปัจจุบันอยู่ด้านซ้าย"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"เปลี่ยนจากโหมดแยกหน้าจอเป็นเต็มหน้าจอ"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"เปลี่ยนไปใช้แอปทางด้านขวาหรือด้านล่างขณะใช้โหมดแยกหน้าจอ"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"เปลี่ยนไปใช้แอปทางด้านซ้ายหรือด้านบนขณะใช้โหมดแยกหน้าจอ"</string> @@ -1194,7 +1191,7 @@      <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{ทำงานอยู่ # แอป}other{ทำงานอยู่ # แอป}}"</string>      <string name="fgs_dot_content_description" msgid="2865071539464777240">"ข้อมูลใหม่"</string>      <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"แอปที่ทำงานอยู่"</string> -    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"แอปเหล่านี้กำลังทำงานแม้ว่าคุณจะไม่ได้ใช้งานอยู่ก็ตาม วิธีนี้ช่วยให้ฟังก์ชันการทำงานของแอปมีประสิทธิภาพมากขึ้น แต่ก็อาจส่งผลต่ออายุการใช้งานแบตเตอรี่ด้วย"</string> +    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"แอปเหล่านี้กำลังทำงานแม้ว่าคุณจะไม่ได้ใช้งานอยู่ก็ตาม วิธีนี้ช่วยให้ฟังก์ชันการทำงานของแอปมีประสิทธิภาพมากขึ้น แต่ก็อาจส่งผลต่อระยะเวลาการใช้งานแบตเตอรี่ด้วย"</string>      <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"หยุด"</string>      <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"หยุดแล้ว"</string>      <string name="clipboard_edit_text_done" msgid="4551887727694022409">"เสร็จ"</string> diff --git a/packages/SystemUI/res/values-th/tiles_states_strings.xml b/packages/SystemUI/res/values-th/tiles_states_strings.xml index d6351ce7df4d..8b7187b66baa 100644 --- a/packages/SystemUI/res/values-th/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-th/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"ปิด"</item>      <item msgid="5137565285664080143">"เปิด"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"ไม่พร้อมใช้งาน"</item> +    <item msgid="3079622119444911877">"ปิด"</item> +    <item msgid="3028994095749238254">"เปิด"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 54bb74b85cba..9f408f4168e8 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Mag-record ng Isyu"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Magsimula"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Ihinto"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"Ulat ng Bug"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ano\'ng naapektuhang parte ng experience sa device?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Piliin ang uri ng isyu"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Pag-record ng screen"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Katamtaman"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Mataas"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Mga hearing device"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Mga hearing device"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Magpares ng bagong device"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"I-click para magpares ng bagong device"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"I-unblock ang mikropono ng device?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"I-unblock ang camera ng device?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"I-unblock ang camera at mikropono ng device?"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Magpalit ng layout ng keyboard"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"o"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"I-clear ang query sa paghahanap"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Mga Shortcut"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Mga Keyboard Shortcut"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Maghanap ng mga shortcut"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Walang nakitang shortcut"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"System"</string> @@ -769,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Buksan ang assistant"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"I-lock ang screen"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Magtala"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitasking ng system"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Lumipat sa split screen nang nasa RHS ang kasalukuyang app"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Lumipat sa split screen nang nasa LHS ang kasalukuyang app"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Pag-multitask"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Gumamit ng split screen nang nasa kanan ang kasalukuyang app"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Gumamit ng split screen nang nasa kaliwa ang kasalukuyang app"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Lumipat sa full screen mula sa split screen"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Lumipat sa app sa kanan o ibaba habang ginagamit ang split screen"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Lumipat sa app sa kaliwa o itaas habang ginagamit ang split screen"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 5364c83d0694..c07c35037642 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Sorunu Kaydedin"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Başlayın"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Durdurun"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cihaz deneyiminiz ne şekilde etkilendi?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sorun türünü seçin"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran kaydedicisi"</string> @@ -364,12 +366,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Orta"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Yüksek"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"İşitme cihazları"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"İşitme cihazları"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yeni cihaz eşle"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz eşlemek için tıklayın"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonunun engellemesi kaldırılsın mı?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Cihaz kamerasının engellemesi kaldırılsın mı?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Cihaz kamerası ile mikrofonunun engellemesi kaldırılsın mı?"</string> @@ -744,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Klavye düzenini değiştir"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"veya"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Arama sorgusunu temizle"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Kısayollar"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Klavye Kısayolları"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Kısayol araması yapın"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Kısayol bulunamadı"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Sistem"</string> @@ -769,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Asistan\'ı aç"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Kilit ekranı"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Not al"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Sistem çoklu görevi"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Mevcut uygulamayı sağ tarafa alarak bölünmüş ekrana geç"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Mevcut uygulamayı sol tarafa alarak bölünmüş ekrana geç"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Çoklu görev"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Sağdaki mevcut uygulamayla birlikte bölünmüş ekranı kullanın"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Soldaki mevcut uygulamayla birlikte bölünmüş ekranı kullanın"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Bölünmüş ekrandan tam ekrana geç"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Bölünmüş ekran kullanırken sağdaki veya alttaki uygulamaya geçiş yapın"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Bölünmüş ekran kullanırken soldaki veya üstteki uygulamaya geçiş yapın"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index da1dfa4af50d..65630348c22c 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Запис помилки"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Почати"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Зупинити"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"На який аспект роботи пристрою вплинула проблема?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Виберіть тип проблеми"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запис відео з екрана"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"Стандартний"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Середній"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Високий"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слухові апарати"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухові апарати"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Підключити новий пристрій"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Натисніть, щоб підключити новий пристрій"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Надати доступ до мікрофона?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Надати доступ до камери пристрою?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Надати доступ до камери й мікрофона?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Змінити розкладку клавіатури"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"або"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Очистити пошуковий запит"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Швидкі команди"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Комбінації клавіш"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Пошук швидких команд"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Швидк. команд не знайдено"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Система"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Відкрити додаток Асистент"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Заблокувати екран"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Створити нотатку"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Багатозадачність системи"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Розділити екран із поточним додатком праворуч"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Розділити екран із поточним додатком ліворуч"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Багатозадачність"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Розділити екран і показувати поточний додаток праворуч"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Розділити екран і показувати поточний додаток ліворуч"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Перейти з розділення екрана на весь екран"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Під час розділення екрана перемикатися на додаток праворуч або внизу"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Під час розділення екрана перемикатися на додаток ліворуч або вгорі"</string> @@ -784,7 +782,7 @@      <string name="input_access_voice_typing" msgid="7291201476395326141">"Відкрити голосовий ввід"</string>      <string name="keyboard_shortcut_group_applications" msgid="7386239431100651266">"Додатки"</string>      <string name="keyboard_shortcut_group_applications_assist" msgid="6772492350416591448">"Асистент"</string> -    <string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"Веб-переглядач"</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_email" msgid="7852376788894975192">"Електронна пошта"</string>      <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS"</string> @@ -903,7 +901,7 @@      <string name="instant_apps_message" msgid="6112428971833011754">"Додаток відкрито без встановлення."</string>      <string name="instant_apps_message_with_help" msgid="1816952263531203932">"Додаток відкрито без встановлення. Торкніться, щоб дізнатися більше."</string>      <string name="app_info" msgid="5153758994129963243">"Про додаток"</string> -    <string name="go_to_web" msgid="636673528981366511">"Веб-переглядач"</string> +    <string name="go_to_web" msgid="636673528981366511">"Вебпереглядач"</string>      <string name="mobile_data" msgid="4564407557775397216">"Мобільний трафік"</string>      <string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>      <string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-uk/tiles_states_strings.xml b/packages/SystemUI/res/values-uk/tiles_states_strings.xml index be779eb51330..61e62e4395ce 100644 --- a/packages/SystemUI/res/values-uk/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-uk/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"Вимкнено"</item>      <item msgid="5137565285664080143">"Увімкнено"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"Недоступно"</item> +    <item msgid="3079622119444911877">"Вимкнено"</item> +    <item msgid="3028994095749238254">"Увімкнено"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index fa4bd02124e5..452beaf4b07b 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -350,6 +350,7 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"مسئلہ ریکارڈ کریں"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"شروع کریں"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"روکیں"</string> +    <string name="qs_record_issue_bug_report" msgid="8229031766918650079">"بگ رپورٹ"</string>      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"آپ کے آلے کے تجربے کا کون سا حصہ متاثر ہوا؟"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"مسئلہ کی قسم منتخب کریں"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"اسکرین ریکارڈ"</string> @@ -364,12 +365,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"متوسط"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"زیادہ"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سماعت کے آلات"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سماعت کے آلات"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"نئے آلے کا جوڑا بنائیں"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"نئے آلے کا جوڑا بنانے کے لیے کلک کریں"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"آلے کا مائیکروفون غیر مسدود کریں؟"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"آلے کا کیمرا غیر مسدود کریں؟"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"آلے کا کیمرا اور مائیکروفون غیر مسدود کریں؟"</string> @@ -744,7 +742,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"کی بورڈ لے آؤٹ سوئچ کریں"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"یا"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"تلاش کا استفسار صاف کریں"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"شارٹ کٹس"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"کی بورڈ شارٹ کٹس"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"شارٹ کٹس تلاش کریں"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"کوئی شارٹ کٹ نہیں ملا"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"سسٹم"</string> @@ -769,9 +767,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"اسسٹنٹ کھولیں"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"مقفل اسکرین"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"نوٹ لیں"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"سسٹم ملٹی ٹاسکنگ"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"موجودہ ایپ کے ساتھ دائیں جانب اسپلٹ اسکرین انٹر کریں"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"موجودہ ایپ کے ساتھ بائیں جانب اسپلٹ اسکرین انٹر کریں"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"ملٹی ٹاسکنگ"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"دائیں جانب موجودہ ایپ کے ساتھ اسپلٹ اسکرین کا استعمال کریں"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"بائیں جانب موجودہ ایپ کے ساتھ اسپلٹ اسکرین کا استعمال کریں"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"اسپلٹ اسکرین سے پوری سکرین پر سوئچ کریں"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"اسپلٹ اسکرین کا استعمال کرتے ہوئے دائیں یا نیچے ایپ پر سوئچ کریں"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"اسپلٹ اسکرین کا استعمال کرتے ہوئے بائیں یا اوپر ایپ پر سوئچ کریں"</string> @@ -1123,7 +1121,7 @@      <string name="build_number_copy_toast" msgid="877720921605503046">"بلڈ نمبر کلپ بورڈ میں کاپی ہو گیا۔"</string>      <string name="basic_status" msgid="2315371112182658176">"گفتگو کھولیں"</string>      <string name="select_conversation_title" msgid="6716364118095089519">"گفتگو ویجیٹس"</string> -    <string name="select_conversation_text" msgid="3376048251434956013">"اسے اپنے ہوم اسکرین پر شامل کرنے کے لیے گفتگو پر تھپتھپائیں"</string> +    <string name="select_conversation_text" msgid="3376048251434956013">"اسے اپنی ہوم اسکرین پر شامل کرنے کے لیے گفتگو پر تھپتھپائیں"</string>      <string name="no_conversations_text" msgid="5354115541282395015">"آپ کی حالیہ گفتگوئیں یہاں دکھائی دیں گی"</string>      <string name="priority_conversations" msgid="3967482288896653039">"ترجیحی گفتگوئیں"</string>      <string name="recent_conversations" msgid="8531874684782574622">"حالیہ گفتگوئیں"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 195b044a0f6f..7a5cbad4aae1 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Yozib olishda xato"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Boshlash"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Toʻxtatish"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Qurilma ishlashining qaysi qismiga taʼsir qildi?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Muammo turini tanlang"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran yozuvi"</string> @@ -364,12 +366,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Oʻrtacha"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Yuqori"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Eshitish qurilmalari"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Eshitish qurilmalari"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yangi qurilmani ulash"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yangi qurilmani ulash uchun bosing"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Qurilma mikrofoni blokdan chiqarilsinmi?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Qurilma kamerasi blokdan chiqarilsinmi?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Qurilma kamerasi va mikrofoni blokdan chiqarilsinmi?"</string> @@ -744,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Klaviatura terilmasini almashtirish"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"yoki"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Qidiruv soʻrovini tozalash"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Tezkor tugmalar"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Tezkor tugmalar"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Tezkor tugmalar qidiruvi"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Tezkor tugmalar topilmadi"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Tizim"</string> @@ -769,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistentni ochish"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Ekran qulfi"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Qayd yaratish"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Tizimdagi multi-vazifalik"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Oʻng tomondagi ajratilgan ekran rejimiga kirish"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Chap tomondagi ajratilgan ekran rejimiga kirish"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Multi-vazifalilik"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Ekranni ajratib, joriy ilovani oʻngga joylash"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Ekranni ajratib, joriy ilovani chapga joylash"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Ajratilgan ekran rejimidan butun ekranga almashtirish"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Ajratilgan ekranda oʻngdagi yoki pastdagi ilovaga almashish"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Ajratilgan ekranda chapdagi yoki yuqoridagi ilovaga almashish"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 469430b5dcf6..85421eef947f 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Ghi lại vấn đề"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Bắt đầu"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Dừng"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Bạn gặp loại vấn đề gì khi dùng thiết bị?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Chọn loại vấn đề"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ghi màn hình"</string> @@ -364,12 +366,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Vừa"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Cao"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Thiết bị trợ thính"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Thiết bị trợ thính"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Ghép nối thiết bị mới"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Nhấp để ghép nối thiết bị mới"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Bỏ chặn micrô của thiết bị?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Bỏ chặn camera của thiết bị?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Bỏ chặn máy ảnh và micrô của thiết bị?"</string> @@ -744,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Chuyển đổi bố cục bàn phím"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"hoặc"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Xoá cụm từ tìm kiếm"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Lối tắt"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Phím tắt"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Lối tắt tìm kiếm"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Không tìm thấy lối tắt"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Hệ thống"</string> @@ -769,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Mở Trợ lý"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Màn hình khoá"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Tạo ghi chú"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Xử lý đa nhiệm trong hệ thống"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Vào chế độ chia đôi màn hình, ứng dụng hiện tại ở màn hình bên phải"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Vào chế độ chia đôi màn hình, ứng dụng hiện tại ở màn hình bên trái"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Đa nhiệm"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Dùng tính năng chia đôi màn hình, trong đó ứng dụng hiện tại ở bên phải"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Dùng tính năng chia đôi màn hình, trong đó ứng dụng hiện tại ở bên trái"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Chuyển từ chế độ chia đôi màn hình sang chế độ toàn màn hình"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Chuyển sang ứng dụng bên phải hoặc ở dưới khi đang chia đôi màn hình"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Chuyển sang ứng dụng bên trái hoặc ở trên khi đang chia đôi màn hình"</string> @@ -994,7 +993,7 @@      <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Huỷ"</string>      <string name="accessibility_floating_button_hidden_notification_title" msgid="4115036997406994799">"Đã ẩn nút hỗ trợ tiếp cận"</string>      <string name="accessibility_floating_button_hidden_notification_text" msgid="1457021647040915658">"Nhấn để hiện nút hỗ trợ tiếp cận"</string> -    <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Đã xoá phím tắt dành cho <xliff:g id="FEATURE_NAME">%s</xliff:g>"</string> +    <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Đã xoá lối tắt cho <xliff:g id="FEATURE_NAME">%s</xliff:g>"</string>      <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Đã xoá # lối tắt}other{Đã xoá # lối tắt}}"</string>      <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Chuyển lên trên cùng bên trái"</string>      <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Chuyển lên trên cùng bên phải"</string> @@ -1283,7 +1282,7 @@      <string name="mirror_display" msgid="2515262008898122928">"Phản chiếu màn hình"</string>      <string name="dismiss_dialog" msgid="2195508495854675882">"Đóng"</string>      <string name="connected_display_icon_desc" msgid="6373560639989971997">"Đã kết nối màn hình"</string> -    <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrô và máy ảnh"</string> +    <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrô và camera"</string>      <string name="privacy_dialog_summary" msgid="2458769652125995409">"Hoạt động sử dụng gần đây của ứng dụng"</string>      <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Xem hoạt động truy cập gần đây"</string>      <string name="privacy_dialog_done_button" msgid="4504330708531434263">"Xong"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 6765d1e4f175..d23a0fd97bc4 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"录制问题"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"开始"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"停止"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"设备体验的哪个方面受到影响?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"选择问题类型"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"屏幕录制"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"标准"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"中"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"高"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助听装置"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助听装置"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"与新设备配对"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"点击即可与新设备配对"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解锁设备麦克风吗?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解锁设备摄像头吗?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要解锁设备摄像头和麦克风吗?"</string> @@ -686,7 +684,7 @@      <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"无法修改来电通知。"</string>      <string name="notification_multichannel_desc" msgid="7414593090056236179">"您无法在此处配置这组通知"</string>      <string name="notification_delegate_header" msgid="1264510071031479920">"代理通知"</string> -    <string name="notification_channel_dialog_title" msgid="6856514143093200019">"所有的<xliff:g id="APP_NAME">%1$s</xliff:g>通知"</string> +    <string name="notification_channel_dialog_title" msgid="6856514143093200019">"所有“<xliff:g id="APP_NAME">%1$s</xliff:g>”通知"</string>      <string name="see_more_title" msgid="7409317011708185729">"查看更多"</string>      <string name="feedback_alerted" msgid="5192459808484271208">"系统已自动将此通知的重要性<b>提升为“默认”</b>。"</string>      <string name="feedback_silenced" msgid="9116540317466126457">"系统已自动将此通知的重要性<b>降低为“静音”</b>。"</string> @@ -745,12 +743,12 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"切换键盘布局"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"或"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"清除搜索查询"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"快捷键"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"键盘快捷键"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"搜索快捷键"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"未找到任何快捷键"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"系统"</string>      <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"输入"</string> -    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"已开应用"</string> +    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"已打开的应用"</string>      <string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"当前应用"</string>      <string name="keyboard_shortcut_a11y_show_search_results" msgid="2865241062981833705">"目前显示的是搜索结果"</string>      <string name="keyboard_shortcut_a11y_filter_system" msgid="7744143131119370483">"目前显示的是系统快捷键"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"打开 Google 助理"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"锁定屏幕"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"添加记事"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"系统多任务处理"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"进入分屏模式,当前应用显示于右侧"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"进入分屏模式,当前应用显示于左侧"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"多任务处理"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"使用分屏模式,并且当前应用位于右侧"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"使用分屏模式,并且当前应用位于左侧"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"从分屏模式切换为全屏"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分屏模式时,切换到右侧或下方的应用"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分屏模式时,切换到左侧或上方的应用"</string> @@ -830,7 +828,7 @@      <string name="left_icon" msgid="5036278531966897006">"向左图标"</string>      <string name="right_icon" msgid="1103955040645237425">"向右图标"</string>      <string name="drag_to_add_tiles" msgid="8933270127508303672">"按住并拖动即可添加功能块"</string> -    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"按住并拖动即可重新排列图块"</string> +    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"按住并拖动即可重新排列功能块"</string>      <string name="drag_to_remove_tiles" msgid="4682194717573850385">"拖动到此处即可移除"</string>      <string name="drag_to_remove_disabled" msgid="933046987838658850">"您至少需要 <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> 个卡片"</string>      <string name="qs_edit" msgid="5583565172803472437">"编辑"</string> @@ -1194,7 +1192,7 @@      <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# 个应用处于活动状态}other{# 个应用处于活动状态}}"</string>      <string name="fgs_dot_content_description" msgid="2865071539464777240">"新信息"</string>      <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"已开启的应用"</string> -    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"这些应用正在保持活跃运行状态,即使您没有在使用它们。这可以改进它们的功能,但可能会影响到电池续航时间。"</string> +    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"这些应用即使在闲置时仍处于活跃运行状态。应用的功能会因此提升,但可能会影响电池续航时间。"</string>      <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>      <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"已停止"</string>      <string name="clipboard_edit_text_done" msgid="4551887727694022409">"完成"</string> @@ -1285,7 +1283,7 @@      <string name="dismiss_dialog" msgid="2195508495854675882">"关闭"</string>      <string name="connected_display_icon_desc" msgid="6373560639989971997">"显示屏已连接"</string>      <string name="privacy_dialog_title" msgid="7839968133469098311">"麦克风和摄像头"</string> -    <string name="privacy_dialog_summary" msgid="2458769652125995409">"近期应用对手机传感器的使用情况"</string> +    <string name="privacy_dialog_summary" msgid="2458769652125995409">"近期被应用使用的情况"</string>      <string name="privacy_dialog_more_button" msgid="7610604080293562345">"查看近期使用情况"</string>      <string name="privacy_dialog_done_button" msgid="4504330708531434263">"完成"</string>      <string name="privacy_dialog_expand_action" msgid="9129262348628331377">"展开并显示选项"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml index a9a377a0fbff..9467b9b27f26 100644 --- a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"已关闭"</item>      <item msgid="5137565285664080143">"已开启"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"不可用"</item> +    <item msgid="3079622119444911877">"关闭"</item> +    <item msgid="3028994095749238254">"开启"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index d4891d533276..04565e53be1c 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"錄製問題"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"開始"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"停止"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"哪些裝置使用體驗受影響?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"選取問題類型"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"螢幕錄影"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"標準"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"中"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"高"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助聽器"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助聽器"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"配對新裝置"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"㩒一下就可以配對新裝置"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解除封鎖裝置麥克風嗎?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解除封鎖裝置相機嗎?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要解除封鎖裝置相機和麥克風嗎?"</string> @@ -745,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"切換鍵盤配置"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"或"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"清除搜尋查詢"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"快速鍵"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"鍵盤快速鍵"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"搜尋快速鍵"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"找不到快速鍵"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"系統"</string> @@ -770,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"開啟「Google 助理」"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"上鎖畫面"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"寫筆記"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"系統多工處理"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"進入分割螢幕模式,並將目前的應用程式顯示在右側"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"進入分割螢幕模式,並將目前的應用程式顯示在左側"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"多工處理"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"使用分割螢幕,並在右側顯示目前使用的應用程式"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"使用分割螢幕,並在左側顯示目前使用的應用程式"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"將分割螢幕切換為全螢幕"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分割螢幕時,切換至右邊或下方的應用程式"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分割螢幕時,切換至左邊或上方的應用程式"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml index f0ccd9e3d864..cca7ac42906a 100644 --- a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"關閉"</item>      <item msgid="5137565285664080143">"開啟"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"無法使用"</item> +    <item msgid="3079622119444911877">"關閉"</item> +    <item msgid="3028994095749238254">"開啟"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index bc59988f681d..11d2c3ed0b0f 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"記錄問題"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"開始"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"停止"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"哪些裝置使用體驗受到影響?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"選取問題類型"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"螢幕錄影"</string> @@ -363,14 +365,10 @@      <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"標準"</string>      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"中"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"高"</string> -    <!-- no translation found for quick_settings_hearing_devices_label (7277170419679404129) --> -    <skip /> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助聽器"</string> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助聽器"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"配對新裝置"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"按一下即可配對新裝置"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解除封鎖裝置麥克風嗎?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解除封鎖裝置相機嗎?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要將裝置的相機和麥克風解除封鎖嗎?"</string> @@ -678,7 +676,7 @@      <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"<b>狀態:</b>已調降順序"</string>      <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"顯示在對話通知頂端 (螢幕鎖定時會顯示為個人資料相片)"</string>      <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"以對話框的形式顯示在對話通知頂端 (螢幕鎖定時會顯示為個人資料相片)"</string> -    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"顯示在對話通知頂端 (螢幕鎖定時會顯示為個人資料相片),並會中斷「零打擾」模式"</string> +    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"顯示在對話通知頂端 (螢幕鎖定時會顯示個人資料相片),並會中斷「零打擾」模式"</string>      <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以對話框的形式顯示在對話通知頂端 (螢幕鎖定時會顯示為個人資料相片),並會中斷「零打擾」模式"</string>      <string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>      <string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string> @@ -745,12 +743,12 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"切換鍵盤配置"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"或"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"清除搜尋查詢"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"快速鍵"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"鍵盤快速鍵"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"搜尋快速鍵"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"找不到快速鍵"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"系統"</string>      <string name="keyboard_shortcut_search_category_input" msgid="5440558509904296233">"輸入"</string> -    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"已開啟的應用程式"</string> +    <string name="keyboard_shortcut_search_category_open_apps" msgid="1450959949739257562">"開啟應用程式"</string>      <string name="keyboard_shortcut_search_category_current_app" msgid="2011953559133734491">"目前的應用程式"</string>      <string name="keyboard_shortcut_a11y_show_search_results" msgid="2865241062981833705">"顯示搜尋結果"</string>      <string name="keyboard_shortcut_a11y_filter_system" msgid="7744143131119370483">"顯示系統快速鍵"</string> @@ -763,16 +761,16 @@      <string name="group_system_go_back" msgid="2730322046244918816">"返回"</string>      <string name="group_system_access_home_screen" msgid="4130366993484706483">"前往主畫面"</string>      <string name="group_system_overview_open_apps" msgid="5659958952937994104">"查看最近開啟的應用程式"</string> -    <string name="group_system_cycle_forward" msgid="5478663965957647805">"前往最近開啟的應用程式"</string> -    <string name="group_system_cycle_back" msgid="8194102916946802902">"返回最近開啟的應用程式"</string> +    <string name="group_system_cycle_forward" msgid="5478663965957647805">"向前循環切換最近開啟的應用程式"</string> +    <string name="group_system_cycle_back" msgid="8194102916946802902">"向後循環切換最近開啟的應用程式"</string>      <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"開啟應用程式清單"</string>      <string name="group_system_access_system_settings" msgid="8731721963449070017">"開啟設定"</string>      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"開啟 Google 助理"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"螢幕鎖定"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"新增記事"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"系統多工處理"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"進入分割畫面模式,並將目前的應用程式顯示於右側"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"進入分割畫面模式,並將目前的應用程式顯示於左側"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"多工處理"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"使用分割畫面,並在右側顯示目前使用的應用程式"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"使用分割畫面,並在左側顯示目前使用的應用程式"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"從分割畫面切換到完整畫面"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"使用分割畫面時,切換到右邊或上方的應用程式"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"使用分割畫面時,切換到左邊或上方的應用程式"</string> @@ -868,7 +866,7 @@      <string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"編輯設定順序。"</string>      <string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源鍵選單"</string>      <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string> -    <string name="tuner_lock_screen" msgid="2267383813241144544">"鎖定畫面"</string> +    <string name="tuner_lock_screen" msgid="2267383813241144544">"螢幕鎖定"</string>      <string name="finder_active" msgid="7907846989716941952">"即使這支手機關機,仍可透過「尋找我的裝置」找出手機位置"</string>      <string name="shutdown_progress" msgid="5464239146561542178">"關機中…"</string>      <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看處理步驟"</string> @@ -1194,7 +1192,7 @@      <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# 個應用程式正在運作}other{# 個應用程式正在運作}}"</string>      <string name="fgs_dot_content_description" msgid="2865071539464777240">"新資訊"</string>      <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"運作中的應用程式"</string> -    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"即使你並未使用,這些應用程式仍會持續運作。這可提升應用程式效能,但也可能影響電池續航力。"</string> +    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"這些應用程式會在沒有使用的情況下持續運作。應用程式的實用度會因此提升,但也可能影響電池續航力。"</string>      <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>      <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"已停止"</string>      <string name="clipboard_edit_text_done" msgid="4551887727694022409">"完成"</string> @@ -1285,7 +1283,7 @@      <string name="dismiss_dialog" msgid="2195508495854675882">"關閉"</string>      <string name="connected_display_icon_desc" msgid="6373560639989971997">"螢幕已連結"</string>      <string name="privacy_dialog_title" msgid="7839968133469098311">"麥克風和相機"</string> -    <string name="privacy_dialog_summary" msgid="2458769652125995409">"最近曾使用感應器的應用程式"</string> +    <string name="privacy_dialog_summary" msgid="2458769652125995409">"最近使用的應用程式"</string>      <string name="privacy_dialog_more_button" msgid="7610604080293562345">"查看近期存取記錄"</string>      <string name="privacy_dialog_done_button" msgid="4504330708531434263">"完成"</string>      <string name="privacy_dialog_expand_action" msgid="9129262348628331377">"展開並顯示選項"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml index 2c474f624ca7..4cc580434a36 100644 --- a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml @@ -186,7 +186,9 @@      <item msgid="2478289035899842865">"關閉"</item>      <item msgid="5137565285664080143">"開啟"</item>    </string-array> -    <!-- no translation found for tile_states_hearing_devices:0 (1235334096484287173) --> -    <!-- no translation found for tile_states_hearing_devices:1 (3079622119444911877) --> -    <!-- no translation found for tile_states_hearing_devices:2 (3028994095749238254) --> +  <string-array name="tile_states_hearing_devices"> +    <item msgid="1235334096484287173">"無法使用"</item> +    <item msgid="3079622119444911877">"已關閉"</item> +    <item msgid="3028994095749238254">"已開啟"</item> +  </string-array>  </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 780fe948d531..6f87762c1b41 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -260,7 +260,7 @@      <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"Isikrini sikhiyelwe ngomumo we-landscape."</string>      <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"Isikrini sikhiyelwe ngomumo we-portrait."</string>      <string name="dessert_case" msgid="9104973640704357717">"Isikhwama soswidi"</string> -    <string name="start_dreams" msgid="9131802557946276718">"Isigcini sihenqo"</string> +    <string name="start_dreams" msgid="9131802557946276718">"Isigciniskrini"</string>      <string name="ethernet_label" msgid="2203544727007463351">"I-Ethernet"</string>      <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ungaphazamisi"</string>      <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"I-Bluetooth"</string> @@ -350,6 +350,8 @@      <string name="qs_record_issue_label" msgid="8166290137285529059">"Rekhoda Inkinga"</string>      <string name="qs_record_issue_start" msgid="2979831312582567056">"Qala"</string>      <string name="qs_record_issue_stop" msgid="3531747965741982657">"Misa"</string> +    <!-- no translation found for qs_record_issue_bug_report (8229031766918650079) --> +    <skip />      <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuthinteke yiphi ingxenye yokusebenzisa idivayisi?"</string>      <string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Khetha uhlobo lwenkinga"</string>      <string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Irekhodi lesikrini"</string> @@ -364,12 +366,9 @@      <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Okuphakathi"</string>      <string name="quick_settings_contrast_high" msgid="656049259587494499">"Phezulu"</string>      <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Izinsizakuzwa"</string> -    <!-- no translation found for quick_settings_hearing_devices_dialog_title (9004774017688484981) --> -    <skip /> -    <!-- no translation found for quick_settings_pair_hearing_devices (5987105102207447322) --> -    <skip /> -    <!-- no translation found for accessibility_hearing_device_pair_new_device (8440082580186130090) --> -    <skip /> +    <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Izinsizakuzwa"</string> +    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Bhangqa idivayisi entsha"</string> +    <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Chofoza ukuze ubhangqe idivayisi entsha"</string>      <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vulela imakrofoni yedivayisi?"</string>      <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Vulela ikhamera yedivayisi?"</string>      <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Vulela ikhamera yedivayisi nemakrofoni?"</string> @@ -744,7 +743,7 @@      <string name="keyboard_shortcut_group_system_switch_input" msgid="952555530383268166">"Shintsha isakhiwo sekhibhodi"</string>      <string name="keyboard_shortcut_join" msgid="3578314570034512676">"noma"</string>      <string name="keyboard_shortcut_clear_text" msgid="6631051796030377857">"Sula umbuzo wosesho"</string> -    <string name="keyboard_shortcut_search_list_title" msgid="1156178106617830429">"Izinqamuleli"</string> +    <string name="keyboard_shortcut_search_list_title" msgid="4271769465397671138">"Izinqamuleli Zekhibhodi"</string>      <string name="keyboard_shortcut_search_list_hint" msgid="5982623262974326746">"Sesha izinqamuleli"</string>      <string name="keyboard_shortcut_search_list_no_result" msgid="6819302191660875501">"Azikho izinqamuleli ezitholakele"</string>      <string name="keyboard_shortcut_search_category_system" msgid="1151182120757052669">"Isistimu"</string> @@ -769,9 +768,9 @@      <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Vula umsizi"</string>      <string name="group_system_lock_screen" msgid="7391191300363416543">"Khiya isikrini"</string>      <string name="group_system_quick_memo" msgid="3764560265935722903">"Thatha inothi"</string> -    <string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Ukwenza imisebenzi eminingi yesistimu"</string> -    <string name="system_multitasking_rhs" msgid="2454557648974553729">"Faka ukuhlukanisa isikrini nge-app yamanje kuya ku-RHS"</string> -    <string name="system_multitasking_lhs" msgid="3516599774920979402">"Faka ukuhlukanisa isikrini nge-app yamanje kuya ku-LHS"</string> +    <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Ukwenza imisebenzi eminingi"</string> +    <string name="system_multitasking_rhs" msgid="8714224917276297810">"Sebenzisa isikrini esihlukanisayo nge-app yamanje kwesokudla"</string> +    <string name="system_multitasking_lhs" msgid="8402954791206308783">"Sebenzisa isikrini sokuhlukanisa nge-app yamanje kwesokunxele"</string>      <string name="system_multitasking_full_screen" msgid="336048080383640562">"Shintsha usuka ekuhlukaniseni isikrini uye kusikrini esigcwele"</string>      <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"Shintshela ku-app ngakwesokudla noma ngezansi ngenkathi usebenzisa uhlukanisa isikrini"</string>      <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"Shintshela ku-app ngakwesokunxele noma ngaphezulu ngenkathi usebenzisa ukuhlukanisa isikrini"</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index a6f6d4dcf2f9..fa9d507dbff5 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -116,9 +116,6 @@           The syntax is setting-name:spec. If the tile is a TileService, the spec should be specified           as custom(package/class). Relative class name is supported. -->      <string-array name="config_quickSettingsAutoAdd" translatable="false"> -        <item>accessibility_display_daltonizer_enabled:color_correction</item> -        <item>accessibility_display_inversion_enabled:inversion</item> -        <item>one_handed_mode_enabled:onehanded</item>          <item>accessibility_font_scaling_has_been_changed:font_scaling</item>      </string-array> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index b0b548295b71..26fa2b136ed4 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -613,7 +613,7 @@      <dimen name="volume_panel_slice_vertical_padding">8dp</dimen>      <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen> -    <dimen name="volume_panel_corner_radius">52dp</dimen> +    <dimen name="volume_panel_corner_radius">28dp</dimen>      <!-- Size of each item in the ringer selector drawer. -->      <dimen name="volume_ringer_drawer_item_size">42dp</dimen> @@ -2001,4 +2001,7 @@      <!-- SliceView grid gutter for ANC Slice -->      <dimen name="abc_slice_grid_gutter">0dp</dimen> +    <!-- SliceView icon size --> +    <dimen name="abc_slice_big_pic_min_height">64dp</dimen> +    <dimen name="abc_slice_big_pic_max_height">64dp</dimen>  </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index af661aa172c7..f60f6c7af289 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -678,6 +678,8 @@      <string name="turn_on_bluetooth">Use Bluetooth</string>      <!-- QuickSettings: Bluetooth dialog device connected default summary [CHAR LIMIT=NONE]-->      <string name="quick_settings_bluetooth_device_connected">Connected</string> +    <!-- QuickSettings: Bluetooth dialog device in audio sharing default summary [CHAR LIMIT=50]--> +    <string name="quick_settings_bluetooth_device_audio_sharing">Audio Sharing</string>      <!-- QuickSettings: Bluetooth dialog device saved default summary [CHAR LIMIT=NONE]-->      <string name="quick_settings_bluetooth_device_saved">Saved</string>      <!-- QuickSettings: Accessibility label to disconnect a device [CHAR LIMIT=NONE]--> @@ -687,9 +689,13 @@      <!-- QuickSettings: Bluetooth auto on tomorrow [CHAR LIMIT=NONE]-->      <string name="turn_on_bluetooth_auto_tomorrow">Automatically turn on again tomorrow</string>      <!-- QuickSettings: Bluetooth auto on info text when disabled [CHAR LIMIT=NONE]--> -    <string name="turn_on_bluetooth_auto_info_disabled">Features like Quick Share, Find My Device, and device location use Bluetooth</string> +    <string name="turn_on_bluetooth_auto_info_disabled">Features like Quick Share and Find My Device use Bluetooth</string>      <!-- QuickSettings: Bluetooth auto on info text when enabled [CHAR LIMIT=NONE]--> -    <string name="turn_on_bluetooth_auto_info_enabled">Bluetooth will turn on tomorrow at 5 AM</string> +    <string name="turn_on_bluetooth_auto_info_enabled">Bluetooth will turn on tomorrow morning</string> +    <!-- QuickSettings: Bluetooth dialog audio sharing button text [CHAR LIMIT=50]--> +    <string name="quick_settings_bluetooth_audio_sharing_button">Audio Sharing</string> +    <!-- QuickSettings: Bluetooth dialog audio sharing button text when sharing audio [CHAR LIMIT=50]--> +    <string name="quick_settings_bluetooth_audio_sharing_button_sharing">Sharing Audio</string>      <!-- QuickSettings: Bluetooth secondary label for the battery level of a connected device [CHAR LIMIT=20]-->      <string name="quick_settings_bluetooth_secondary_label_battery_level"><xliff:g id="battery_level_as_percentage">%s</xliff:g> battery</string> diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensor.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensor.kt index a2b119833474..f07dce5e3482 100644 --- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensor.kt +++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensor.kt @@ -16,6 +16,7 @@  package com.android.systemui.biometrics.shared.model +import android.graphics.Rect  import android.hardware.fingerprint.FingerprintSensorPropertiesInternal  /** Fingerprint sensor property. Represents [FingerprintSensorPropertiesInternal]. */ @@ -23,12 +24,23 @@ data class FingerprintSensor(      val sensorId: Int,      val sensorStrength: SensorStrength,      val maxEnrollmentsPerUser: Int, -    val sensorType: FingerprintSensorType +    val sensorType: FingerprintSensorType, +    val sensorBounds: Rect, +    val sensorRadius: Int,  )  /** Convert [FingerprintSensorPropertiesInternal] to corresponding [FingerprintSensor] */  fun FingerprintSensorPropertiesInternal.toFingerprintSensor(): FingerprintSensor {      val sensorStrength: SensorStrength = this.sensorStrength.toSensorStrength()      val sensorType: FingerprintSensorType = this.sensorType.toSensorType() -    return FingerprintSensor(this.sensorId, sensorStrength, this.maxEnrollmentsPerUser, sensorType) +    val sensorBounds: Rect = this.location.rect +    val sensorRadius = this.location.sensorRadius +    return FingerprintSensor( +        this.sensorId, +        sensorStrength, +        this.maxEnrollmentsPerUser, +        sensorType, +        sensorBounds, +        sensorRadius, +    )  } diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt index 476daac5ff00..0f3d28586588 100644 --- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt +++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/SensorStrength.kt @@ -33,3 +33,10 @@ fun Int.toSensorStrength(): SensorStrength =          SensorProperties.STRENGTH_STRONG -> SensorStrength.STRONG          else -> throw IllegalArgumentException("Invalid SensorStrength value: $this")      } +/** Convert [SensorStrength] to corresponding [Int] */ +fun SensorStrength.toInt(): Int = +    when (this) { +        SensorStrength.CONVENIENCE -> SensorProperties.STRENGTH_CONVENIENCE +        SensorStrength.WEAK -> SensorProperties.STRENGTH_WEAK +        SensorStrength.STRONG -> SensorProperties.STRENGTH_STRONG +    } diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 70182c16a093..460779c73cda 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -15,6 +15,7 @@   */  package com.android.keyguard +import android.os.Trace  import android.content.BroadcastReceiver  import android.content.Context  import android.content.Intent @@ -31,7 +32,6 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener  import androidx.annotation.VisibleForTesting  import androidx.lifecycle.Lifecycle  import androidx.lifecycle.repeatOnLifecycle -import com.android.app.tracing.coroutines.launch  import com.android.systemui.broadcast.BroadcastDispatcher  import com.android.systemui.customization.R  import com.android.systemui.dagger.qualifiers.Background @@ -66,7 +66,6 @@ import java.util.Locale  import java.util.TimeZone  import java.util.concurrent.Executor  import javax.inject.Inject -import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.DisposableHandle  import kotlinx.coroutines.Job @@ -74,6 +73,7 @@ import kotlinx.coroutines.flow.combine  import kotlinx.coroutines.flow.filter  import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.launch  /**   * Controller for a Clock provided by the registry and used on the keyguard. Instantiated by @@ -91,7 +91,6 @@ constructor(      @DisplaySpecific private val resources: Resources,      private val context: Context,      @Main private val mainExecutor: DelayableExecutor, -    @Main private val mainImmediateDispatcher: CoroutineDispatcher,      @Background private val bgExecutor: Executor,      private val clockBuffers: ClockMessageBuffers,      private val featureFlags: FeatureFlagsClassic, @@ -426,12 +425,13 @@ constructor(          keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)          zenModeController.addCallback(zenModeCallback)          disposableHandle = -            parent.repeatWhenAttached(mainImmediateDispatcher) { +            parent.repeatWhenAttached {                  repeatOnLifecycle(Lifecycle.State.CREATED) {                      listenForDozing(this)                      if (MigrateClocksToBlueprint.isEnabled) {                          listenForDozeAmountTransition(this)                          listenForAnyStateToAodTransition(this) +                        listenForAnyStateToLockscreenTransition(this)                      } else {                          listenForDozeAmount(this)                      } @@ -522,8 +522,12 @@ constructor(      private fun handleDoze(doze: Float) {          dozeAmount = doze          clock?.run { +            Trace.beginSection("$TAG#smallClock.animations.doze")              smallClock.animations.doze(dozeAmount) +            Trace.endSection() +            Trace.beginSection("$TAG#largeClock.animations.doze")              largeClock.animations.doze(dozeAmount) +            Trace.endSection()          }          smallTimeListener?.update(doze < DOZE_TICKRATE_THRESHOLD)          largeTimeListener?.update(doze < DOZE_TICKRATE_THRESHOLD) @@ -531,19 +535,17 @@ constructor(      @VisibleForTesting      internal fun listenForDozeAmount(scope: CoroutineScope): Job { -        return scope.launch("$TAG#listenForDozeAmount") { -            keyguardInteractor.dozeAmount.collect { handleDoze(it) } -        } +        return scope.launch { keyguardInteractor.dozeAmount.collect { handleDoze(it) } }      }      @VisibleForTesting      internal fun listenForDozeAmountTransition(scope: CoroutineScope): Job { -        return scope.launch("$TAG#listenForDozeAmountTransition") { +        return scope.launch {              merge( -                    keyguardTransitionInteractor.aodToLockscreenTransition.map { step -> +                    keyguardTransitionInteractor.transition(AOD, LOCKSCREEN).map { step ->                          step.copy(value = 1f - step.value)                      }, -                    keyguardTransitionInteractor.lockscreenToAodTransition, +                    keyguardTransitionInteractor.transition(LOCKSCREEN, AOD),                  ).filter {                      it.transitionState != TransitionState.FINISHED                  } @@ -556,7 +558,7 @@ constructor(       */      @VisibleForTesting      internal fun listenForAnyStateToAodTransition(scope: CoroutineScope): Job { -        return scope.launch("$TAG#listenForAnyStateToAodTransition") { +        return scope.launch {              keyguardTransitionInteractor                  .transitionStepsToState(AOD)                  .filter { it.transitionState == TransitionState.STARTED } @@ -566,8 +568,19 @@ constructor(      }      @VisibleForTesting +    internal fun listenForAnyStateToLockscreenTransition(scope: CoroutineScope): Job { +        return scope.launch { +            keyguardTransitionInteractor +                    .transitionStepsToState(LOCKSCREEN) +                    .filter { it.transitionState == TransitionState.STARTED } +                    .filter { it.from != AOD } +                    .collect { handleDoze(0f) } +        } +    } + +    @VisibleForTesting      internal fun listenForDozing(scope: CoroutineScope): Job { -        return scope.launch("$TAG#listenForDozing") { +        return scope.launch {              combine(                      keyguardInteractor.dozeAmount,                      keyguardInteractor.isDozing, diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 25d771308aea..c509356c4e63 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -83,9 +83,9 @@ import com.android.systemui.classifier.FalsingCollector;  import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;  import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor;  import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags;  import com.android.systemui.keyguard.KeyguardWmStateRefactor;  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; +import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent;  import com.android.systemui.log.SessionTracker;  import com.android.systemui.plugins.ActivityStarter;  import com.android.systemui.plugins.FalsingManager; @@ -101,6 +101,8 @@ import com.android.systemui.util.ViewController;  import com.android.systemui.util.kotlin.JavaAdapter;  import com.android.systemui.util.settings.GlobalSettings; +import dagger.Lazy; +  import java.io.File;  import java.util.Arrays;  import java.util.Optional; @@ -108,7 +110,6 @@ import java.util.Optional;  import javax.inject.Inject;  import javax.inject.Provider; -import dagger.Lazy;  import kotlinx.coroutines.Job;  /** Controller for {@link KeyguardSecurityContainer} */ @@ -310,7 +311,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard           */          @Override          public void finish(int targetUserId) { -            if (!mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +            if (!RefactorKeyguardDismissIntent.isEnabled()) {                  // If there's a pending runnable because the user interacted with a widget                  // and we're leaving keyguard, then run it.                  boolean deferKeyguardDone = false; @@ -649,7 +650,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard       * @param action callback to be invoked when keyguard disappear animation completes.       */      public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) { -        if (mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +        if (RefactorKeyguardDismissIntent.isEnabled()) {              return;          }          if (mCancelAction != null) { @@ -943,7 +944,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard              mUiEventLogger.log(uiEvent, getSessionId());          } -        if (mFeatureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +        if (RefactorKeyguardDismissIntent.isEnabled()) {              if (authenticatedWithPrimaryAuth) {                  mPrimaryBouncerInteractor.get()                          .notifyKeyguardAuthenticatedPrimaryAuth(targetUserId); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 8c51a4e0ce66..4987724ea7b2 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -225,7 +225,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab      protected static final int BIOMETRIC_STATE_STOPPED = 0;      /** Biometric authentication state: Listening. */ -    private static final int BIOMETRIC_STATE_RUNNING = 1; +    protected static final int BIOMETRIC_STATE_RUNNING = 1;      /**       * Biometric authentication: Cancelling and waiting for the relevant biometric service to @@ -1145,7 +1145,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab          if (getUserCanSkipBouncer(userId)) {              mTrustManager.unlockedByBiometricForUser(userId, FACE);          } -        updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);          mLogger.d("onFaceAuthenticated");          for (int i = 0; i < mCallbacks.size(); i++) {              KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -1156,6 +1155,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab              }          } +        // Intentionally update the fingerprint running state after sending the +        // onBiometricAuthenticated callback to listeners. Updating the fingerprint listening state +        // can update the state of the device which listeners to the callback may rely on. +        // For example, the alternate bouncer visibility state or udfps finger down state. +        updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE); +          // Only authenticate face once when assistant is visible          mAssistantVisible = false; diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 3e03fb8dfaff..b8af59d78942 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -401,8 +401,6 @@ public class ScreenDecorations implements          mExecutor = mThreadFactory.buildDelayableExecutorOnHandler(mHandler);          mExecutor.execute(this::startOnScreenDecorationsThread);          mDotViewController.setUiExecutor(mExecutor); -        mJavaAdapter.alwaysCollectFlow(mFacePropertyRepository.getSensorLocation(), -                this::onFaceSensorLocationChanged);          mCommandRegistry.registerCommand(ScreenDecorCommand.SCREEN_DECOR_CMD_NAME,                  () -> new ScreenDecorCommand(mScreenDecorCommandCallback));      } @@ -579,6 +577,8 @@ public class ScreenDecorations implements          };          mDisplayTracker.addDisplayChangeCallback(mDisplayListener, new HandlerExecutor(mHandler));          updateConfiguration(); +        mJavaAdapter.alwaysCollectFlow(mFacePropertyRepository.getSensorLocation(), +                this::onFaceSensorLocationChanged);          Trace.endSection();      } @@ -1320,10 +1320,18 @@ public class ScreenDecorations implements      @VisibleForTesting      void onFaceSensorLocationChanged(Point location) {          mLogger.onSensorLocationChanged(); +          if (mExecutor != null) {              mExecutor.execute( -                    () -> updateOverlayProviderViews( -                            new Integer[]{mFaceScanningViewId})); +                    () -> { +                        if (getOverlayView(mFaceScanningViewId) == null) { +                            // face sensor location was just initialized +                            setupDecorations(); +                        } else { +                            updateOverlayProviderViews(new Integer[]{mFaceScanningViewId}); +                        } +                    } +            );          }      } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java index 7e96e48545ea..615363da073a 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java @@ -72,6 +72,7 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp      private boolean mEndAnimationCanceled = false;      @MagnificationState      private int mState = STATE_DISABLED; +    private Runnable mOnAnimationEndRunnable;      WindowMagnificationAnimationController(@UiContext Context context) {          this(context, newValueAnimator(context.getResources())); @@ -303,12 +304,7 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp              return;          } -        // If the animation is playing backwards, mStartSpec will be the final spec we would -        // like to reach. -        AnimationSpec spec = isReverse ? mStartSpec : mEndSpec; -        mController.updateWindowMagnificationInternal( -                spec.mScale, spec.mCenterX, spec.mCenterY, -                mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY); +        mOnAnimationEndRunnable.run();          if (mState == STATE_DISABLING) {              mController.deleteWindowMagnification(); @@ -333,6 +329,10 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp      public void onAnimationRepeat(Animator animation) {      } +    void setOnAnimationEndRunnable(Runnable runnable) { +        mOnAnimationEndRunnable = runnable; +    } +      private void sendAnimationCallback(boolean success) {          if (mAnimationCallback != null) {              try { diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index a847c3d510b1..9837e369bc91 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -260,6 +260,11 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold          mContext = context;          mHandler = handler;          mAnimationController = animationController; +        mAnimationController.setOnAnimationEndRunnable(() -> { +            if (Flags.createWindowlessWindowMagnifier()) { +                notifySourceBoundsChanged(); +            } +        });          mAnimationController.setWindowMagnificationController(this);          mWindowMagnifierCallback = callback;          mSysUiState = sysUiState; @@ -1051,11 +1056,15 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold              // Notify source bounds change when the magnifier is not animating.              if (!mAnimationController.isAnimating()) { -                mWindowMagnifierCallback.onSourceBoundsChanged(mDisplayId, mSourceBounds); +                notifySourceBoundsChanged();              }          }      } +    private void notifySourceBoundsChanged() { +        mWindowMagnifierCallback.onSourceBoundsChanged(mDisplayId, mSourceBounds); +    } +      /**       * Updates the position of {@link mSurfaceControlViewHost} and layout params of MirrorView based       * on the position and size of {@link #mMagnificationFrame}. diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java index 1018f70c7f60..eb840f1f4c90 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java @@ -244,11 +244,13 @@ class MenuInfoRepository {                  mSecureSettings.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),                  /* notifyForDescendants */ false, mMenuTargetFeaturesContentObserver,                  UserHandle.USER_CURRENT); -        mSecureSettings.registerContentObserverForUser( -                mSecureSettings.getUriFor(ENABLED_ACCESSIBILITY_SERVICES), -                /* notifyForDescendants */ false, -                mMenuTargetFeaturesContentObserver, -                UserHandle.USER_CURRENT); +        if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) { +            mSecureSettings.registerContentObserverForUser( +                    mSecureSettings.getUriFor(ENABLED_ACCESSIBILITY_SERVICES), +                    /* notifyForDescendants */ false, +                    mMenuTargetFeaturesContentObserver, +                    UserHandle.USER_CURRENT); +        }          mSecureSettings.registerContentObserverForUser(                  mSecureSettings.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE),                  /* notifyForDescendants */ false, mMenuSizeContentObserver, @@ -263,8 +265,10 @@ class MenuInfoRepository {                  UserHandle.USER_CURRENT);          mContext.registerComponentCallbacks(mComponentCallbacks); -        mAccessibilityManager.addAccessibilityServicesStateChangeListener( -                mA11yServicesStateChangeListener); +        if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) { +            mAccessibilityManager.addAccessibilityServicesStateChangeListener( +                    mA11yServicesStateChangeListener); +        }      }      void unregisterObserversAndCallbacks() { @@ -273,8 +277,10 @@ class MenuInfoRepository {          mContext.getContentResolver().unregisterContentObserver(mMenuFadeOutContentObserver);          mContext.unregisterComponentCallbacks(mComponentCallbacks); -        mAccessibilityManager.removeAccessibilityServicesStateChangeListener( -                mA11yServicesStateChangeListener); +        if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) { +            mAccessibilityManager.removeAccessibilityServicesStateChangeListener( +                    mA11yServicesStateChangeListener); +        }      }      interface OnSettingsContentsChanged { diff --git a/packages/SystemUI/src/com/android/systemui/ailabs/OWNERS b/packages/SystemUI/src/com/android/systemui/ailabs/OWNERS new file mode 100644 index 000000000000..b65d29c6a0bb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/ailabs/OWNERS @@ -0,0 +1,9 @@ +# Bug component: 1495344 + +dupin@google.com +linyuh@google.com +pauldpong@google.com +praveenj@google.com +vicliang@google.com +mfolkerts@google.com +yuklimko@google.com diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt index 3a45db17b64c..61d1c713fb77 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt @@ -323,7 +323,13 @@ class UdfpsControllerOverlay @JvmOverloads constructor(          overlayParams = updatedOverlayParams          sensorBounds = updatedOverlayParams.sensorBounds          getTouchOverlay()?.let { -            windowManager.updateViewLayout(it, coreLayoutParams.updateDimensions(null)) +            if (addViewRunnable != null) { +                // Only updateViewLayout if there's no pending view to add to WM. +                // If there is a pending view, that means the view hasn't been added yet so there's +                // no need to update any layouts. Instead the correct params will be used when the +                // view is eventually added. +                windowManager.updateViewLayout(it, coreLayoutParams.updateDimensions(null)) +            }          }      } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt index ec54e4ce5e86..9816896e3ea8 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerLegacy.kt @@ -282,7 +282,8 @@ open class UdfpsKeyguardViewControllerLegacy(      @VisibleForTesting      suspend fun listenForGoneToAodTransition(scope: CoroutineScope): Job {          return scope.launch { -            transitionInteractor.goneToAodTransition.collect { transitionStep -> +            transitionInteractor.transition(KeyguardState.GONE, KeyguardState.AOD).collect { +                transitionStep ->                  view.onDozeAmountChanged(                      transitionStep.value,                      transitionStep.value, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt index 7d6721903c37..591da4096956 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt @@ -18,7 +18,6 @@ package com.android.systemui.biometrics.domain.interactor  import android.content.Context  import android.content.res.Configuration -import android.view.Display  import com.android.systemui.biometrics.data.repository.DisplayStateRepository  import com.android.systemui.biometrics.shared.model.DisplayRotation  import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging @@ -28,7 +27,6 @@ import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.display.data.repository.DisplayRepository  import com.android.systemui.unfold.compat.ScreenSizeFoldProvider  import com.android.systemui.unfold.updates.FoldProvider -import com.android.systemui.util.kotlin.sample  import java.util.concurrent.Executor  import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope @@ -36,8 +34,6 @@ import kotlinx.coroutines.channels.awaitClose  import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.SharingStarted  import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.stateIn  /** Aggregates display state information. */ @@ -129,16 +125,7 @@ constructor(          screenSizeFoldProvider.onConfigurationChange(newConfig)      } -    private val defaultDisplay = -        displayRepository.displays.map { displays -> -            displays.firstOrNull { it.displayId == Display.DEFAULT_DISPLAY } -        } - -    override val isDefaultDisplayOff = -        displayRepository.displayChangeEvent -            .filter { it == Display.DEFAULT_DISPLAY } -            .sample(defaultDisplay) -            .map { it?.state == Display.STATE_OFF } +    override val isDefaultDisplayOff = displayRepository.defaultDisplayOff      override val isLargeScreen: Flow<Boolean> = displayStateRepository.isLargeScreen diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt index 83b3380ae6be..1eef91debab3 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt @@ -27,7 +27,8 @@ import com.android.systemui.biometrics.udfps.TouchProcessorResult.ProcessedTouch  import com.android.systemui.dagger.SysUISingleton  import javax.inject.Inject -private val SUPPORTED_ROTATIONS = setOf(Surface.ROTATION_90, Surface.ROTATION_270) +private val SUPPORTED_ROTATIONS = +    setOf(Surface.ROTATION_90, Surface.ROTATION_270, Surface.ROTATION_180)  /**   * TODO(b/259140693): Consider using an object pool of TouchProcessorResult to avoid allocations. diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt index 76d46ed9889f..072fe47df42b 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt @@ -463,6 +463,23 @@ object BiometricViewBinder {                          }                      }                  } + +                // Retry and confirmation when finger on sensor +                launch { +                    combine( +                            viewModel.canTryAgainNow, +                            viewModel.hasFingerOnSensor, +                            viewModel.isPendingConfirmation, +                            ::Triple +                        ) +                        .collect { (canRetry, fingerAcquired, pendingConfirmation) -> +                            if (canRetry && fingerAcquired) { +                                legacyCallback.onButtonTryAgain() +                            } else if (pendingConfirmation && fingerAcquired) { +                                viewModel.confirmAuthenticated() +                            } +                        } +                }              }          } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index 21ebff4d0b71..4e9acbd25b62 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -22,6 +22,7 @@ import android.content.pm.PackageManager  import android.graphics.Rect  import android.graphics.drawable.BitmapDrawable  import android.graphics.drawable.Drawable +import android.hardware.biometrics.BiometricFingerprintConstants  import android.hardware.biometrics.BiometricPrompt  import android.hardware.biometrics.Flags.customBiometricPrompt  import android.hardware.biometrics.PromptContentView @@ -32,6 +33,7 @@ import com.android.systemui.Flags.bpTalkback  import com.android.systemui.Flags.constraintBp  import com.android.systemui.biometrics.UdfpsUtils  import com.android.systemui.biometrics.Utils +import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor  import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor  import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor  import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor @@ -40,6 +42,7 @@ import com.android.systemui.biometrics.shared.model.BiometricModality  import com.android.systemui.biometrics.shared.model.DisplayRotation  import com.android.systemui.biometrics.shared.model.PromptKind  import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus  import com.android.systemui.res.R  import javax.inject.Inject  import kotlinx.coroutines.Job @@ -66,6 +69,7 @@ constructor(      promptSelectorInteractor: PromptSelectorInteractor,      @Application private val context: Context,      private val udfpsOverlayInteractor: UdfpsOverlayInteractor, +    private val biometricStatusInteractor: BiometricStatusInteractor,      private val udfpsUtils: UdfpsUtils  ) {      /** The set of modalities available for this prompt */ @@ -185,6 +189,24 @@ constructor(      /** Fingerprint sensor state. */      val fingerprintStartMode: Flow<FingerprintStartMode> = _fingerprintStartMode.asStateFlow() +    /** Whether a finger has been acquired by the sensor */ +    // TODO(b/331948073): Add support for detecting SFPS finger without authentication running +    val hasFingerBeenAcquired: Flow<Boolean> = +        combine(biometricStatusInteractor.fingerprintAcquiredStatus, modalities) { +                status, +                modalities -> +                modalities.hasSfps && +                    status is AcquiredFingerprintAuthenticationStatus && +                    status.acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START +            } +            .distinctUntilChanged() + +    /** Whether there is currently a finger on the sensor */ +    val hasFingerOnSensor: Flow<Boolean> = +        combine(hasFingerBeenAcquired, _isOverlayTouched) { hasFingerBeenAcquired, overlayTouched -> +            hasFingerBeenAcquired || overlayTouched +        } +      private val _forceLargeSize = MutableStateFlow(false)      private val _forceMediumSize = MutableStateFlow(false) diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java index 161458fdb33e..a90e60d2a8a3 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java @@ -56,4 +56,22 @@ public class BroadcastDialogController {              broadcastDialog.show();          }      } + +    /** Creates a [BroadcastDialog] for the user to switch broadcast or change the output device +     * +     * @param currentBroadcastAppName Indicates the APP name currently broadcasting +     * @param outputPkgName Indicates the output media package name to be switched +     * @param controller Indicates the dialog controller of the source view. +     */ +    public void createBroadcastDialogWithController( +            String currentBroadcastAppName, String outputPkgName, +            DialogTransitionAnimator.Controller controller) { +        SystemUIDialog broadcastDialog = mBroadcastDialogFactory.create( +                currentBroadcastAppName, outputPkgName).createDialog(); +        if (controller != null) { +            mDialogTransitionAnimator.show(broadcastDialog, controller); +        } else { +            broadcastDialog.show(); +        } +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt new file mode 100644 index 000000000000..e44f0543fc87 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.bluetooth.qsdialog + +import androidx.annotation.StringRes +import com.android.settingslib.bluetooth.BluetoothUtils +import com.android.settingslib.bluetooth.LocalBluetoothManager +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.res.R +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.stateIn + +internal sealed class AudioSharingButtonState { +    object Gone : AudioSharingButtonState() +    data class Visible(@StringRes val resId: Int) : AudioSharingButtonState() +} + +/** Holds business logic for the audio sharing state. */ +@SysUISingleton +internal class AudioSharingInteractor +@Inject +constructor( +    private val localBluetoothManager: LocalBluetoothManager?, +    bluetoothStateInteractor: BluetoothStateInteractor, +    deviceItemInteractor: DeviceItemInteractor, +    @Application private val coroutineScope: CoroutineScope, +    @Background private val backgroundDispatcher: CoroutineDispatcher, +) { +    /** Flow representing the update of AudioSharingButtonState. */ +    internal val audioSharingButtonStateUpdate: Flow<AudioSharingButtonState> = +        combine( +                bluetoothStateInteractor.bluetoothStateUpdate, +                deviceItemInteractor.deviceItemUpdate +            ) { bluetoothState, deviceItem -> +                getButtonState(bluetoothState, deviceItem) +            } +            .flowOn(backgroundDispatcher) +            .stateIn( +                coroutineScope, +                SharingStarted.WhileSubscribed(replayExpirationMillis = 0), +                initialValue = AudioSharingButtonState.Gone +            ) + +    private fun getButtonState( +        bluetoothState: Boolean, +        deviceItem: List<DeviceItem> +    ): AudioSharingButtonState { +        return when { +            // Don't show button when bluetooth is off +            !bluetoothState -> AudioSharingButtonState.Gone +            // Show sharing audio when broadcasting +            BluetoothUtils.isBroadcasting(localBluetoothManager) -> +                AudioSharingButtonState.Visible( +                    R.string.quick_settings_bluetooth_audio_sharing_button_sharing +                ) +            // When not broadcasting, don't show button if there's connected source in any device +            deviceItem.any { +                BluetoothUtils.hasConnectedBroadcastSource( +                    it.cachedBluetoothDevice, +                    localBluetoothManager +                ) +            } -> AudioSharingButtonState.Gone +            // Show audio sharing when there's a connected LE audio device +            deviceItem.any { BluetoothUtils.isActiveLeAudioDevice(it.cachedBluetoothDevice) } -> +                AudioSharingButtonState.Visible( +                    R.string.quick_settings_bluetooth_audio_sharing_button +                ) +            else -> AudioSharingButtonState.Gone +        } +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt index 94d7af74f1dd..17f9e634ec62 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractor.kt @@ -25,12 +25,17 @@ import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLoggin  import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background  import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.channels.awaitClose  import kotlinx.coroutines.flow.SharingStarted  import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.onStart  import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.withContext  /** Holds business logic for the Bluetooth Dialog's bluetooth and device connection state */  @SysUISingleton @@ -40,9 +45,10 @@ constructor(      private val localBluetoothManager: LocalBluetoothManager?,      private val logger: BluetoothTileDialogLogger,      @Application private val coroutineScope: CoroutineScope, +    @Background private val backgroundDispatcher: CoroutineDispatcher,  ) { -    internal val bluetoothStateUpdate: StateFlow<Boolean?> = +    internal val bluetoothStateUpdate: StateFlow<Boolean> =          conflatedCallbackFlow {                  val listener =                      object : BluetoothCallback { @@ -64,16 +70,22 @@ constructor(                  localBluetoothManager?.eventManager?.registerCallback(listener)                  awaitClose { localBluetoothManager?.eventManager?.unregisterCallback(listener) }              } +            .onStart { emit(isBluetoothEnabled()) } +            .flowOn(backgroundDispatcher)              .stateIn(                  coroutineScope,                  SharingStarted.WhileSubscribed(replayExpirationMillis = 0), -                initialValue = null +                initialValue = false              ) -    internal var isBluetoothEnabled: Boolean -        get() = localBluetoothManager?.bluetoothAdapter?.isEnabled == true -        set(value) { -            if (isBluetoothEnabled != value) { +    suspend fun isBluetoothEnabled(): Boolean = +        withContext(backgroundDispatcher) { +            localBluetoothManager?.bluetoothAdapter?.isEnabled == true +        } + +    suspend fun setBluetoothEnabled(value: Boolean) { +        withContext(backgroundDispatcher) { +            if (isBluetoothEnabled() != value) {                  localBluetoothManager?.bluetoothAdapter?.apply {                      if (value) enable() else disable()                      logger.logBluetoothState( @@ -83,6 +95,7 @@ constructor(                  }              }          } +    }      companion object {          private const val TAG = "BtStateInteractor" diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt index c7d171d5b804..dd8c0df387dc 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt @@ -27,6 +27,7 @@ import android.view.ViewGroup  import android.view.ViewGroup.LayoutParams.WRAP_CONTENT  import android.view.accessibility.AccessibilityNodeInfo  import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction +import android.widget.Button  import android.widget.ImageView  import android.widget.ProgressBar  import android.widget.Switch @@ -59,7 +60,6 @@ class BluetoothTileDialogDelegate  internal constructor(      @Assisted private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties,      @Assisted private val cachedContentHeight: Int, -    @Assisted private val bluetoothToggleInitialValue: Boolean,      @Assisted private val bluetoothTileDialogCallback: BluetoothTileDialogCallback,      @Assisted private val dismissListener: Runnable,      @Main private val mainDispatcher: CoroutineDispatcher, @@ -69,8 +69,7 @@ internal constructor(      private val systemuiDialogFactory: SystemUIDialog.Factory,  ) : SystemUIDialog.Delegate { -    private val mutableBluetoothStateToggle: MutableStateFlow<Boolean> = -        MutableStateFlow(bluetoothToggleInitialValue) +    private val mutableBluetoothStateToggle: MutableStateFlow<Boolean?> = MutableStateFlow(null)      internal val bluetoothStateToggle          get() = mutableBluetoothStateToggle.asStateFlow() @@ -99,7 +98,6 @@ internal constructor(          fun create(              initialUiProperties: BluetoothTileDialogViewModel.UiProperties,              cachedContentHeight: Int, -            bluetoothEnabled: Boolean,              dialogCallback: BluetoothTileDialogCallback,              dimissListener: Runnable          ): BluetoothTileDialogDelegate @@ -130,6 +128,9 @@ internal constructor(          getPairNewDeviceButton(dialog).setOnClickListener {              bluetoothTileDialogCallback.onPairNewDeviceClicked(it)          } +        getAudioSharingButtonView(dialog).setOnClickListener { +            bluetoothTileDialogCallback.onAudioSharingButtonClicked(it) +        }          getScrollViewContent(dialog).apply {              minimumHeight =                  resources.getDimensionPixelSize(initialUiProperties.scrollViewMinHeightResId) @@ -211,9 +212,19 @@ internal constructor(          getAutoOnToggleInfoTextView(dialog).text = dialog.context.getString(infoResId)      } +    internal fun onAudioSharingButtonUpdated( +        dialog: SystemUIDialog, +        visibility: Int, +        label: String? +    ) { +        getAudioSharingButtonView(dialog).apply { +            this.visibility = visibility +            label?.let { text = it } +        } +    } +      private fun setupToggle(dialog: SystemUIDialog) {          val toggleView = getToggleView(dialog) -        toggleView.isChecked = bluetoothToggleInitialValue          toggleView.setOnCheckedChangeListener { view, isChecked ->              mutableBluetoothStateToggle.value = isChecked              view.apply { @@ -259,6 +270,10 @@ internal constructor(          return dialog.requireViewById(R.id.bluetooth_auto_on_toggle)      } +    private fun getAudioSharingButtonView(dialog: SystemUIDialog): Button { +        return dialog.requireViewById(R.id.audio_sharing_button) +    } +      private fun getAutoOnToggleView(dialog: SystemUIDialog): View {          return dialog.requireViewById(R.id.bluetooth_auto_on_toggle_layout)      } @@ -412,6 +427,8 @@ internal constructor(          const val ACTION_PREVIOUSLY_CONNECTED_DEVICE =              "com.android.settings.PREVIOUSLY_CONNECTED_DEVICE"          const val ACTION_PAIR_NEW_DEVICE = "android.settings.BLUETOOTH_PAIRING_SETTINGS" +        const val ACTION_AUDIO_SHARING = +            "com.google.android.settings.BLUETOOTH_AUDIO_SHARING_SETTINGS"          const val DISABLED_ALPHA = 0.3f          const val ENABLED_ALPHA = 1f          const val PROGRESS_BAR_ANIMATION_DURATION_MS = 1500L diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt index add1647143d8..b592b8ed4332 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt @@ -30,9 +30,12 @@ enum class BluetoothTileDialogUiEvent(val metricId: Int) : UiEventLogger.UiEvent      @UiEvent(doc = "Connected device clicked to active") CONNECTED_DEVICE_SET_ACTIVE(1499),      @UiEvent(doc = "Saved clicked to connect") SAVED_DEVICE_CONNECT(1500),      @UiEvent(doc = "Active device clicked to disconnect") ACTIVE_DEVICE_DISCONNECT(1507), +    @UiEvent(doc = "Audio sharing device clicked, do nothing") AUDIO_SHARING_DEVICE_CLICKED(1699),      @UiEvent(doc = "Connected other device clicked to disconnect")      CONNECTED_OTHER_DEVICE_DISCONNECT(1508), -    @UiEvent(doc = "The auto on toggle is clicked") BLUETOOTH_AUTO_ON_TOGGLE_CLICKED(1617); +    @UiEvent(doc = "The auto on toggle is clicked") BLUETOOTH_AUTO_ON_TOGGLE_CLICKED(1617), +    @UiEvent(doc = "The audio sharing button is clicked") +    BLUETOOTH_AUDIO_SHARING_BUTTON_CLICKED(1700);      override fun getId() = metricId  } diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt index e65b65710f94..eb919e3ca36b 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModel.kt @@ -28,9 +28,11 @@ import androidx.annotation.StringRes  import androidx.annotation.VisibleForTesting  import com.android.internal.jank.InteractionJankMonitor  import com.android.internal.logging.UiEventLogger +import com.android.settingslib.bluetooth.BluetoothUtils  import com.android.systemui.Prefs  import com.android.systemui.animation.DialogCuj  import com.android.systemui.animation.DialogTransitionAnimator +import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogDelegate.Companion.ACTION_AUDIO_SHARING  import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogDelegate.Companion.ACTION_BLUETOOTH_DEVICE_DETAILS  import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogDelegate.Companion.ACTION_PAIR_NEW_DEVICE  import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogDelegate.Companion.ACTION_PREVIOUSLY_CONNECTED_DEVICE @@ -61,6 +63,7 @@ constructor(      private val deviceItemInteractor: DeviceItemInteractor,      private val bluetoothStateInteractor: BluetoothStateInteractor,      private val bluetoothAutoOnInteractor: BluetoothAutoOnInteractor, +    private val audioSharingInteractor: AudioSharingInteractor,      private val dialogTransitionAnimator: DialogTransitionAnimator,      private val activityStarter: ActivityStarter,      private val uiEventLogger: UiEventLogger, @@ -119,7 +122,8 @@ constructor(                                      dialog,                                      it.take(MAX_DEVICE_ITEM_ENTRY),                                      showSeeAll = it.size > MAX_DEVICE_ITEM_ENTRY, -                                    showPairNewDevice = bluetoothStateInteractor.isBluetoothEnabled +                                    showPairNewDevice = +                                        bluetoothStateInteractor.isBluetoothEnabled()                                  )                                  animateProgressBar(dialog, false)                              } @@ -142,10 +146,25 @@ constructor(                      }                      .launchIn(this) +                if (BluetoothUtils.isAudioSharingEnabled()) { +                    audioSharingInteractor.audioSharingButtonStateUpdate +                        .onEach { +                            if (it is AudioSharingButtonState.Visible) { +                                dialogDelegate.onAudioSharingButtonUpdated( +                                    dialog, +                                    VISIBLE, +                                    context.getString(it.resId) +                                ) +                            } else { +                                dialogDelegate.onAudioSharingButtonUpdated(dialog, GONE, null) +                            } +                        } +                        .launchIn(this) +                } +                  // bluetoothStateUpdate is emitted when bluetooth on/off state is changed, re-fetch                  // the device item list.                  bluetoothStateInteractor.bluetoothStateUpdate -                    .filterNotNull()                      .onEach {                          dialogDelegate.onBluetoothStateUpdated(                              dialog, @@ -165,9 +184,10 @@ constructor(                  // bluetoothStateToggle is emitted when user toggles the bluetooth state switch,                  // send the new value to the bluetoothStateInteractor and animate the progress bar.                  dialogDelegate.bluetoothStateToggle +                    .filterNotNull()                      .onEach {                          dialogDelegate.animateProgressBar(dialog, true) -                        bluetoothStateInteractor.isBluetoothEnabled = it +                        bluetoothStateInteractor.setBluetoothEnabled(it)                      }                      .launchIn(this) @@ -222,11 +242,10 @@ constructor(          return bluetoothDialogDelegateFactory.create(              UiProperties.build( -                bluetoothStateInteractor.isBluetoothEnabled, +                bluetoothStateInteractor.isBluetoothEnabled(),                  isAutoOnToggleFeatureAvailable()              ),              cachedContentHeight, -            bluetoothStateInteractor.isBluetoothEnabled,              this@BluetoothTileDialogViewModel,              { cancelJob() }          ) @@ -256,6 +275,11 @@ constructor(          startSettingsActivity(Intent(ACTION_PAIR_NEW_DEVICE), view)      } +    override fun onAudioSharingButtonClicked(view: View) { +        uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_AUDIO_SHARING_BUTTON_CLICKED) +        startSettingsActivity(Intent(ACTION_AUDIO_SHARING), view) +    } +      private fun cancelJob() {          job?.cancel()          job = null @@ -312,4 +336,5 @@ interface BluetoothTileDialogCallback {      fun onDeviceItemGearClicked(deviceItem: DeviceItem, view: View)      fun onSeeAllClicked(view: View)      fun onPairNewDeviceClicked(view: View) +    fun onAudioSharingButtonClicked(view: View)  } diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItem.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItem.kt index dc5efefdfb16..0ea98d14bca3 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItem.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItem.kt @@ -37,6 +37,7 @@ import com.android.settingslib.bluetooth.CachedBluetoothDevice  enum class DeviceItemType {      ACTIVE_MEDIA_BLUETOOTH_DEVICE, +    AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,      AVAILABLE_MEDIA_BLUETOOTH_DEVICE,      CONNECTED_BLUETOOTH_DEVICE,      SAVED_BLUETOOTH_DEVICE, diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt index f04ba75ca3ef..49d0847ab0c7 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt @@ -21,13 +21,16 @@ import android.content.Context  import android.media.AudioManager  import com.android.settingslib.bluetooth.BluetoothUtils  import com.android.settingslib.bluetooth.CachedBluetoothDevice +import com.android.settingslib.bluetooth.LocalBluetoothManager  import com.android.settingslib.flags.Flags +import com.android.settingslib.flags.Flags.enableLeAudioSharing  import com.android.systemui.res.R  private val backgroundOn = R.drawable.settingslib_switch_bar_bg_on  private val backgroundOff = R.drawable.bluetooth_tile_dialog_bg_off  private val backgroundOffBusy = R.drawable.bluetooth_tile_dialog_bg_off_busy  private val connected = R.string.quick_settings_bluetooth_device_connected +private val audioSharing = R.string.quick_settings_bluetooth_device_audio_sharing  private val saved = R.string.quick_settings_bluetooth_device_saved  private val actionAccessibilityLabelActivate =      R.string.accessibility_quick_settings_bluetooth_device_tap_to_activate @@ -39,35 +42,81 @@ internal abstract class DeviceItemFactory {      abstract fun isFilterMatched(          context: Context,          cachedDevice: CachedBluetoothDevice, -        audioManager: AudioManager? +        audioManager: AudioManager,      ): Boolean      abstract fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem + +    companion object { +        @JvmStatic +        fun createDeviceItem( +            context: Context, +            cachedDevice: CachedBluetoothDevice, +            type: DeviceItemType, +            connectionSummary: String, +            background: Int, +            actionAccessibilityLabel: String +        ): DeviceItem { +            return DeviceItem( +                type = type, +                cachedBluetoothDevice = cachedDevice, +                deviceName = cachedDevice.name, +                connectionSummary = connectionSummary, +                iconWithDescription = +                    BluetoothUtils.getBtClassDrawableWithDescription(context, cachedDevice).let { +                        Pair(it.first, it.second) +                    }, +                background = background, +                isEnabled = !cachedDevice.isBusy, +                actionAccessibilityLabel = actionAccessibilityLabel +            ) +        } +    }  }  internal open class ActiveMediaDeviceItemFactory : DeviceItemFactory() {      override fun isFilterMatched(          context: Context,          cachedDevice: CachedBluetoothDevice, -        audioManager: AudioManager? +        audioManager: AudioManager      ): Boolean {          return BluetoothUtils.isActiveMediaDevice(cachedDevice) &&              BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, audioManager)      }      override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem { -        return DeviceItem( -            type = DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE, -            cachedBluetoothDevice = cachedDevice, -            deviceName = cachedDevice.name, -            connectionSummary = cachedDevice.connectionSummary ?: "", -            iconWithDescription = -                BluetoothUtils.getBtClassDrawableWithDescription(context, cachedDevice).let { p -> -                    Pair(p.first, p.second) -                }, -            background = backgroundOn, -            isEnabled = !cachedDevice.isBusy, -            actionAccessibilityLabel = context.getString(actionAccessibilityLabelDisconnect), +        return createDeviceItem( +            context, +            cachedDevice, +            DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE, +            cachedDevice.connectionSummary ?: "", +            backgroundOn, +            context.getString(actionAccessibilityLabelDisconnect) +        ) +    } +} + +internal class AudioSharingMediaDeviceItemFactory( +    private val localBluetoothManager: LocalBluetoothManager? +) : DeviceItemFactory() { +    override fun isFilterMatched( +        context: Context, +        cachedDevice: CachedBluetoothDevice, +        audioManager: AudioManager +    ): Boolean { +        return enableLeAudioSharing() && +            BluetoothUtils.hasConnectedBroadcastSource(cachedDevice, localBluetoothManager) +    } + +    override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem { +        return createDeviceItem( +            context, +            cachedDevice, +            DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE, +            cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() } +                ?: context.getString(audioSharing), +            if (cachedDevice.isBusy) backgroundOffBusy else backgroundOn, +            ""          )      }  } @@ -76,7 +125,7 @@ internal class ActiveHearingDeviceItemFactory : ActiveMediaDeviceItemFactory() {      override fun isFilterMatched(          context: Context,          cachedDevice: CachedBluetoothDevice, -        audioManager: AudioManager? +        audioManager: AudioManager      ): Boolean {          return BluetoothUtils.isActiveMediaDevice(cachedDevice) &&              BluetoothUtils.isAvailableHearingDevice(cachedDevice) @@ -87,27 +136,21 @@ internal open class AvailableMediaDeviceItemFactory : DeviceItemFactory() {      override fun isFilterMatched(          context: Context,          cachedDevice: CachedBluetoothDevice, -        audioManager: AudioManager? +        audioManager: AudioManager      ): Boolean {          return !BluetoothUtils.isActiveMediaDevice(cachedDevice) &&              BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, audioManager)      } -    // TODO(b/298124674): move create() to the abstract class to reduce duplicate code      override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem { -        return DeviceItem( -            type = DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE, -            cachedBluetoothDevice = cachedDevice, -            deviceName = cachedDevice.name, -            connectionSummary = cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() } -                    ?: context.getString(connected), -            iconWithDescription = -                BluetoothUtils.getBtClassDrawableWithDescription(context, cachedDevice).let { p -> -                    Pair(p.first, p.second) -                }, -            background = if (cachedDevice.isBusy) backgroundOffBusy else backgroundOff, -            isEnabled = !cachedDevice.isBusy, -            actionAccessibilityLabel = context.getString(actionAccessibilityLabelActivate), +        return createDeviceItem( +            context, +            cachedDevice, +            DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE, +            cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() } +                ?: context.getString(connected), +            if (cachedDevice.isBusy) backgroundOffBusy else backgroundOff, +            context.getString(actionAccessibilityLabelActivate)          )      }  } @@ -116,7 +159,7 @@ internal class AvailableHearingDeviceItemFactory : ActiveMediaDeviceItemFactory(      override fun isFilterMatched(          context: Context,          cachedDevice: CachedBluetoothDevice, -        audioManager: AudioManager? +        audioManager: AudioManager      ): Boolean {          return !BluetoothUtils.isActiveMediaDevice(cachedDevice) &&              BluetoothUtils.isAvailableHearingDevice(cachedDevice) @@ -127,32 +170,25 @@ internal class ConnectedDeviceItemFactory : DeviceItemFactory() {      override fun isFilterMatched(          context: Context,          cachedDevice: CachedBluetoothDevice, -        audioManager: AudioManager? +        audioManager: AudioManager      ): Boolean {          return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) { -            !BluetoothUtils.isExclusivelyManagedBluetoothDevice( -                context, -                cachedDevice.getDevice() -            ) && BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager) +            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) && +                BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)          } else {              BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)          }      }      override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem { -        return DeviceItem( -            type = DeviceItemType.CONNECTED_BLUETOOTH_DEVICE, -            cachedBluetoothDevice = cachedDevice, -            deviceName = cachedDevice.name, -            connectionSummary = cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() } -                    ?: context.getString(connected), -            iconWithDescription = -                BluetoothUtils.getBtClassDrawableWithDescription(context, cachedDevice).let { p -> -                    Pair(p.first, p.second) -                }, -            background = if (cachedDevice.isBusy) backgroundOffBusy else backgroundOff, -            isEnabled = !cachedDevice.isBusy, -            actionAccessibilityLabel = context.getString(actionAccessibilityLabelDisconnect), +        return createDeviceItem( +            context, +            cachedDevice, +            DeviceItemType.CONNECTED_BLUETOOTH_DEVICE, +            cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() } +                ?: context.getString(connected), +            if (cachedDevice.isBusy) backgroundOffBusy else backgroundOff, +            context.getString(actionAccessibilityLabelDisconnect)          )      }  } @@ -161,32 +197,26 @@ internal open class SavedDeviceItemFactory : DeviceItemFactory() {      override fun isFilterMatched(          context: Context,          cachedDevice: CachedBluetoothDevice, -        audioManager: AudioManager? +        audioManager: AudioManager      ): Boolean {          return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) { -            !BluetoothUtils.isExclusivelyManagedBluetoothDevice( -                context, -                cachedDevice.getDevice() -            ) && cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected +            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) && +                cachedDevice.bondState == BluetoothDevice.BOND_BONDED && +                !cachedDevice.isConnected          } else {              cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected          }      }      override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem { -        return DeviceItem( -            type = DeviceItemType.SAVED_BLUETOOTH_DEVICE, -            cachedBluetoothDevice = cachedDevice, -            deviceName = cachedDevice.name, -            connectionSummary = cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() } -                    ?: context.getString(saved), -            iconWithDescription = -                BluetoothUtils.getBtClassDrawableWithDescription(context, cachedDevice).let { p -> -                    Pair(p.first, p.second) -                }, -            background = if (cachedDevice.isBusy) backgroundOffBusy else backgroundOff, -            isEnabled = !cachedDevice.isBusy, -            actionAccessibilityLabel = context.getString(actionAccessibilityLabelActivate), +        return createDeviceItem( +            context, +            cachedDevice, +            DeviceItemType.SAVED_BLUETOOTH_DEVICE, +            cachedDevice.connectionSummary.takeUnless { it.isNullOrEmpty() } +                ?: context.getString(saved), +            if (cachedDevice.isBusy) backgroundOffBusy else backgroundOff, +            context.getString(actionAccessibilityLabelActivate)          )      }  } @@ -195,7 +225,7 @@ internal class SavedHearingDeviceItemFactory : SavedDeviceItemFactory() {      override fun isFilterMatched(          context: Context,          cachedDevice: CachedBluetoothDevice, -        audioManager: AudioManager? +        audioManager: AudioManager      ): Boolean {          return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {              !BluetoothUtils.isExclusivelyManagedBluetoothDevice( diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt index 4e28cafb5004..66e593b94b21 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt @@ -113,6 +113,7 @@ constructor(      private var deviceItemFactoryList: List<DeviceItemFactory> =          listOf(              ActiveMediaDeviceItemFactory(), +            AudioSharingMediaDeviceItemFactory(localBluetoothManager),              AvailableMediaDeviceItemFactory(),              ConnectedDeviceItemFactory(),              SavedDeviceItemFactory() @@ -121,6 +122,7 @@ constructor(      private var displayPriority: List<DeviceItemType> =          listOf(              DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE, +            DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE,              DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,              DeviceItemType.CONNECTED_BLUETOOTH_DEVICE,              DeviceItemType.SAVED_BLUETOOTH_DEVICE, @@ -177,6 +179,9 @@ constructor(                          disconnect()                          uiEventLogger.log(BluetoothTileDialogUiEvent.ACTIVE_DEVICE_DISCONNECT)                      } +                    DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> { +                        uiEventLogger.log(BluetoothTileDialogUiEvent.AUDIO_SHARING_DEVICE_CLICKED) +                    }                      DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE -> {                          setActive()                          uiEventLogger.log(BluetoothTileDialogUiEvent.CONNECTED_DEVICE_SET_ACTIVE) diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt index 7525ce0f98ac..fa19bf478453 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt @@ -27,9 +27,9 @@ import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository  import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor  import com.android.systemui.keyguard.shared.model.KeyguardState -import com.android.systemui.keyguard.shared.model.TransitionState  import com.android.systemui.plugins.statusbar.StatusBarStateController  import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.util.kotlin.BooleanFlowOperators.or  import com.android.systemui.util.time.SystemClock  import dagger.Lazy  import javax.inject.Inject @@ -78,15 +78,14 @@ constructor(              bouncerRepository.alternateBouncerUIAvailable          }      private val isDozingOrAod: Flow<Boolean> = -        keyguardTransitionInteractor -            .get() -            .transitions -            .map { -                it.to == KeyguardState.DOZING || -                    it.to == KeyguardState.AOD || -                    ((it.from == KeyguardState.DOZING || it.from == KeyguardState.AOD) && -                        it.transitionState != TransitionState.FINISHED) -            } +        or( +                keyguardTransitionInteractor.get().transitionValue(KeyguardState.DOZING).map { +                    it > 0f +                }, +                keyguardTransitionInteractor.get().transitionValue(KeyguardState.AOD).map { +                    it > 0f +                }, +            )              .distinctUntilChanged()      /** diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt index aeb564d53195..02a40d93ab65 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt @@ -16,6 +16,7 @@  package com.android.systemui.bouncer.domain.interactor +import com.android.compose.animation.scene.SceneKey  import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor  import com.android.systemui.authentication.domain.interactor.AuthenticationResult  import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Sim @@ -26,6 +27,8 @@ import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor  import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.Scenes  import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.async @@ -47,6 +50,7 @@ constructor(      private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,      private val falsingInteractor: FalsingInteractor,      private val powerInteractor: PowerInteractor, +    sceneInteractor: SceneInteractor,  ) {      private val _onIncorrectBouncerInput = MutableSharedFlow<Unit>()      val onIncorrectBouncerInput: SharedFlow<Unit> = _onIncorrectBouncerInput @@ -80,6 +84,10 @@ constructor(              }              .map {} +    /** The scene to show when bouncer is dismissed. */ +    val dismissDestination: Flow<SceneKey> = +        sceneInteractor.previousScene.map { it ?: Scenes.Lockscreen } +      /** Notifies that the user has places down a pointer, not necessarily dragging just yet. */      fun onDown() {          falsingInteractor.avoidGesture() diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt index 5c07cc57c620..7c41b75d7105 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt @@ -21,6 +21,12 @@ import android.app.admin.DevicePolicyResources  import android.content.Context  import android.graphics.Bitmap  import androidx.core.graphics.drawable.toBitmap +import com.android.compose.animation.scene.Back +import com.android.compose.animation.scene.SceneKey +import com.android.compose.animation.scene.Swipe +import com.android.compose.animation.scene.SwipeDirection +import com.android.compose.animation.scene.UserAction +import com.android.compose.animation.scene.UserActionResult  import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor  import com.android.systemui.authentication.shared.model.AuthenticationMethodModel  import com.android.systemui.authentication.shared.model.AuthenticationWipeModel @@ -35,6 +41,7 @@ import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.inputmethod.domain.interactor.InputMethodInteractor +import com.android.systemui.scene.shared.model.Scenes  import com.android.systemui.user.domain.interactor.SelectedUserInteractor  import com.android.systemui.user.ui.viewmodel.UserActionViewModel  import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel @@ -82,6 +89,15 @@ class BouncerViewModel(                  initialValue = null,              ) +    val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = +        bouncerInteractor.dismissDestination +            .map(::destinationSceneMap) +            .stateIn( +                applicationScope, +                SharingStarted.WhileSubscribed(), +                initialValue = destinationSceneMap(Scenes.Lockscreen), +            ) +      val message: BouncerMessageViewModel = bouncerMessageViewModel      val userSwitcherDropdown: StateFlow<List<UserSwitcherDropdownItemViewModel>> = @@ -310,8 +326,7 @@ class BouncerViewModel(                  { message },                  failedAttempts,                  remainingAttempts, -            ) -                ?: message +            ) ?: message          } else {              message          } @@ -328,8 +343,7 @@ class BouncerViewModel(                      .KEYGUARD_DIALOG_FAILED_ATTEMPTS_ERASING_PROFILE,                  { message },                  failedAttempts, -            ) -                ?: message +            ) ?: message          } else {              message          } @@ -357,6 +371,12 @@ class BouncerViewModel(          }      } +    private fun destinationSceneMap(prevScene: SceneKey) = +        mapOf( +            Back to UserActionResult(prevScene), +            Swipe(SwipeDirection.Down) to UserActionResult(prevScene), +        ) +      data class DialogViewModel(          val text: String, @@ -400,13 +420,13 @@ object BouncerViewModelModule {              simBouncerInteractor = simBouncerInteractor,              authenticationInteractor = authenticationInteractor,              selectedUserInteractor = selectedUserInteractor, +            devicePolicyManager = devicePolicyManager, +            bouncerMessageViewModel = bouncerMessageViewModel,              flags = flags,              selectedUser = userSwitcherViewModel.selectedUser,              users = userSwitcherViewModel.users,              userSwitcherMenu = userSwitcherViewModel.menu,              actionButton = actionButtonInteractor.actionButton, -            devicePolicyManager = devicePolicyManager, -            bouncerMessageViewModel = bouncerMessageViewModel,          )      }  } diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt index 12cac9251b25..4c2380c5e4db 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt @@ -135,8 +135,11 @@ class PinBouncerViewModel(          onIntentionalUserInput() -        mutablePinInput.value = pinInput.append(input) -        tryAuthenticate(useAutoConfirm = true) +        val maxInputLength = hintedPinLength.value ?: Int.MAX_VALUE +        if (pinInput.getPin().size < maxInputLength) { +            mutablePinInput.value = pinInput.append(input) +            tryAuthenticate(useAutoConfirm = true) +        }      }      /** Notifies that the user clicked the backspace button. */ diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt index 4d328d6cb13f..5a174b9d2f80 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt @@ -21,6 +21,7 @@ import com.android.compose.animation.scene.SceneKey  import com.android.systemui.CoreStartable  import com.android.systemui.communal.domain.interactor.CommunalInteractor  import com.android.systemui.communal.shared.model.CommunalScenes +import com.android.systemui.communal.shared.model.CommunalTransitionKeys  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.dagger.qualifiers.Background @@ -70,9 +71,9 @@ constructor(          keyguardTransitionInteractor.startedKeyguardTransitionStep              .mapLatest(::determineSceneAfterTransition)              .filterNotNull() -            // TODO(b/322787129): Also set a custom transition animation here to avoid the regular -            // slide-in animation when setting the scene programmatically -            .onEach { nextScene -> communalInteractor.changeScene(nextScene) } +            .onEach { nextScene -> +                communalInteractor.changeScene(nextScene, CommunalTransitionKeys.SimpleFade) +            }              .launchIn(applicationScope)          // TODO(b/322787129): re-enable once custom animations are in place @@ -143,7 +144,14 @@ constructor(          val docked = dockManager.isDocked          return when { -            docked && to == KeyguardState.LOCKSCREEN && from == KeyguardState.DREAMING -> { +            to == KeyguardState.OCCLUDED -> { +                // Hide communal when an activity is started on keyguard, to ensure the activity +                // underneath the hub is shown. +                CommunalScenes.Blank +            } +            to == KeyguardState.GLANCEABLE_HUB && from == KeyguardState.OCCLUDED -> { +                // When transitioning to the hub from an occluded state, fade out the hub without +                // doing any translation.                  CommunalScenes.Communal              }              to == KeyguardState.GONE -> CommunalScenes.Blank diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt index c724244816ea..9debe0e56083 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt @@ -57,6 +57,9 @@ interface CommunalSettingsRepository {       * Settings.       */      fun getWidgetCategories(user: UserInfo): Flow<CommunalWidgetCategories> + +    /** Keyguard widgets enabled state by Device Policy Manager for the specified user. */ +    fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean>  }  @SysUISingleton @@ -115,6 +118,16 @@ constructor(              }              .flowOn(bgDispatcher) +    override fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> = +        broadcastDispatcher +            .broadcastFlow( +                filter = +                    IntentFilter(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), +                user = user.userHandle +            ) +            .emitOnStart() +            .map { devicePolicyManager.areKeyguardWidgetsAllowed(user.id) } +      private fun getEnabledByUser(user: UserInfo): Flow<Boolean> =          secureSettings              .observerFlow(userId = user.id, names = arrayOf(Settings.Secure.GLANCEABLE_HUB_ENABLED)) @@ -128,16 +141,6 @@ constructor(                  ) == 1              } -    private fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> = -        broadcastDispatcher -            .broadcastFlow( -                filter = -                    IntentFilter(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), -                user = user.userHandle -            ) -            .emitOnStart() -            .map { devicePolicyManager.areKeyguardWidgetsAllowed(user.id) } -      companion object {          const val GLANCEABLE_HUB_CONTENT_SETTING = "glanceable_hub_content_setting"          private const val ENABLED_SETTING_DEFAULT = 1 diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index 246d5d92f8b0..373e1c9daa7b 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -44,6 +44,8 @@ import com.android.systemui.communal.widgets.EditWidgetsActivityStarter  import com.android.systemui.communal.widgets.WidgetConfigurator  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dock.DockManager +import com.android.systemui.dock.retrieveIsDocked  import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor  import com.android.systemui.log.LogBuffer  import com.android.systemui.log.core.Logger @@ -97,12 +99,13 @@ constructor(      mediaRepository: CommunalMediaRepository,      smartspaceRepository: SmartspaceRepository,      keyguardInteractor: KeyguardInteractor, -    communalSettingsInteractor: CommunalSettingsInteractor, +    private val communalSettingsInteractor: CommunalSettingsInteractor,      private val appWidgetHost: CommunalAppWidgetHost,      private val editWidgetsActivityStarter: EditWidgetsActivityStarter,      private val userTracker: UserTracker,      private val activityStarter: ActivityStarter,      private val userManager: UserManager, +    private val dockManager: DockManager,      sceneInteractor: SceneInteractor,      sceneContainerFlags: SceneContainerFlags,      @CommunalLog logBuffer: LogBuffer, @@ -123,7 +126,7 @@ constructor(          and(                  communalSettingsInteractor.isCommunalEnabled,                  not(keyguardInteractor.isEncryptedOrLockdown), -                or(keyguardInteractor.isKeyguardVisible, keyguardInteractor.isDreaming) +                or(keyguardInteractor.isKeyguardShowing, keyguardInteractor.isDreaming)              )              .distinctUntilChanged()              .onEach { available -> @@ -143,6 +146,9 @@ constructor(                  replay = 1,              ) +    /** Whether to show communal by default */ +    val showByDefault: Flow<Boolean> = and(isCommunalAvailable, dockManager.retrieveIsDocked()) +      /**       * Target scene as requested by the underlying [SceneTransitionLayout] or through [changeScene].       * @@ -352,7 +358,14 @@ constructor(      /** A list of widget content to be displayed in the communal hub. */      val widgetContent: Flow<List<WidgetContent>> =          combine( -            widgetRepository.communalWidgets.map { filterWidgetsByExistingUsers(it) }, +            widgetRepository.communalWidgets +                .map { filterWidgetsByExistingUsers(it) } +                .combine(communalSettingsInteractor.allowedByDevicePolicyForWorkProfile) { +                    // exclude widgets under work profile if not allowed by device policy +                    widgets, +                    allowedForWorkProfile -> +                    filterWidgetsAllowedByDevicePolicy(widgets, allowedForWorkProfile) +                },              communalSettingsInteractor.communalWidgetCategories,              updateOnWorkProfileBroadcastReceived,          ) { widgets, allowedCategories, _ -> @@ -374,6 +387,19 @@ constructor(              }          } +    /** Filter widgets based on whether their associated profile is allowed by device policy. */ +    private fun filterWidgetsAllowedByDevicePolicy( +        list: List<CommunalWidgetContentModel>, +        allowedByDevicePolicyForWorkProfile: Boolean +    ): List<CommunalWidgetContentModel> = +        if (allowedByDevicePolicyForWorkProfile) { +            list +        } else { +            // Get associated work profile for the currently selected user. +            val workProfile = userTracker.userProfiles.find { it.isManagedProfile } +            list.filter { it.providerInfo.profile.identifier != workProfile?.id } +        } +      /** A flow of available smartspace targets. Currently only showing timers. */      private val smartspaceTargets: Flow<List<SmartspaceTarget>> =          if (!smartspaceRepository.isSmartspaceRemoteViewsEnabled) { diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt index 20f60b79c784..f9de60984e2d 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt @@ -16,6 +16,8 @@  package com.android.systemui.communal.domain.interactor +import android.content.pm.UserInfo +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow  import com.android.systemui.communal.data.model.CommunalEnabledState  import com.android.systemui.communal.data.model.CommunalWidgetCategories  import com.android.systemui.communal.data.repository.CommunalSettingsRepository @@ -24,13 +26,18 @@ import com.android.systemui.dagger.qualifiers.Background  import com.android.systemui.log.dagger.CommunalTableLog  import com.android.systemui.log.table.TableLogBuffer  import com.android.systemui.log.table.logDiffsForTable +import com.android.systemui.settings.UserTracker  import com.android.systemui.user.domain.interactor.SelectedUserInteractor +import java.util.concurrent.Executor  import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.SharingStarted  import kotlinx.coroutines.flow.StateFlow  import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf  import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.stateIn @@ -40,8 +47,10 @@ class CommunalSettingsInteractor  @Inject  constructor(      @Background private val bgScope: CoroutineScope, +    @Background private val bgExecutor: Executor,      private val repository: CommunalSettingsRepository,      userInteractor: SelectedUserInteractor, +    private val userTracker: UserTracker,      @CommunalTableLog tableLogBuffer: TableLogBuffer,  ) {      /** Whether or not communal is enabled for the currently selected user. */ @@ -68,4 +77,33 @@ constructor(                  started = SharingStarted.Eagerly,                  initialValue = CommunalWidgetCategories().categories              ) + +    private val workProfileUserInfoCallbackFlow: Flow<UserInfo?> = conflatedCallbackFlow { +        fun send(profiles: List<UserInfo>) { +            trySend(profiles.find { it.isManagedProfile }) +        } + +        val callback = +            object : UserTracker.Callback { +                override fun onProfilesChanged(profiles: List<UserInfo>) { +                    send(profiles) +                } +            } +        userTracker.addCallback(callback, bgExecutor) +        send(userTracker.userProfiles) + +        awaitClose { userTracker.removeCallback(callback) } +    } + +    /** Whether or not keyguard widgets are allowed for work profile by device policy manager. */ +    val allowedByDevicePolicyForWorkProfile: StateFlow<Boolean> = +        workProfileUserInfoCallbackFlow +            .flatMapLatest { workProfile -> +                workProfile?.let { repository.getAllowedByDevicePolicy(it) } ?: flowOf(false) +            } +            .stateIn( +                scope = bgScope, +                started = SharingStarted.WhileSubscribed(), +                initialValue = false +            )  } diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt new file mode 100644 index 000000000000..a3c61a413639 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.communal.shared.model + +import com.android.compose.animation.scene.TransitionKey + +/** + * Defines all known named transitions for [CommunalScenes]. + * + * These transitions can be referenced by key when changing scenes programmatically. + */ +object CommunalTransitionKeys { +    /** Fades the glanceable hub without any translation */ +    val SimpleFade = TransitionKey("SimpleFade") +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt index 96e4b341cb6d..bdf4e721a551 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt @@ -16,7 +16,11 @@  package com.android.systemui.communal.ui.viewmodel +import com.android.systemui.communal.domain.interactor.CommunalInteractor  import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState  import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel @@ -25,6 +29,7 @@ import javax.inject.Inject  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter  import kotlinx.coroutines.flow.merge  /** View model for transitions related to the communal hub. */ @@ -37,6 +42,8 @@ constructor(      lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel,      dreamToGlanceableHubTransitionViewModel: DreamingToGlanceableHubTransitionViewModel,      glanceableHubToDreamTransitionViewModel: GlanceableHubToDreamingTransitionViewModel, +    communalInteractor: CommunalInteractor, +    keyguardTransitionInteractor: KeyguardTransitionInteractor,  ) {      /**       * Whether UMO location should be on communal. This flow is responsive to transitions so that a @@ -51,4 +58,14 @@ constructor(                  glanceableHubToDreamTransitionViewModel.showUmo,              )              .distinctUntilChanged() + +    /** Whether to show communal by default */ +    val showByDefault: Flow<Boolean> = communalInteractor.showByDefault + +    val transitionFromOccludedEnded = +        keyguardTransitionInteractor.transitionStepsFromState(KeyguardState.OCCLUDED).filter { step +            -> +            step.transitionState == TransitionState.FINISHED || +                step.transitionState == TransitionState.CANCELED +        }  } diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt index 0e04d15d8680..e418641231ed 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/data/repository/DeviceEntryFaceAuthRepository.kt @@ -50,6 +50,7 @@ import com.android.systemui.keyguard.data.repository.TrustRepository  import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor  import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.StatusBarState  import com.android.systemui.keyguard.shared.model.SysUiFaceAuthenticateOptions  import com.android.systemui.keyguard.shared.model.TransitionState  import com.android.systemui.log.FaceAuthenticationLogger @@ -294,7 +295,8 @@ constructor(      }      private fun listenForSchedulingWatchdog() { -        keyguardTransitionInteractor.anyStateToGoneTransition +        keyguardTransitionInteractor +            .transition(to = KeyguardState.GONE)              .filter { it.transitionState == TransitionState.FINISHED }              .onEach {                  // We deliberately want to run this in background because scheduleWatchdog does @@ -312,7 +314,17 @@ constructor(          // or device starts going to sleep.          merge(                  powerInteractor.isAsleep, -                keyguardTransitionInteractor.isInTransitionToState(KeyguardState.GONE), +                combine( +                    keyguardTransitionInteractor.isFinishedInState(KeyguardState.GONE), +                    keyguardInteractor.statusBarState, +                ) { isFinishedInGoneState, statusBarState -> +                    // When the user is dragging the primary bouncer in (up) by manually scrolling +                    // up on the lockscreen, the device won't be irreversibly transitioned to GONE +                    // until the statusBarState updates to SHADE, so we check that here. +                    // Else, we could reset the face auth state too early and end up in a strange +                    // state. +                    isFinishedInGoneState && statusBarState == StatusBarState.SHADE +                },                  userRepository.selectedUser.map {                      it.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS                  }, diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt index a7266503b7a1..03819ed9e2fe 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt @@ -37,6 +37,10 @@ import com.android.systemui.deviceentry.shared.model.ErrorFaceAuthenticationStat  import com.android.systemui.deviceentry.shared.model.FaceAuthenticationStatus  import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState.AOD +import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING +import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN +import com.android.systemui.keyguard.shared.model.KeyguardState.OFF  import com.android.systemui.keyguard.shared.model.TransitionState  import com.android.systemui.log.FaceAuthenticationLogger  import com.android.systemui.power.domain.interactor.PowerInteractor @@ -121,9 +125,9 @@ constructor(              .launchIn(applicationScope)          merge( -                keyguardTransitionInteractor.aodToLockscreenTransition, -                keyguardTransitionInteractor.offToLockscreenTransition, -                keyguardTransitionInteractor.dozingToLockscreenTransition +                keyguardTransitionInteractor.transition(AOD, LOCKSCREEN), +                keyguardTransitionInteractor.transition(OFF, LOCKSCREEN), +                keyguardTransitionInteractor.transition(DOZING, LOCKSCREEN),              )              .filter { it.transitionState == TransitionState.STARTED }              .sample(powerInteractor.detailedWakefulness) diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt index 1230156953ee..4ac0c5683d06 100644 --- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt @@ -42,6 +42,7 @@ import kotlinx.coroutines.flow.SharingStarted  import kotlinx.coroutines.flow.StateFlow  import kotlinx.coroutines.flow.combine  import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter  import kotlinx.coroutines.flow.filterIsInstance  import kotlinx.coroutines.flow.flowOn  import kotlinx.coroutines.flow.map @@ -67,6 +68,9 @@ interface DisplayRepository {       */      val pendingDisplay: Flow<PendingDisplay?> +    /** Whether the default display is currently off. */ +    val defaultDisplayOff: Flow<Boolean> +      /** Represents a connected display that has not been enabled yet. */      interface PendingDisplay {          /** Id of the pending display. */ @@ -290,6 +294,11 @@ constructor(              }              .debugLog("pendingDisplay") +    override val defaultDisplayOff: Flow<Boolean> = +        displays +            .map { displays -> displays.firstOrNull { it.displayId == Display.DEFAULT_DISPLAY } } +            .map { it?.state == Display.STATE_OFF } +      private fun <T> Flow<T>.debugLog(flowName: String): Flow<T> {          return if (DEBUG) {              traceEach(flowName, logcat = true, traceEmissionCount = true) diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index 1a855d735a02..95012a2643a5 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -54,8 +54,6 @@ public class DozeUi implements DozeMachine.Part {      private final DozeParameters mDozeParameters;      private final DozeLog mDozeLog;      private final DelayableExecutor mBgExecutor; - -    private Runnable mCancelRunnable = null;      private long mLastTimeTickElapsed = 0;      // If time tick is scheduled and there's not a pending runnable to cancel:      private volatile boolean mTimeTickScheduled; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/HideComplicationTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/HideComplicationTouchHandler.java index ee48ee5f50fd..d525ce36a061 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/HideComplicationTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/HideComplicationTouchHandler.java @@ -16,6 +16,7 @@  package com.android.systemui.dreams.complication; +import static com.android.systemui.Flags.removeDreamOverlayHideOnTouch;  import static com.android.systemui.dreams.complication.dagger.ComplicationModule.COMPLICATIONS_FADE_OUT_DELAY;  import static com.android.systemui.dreams.complication.dagger.ComplicationModule.COMPLICATIONS_RESTORE_TIMEOUT; @@ -120,7 +121,7 @@ public class HideComplicationTouchHandler implements DreamTouchHandler {          final boolean bouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();          // If other sessions are interested in this touch, do not fade out elements. -        if (session.getActiveSessionCount() > 1 || bouncerShowing +        if (removeDreamOverlayHideOnTouch() || session.getActiveSessionCount() > 1 || bouncerShowing                  || mOverlayStateController.areExitAnimationsRunning()) {              if (DEBUG) {                  Log.d(TAG, "not fading. Active session count: " + session.getActiveSessionCount() diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java index 75c50fd5f586..66d413ab56b8 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java @@ -37,6 +37,7 @@ import androidx.annotation.VisibleForTesting;  import com.android.internal.logging.UiEvent;  import com.android.internal.logging.UiEventLogger;  import com.android.internal.widget.LockPatternUtils; +import com.android.systemui.Flags;  import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;  import com.android.systemui.dreams.touch.scrim.ScrimController;  import com.android.systemui.dreams.touch.scrim.ScrimManager; @@ -124,13 +125,19 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler {                  public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,                          float distanceY) {                      if (mCapture == null) { -                        // If the user scrolling favors a vertical direction, begin capturing -                        // scrolls. -                        mCapture = Math.abs(distanceY) > Math.abs(distanceX);                          mBouncerInitiallyShowing = mCentralSurfaces                                  .map(CentralSurfaces::isBouncerShowing)                                  .orElse(false); +                        if (Flags.dreamOverlayBouncerSwipeDirectionFiltering()) { +                            mCapture = Math.abs(distanceY) > Math.abs(distanceX) +                                    && ((distanceY < 0 && mBouncerInitiallyShowing) +                                    || (distanceY > 0 && !mBouncerInitiallyShowing)); +                        } else { +                            // If the user scrolling favors a vertical direction, begin capturing +                            // scrolls. +                            mCapture = Math.abs(distanceY) > Math.abs(distanceX); +                        }                          if (mCapture) {                              // reset expanding                              mExpanded = false; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java index e1d03392044a..cddba04b5a7c 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java @@ -16,7 +16,6 @@  package com.android.systemui.dreams.touch; -import static com.android.systemui.dreams.touch.dagger.DreamTouchModule.INPUT_SESSION_NAME;  import static com.android.systemui.dreams.touch.dagger.DreamTouchModule.PILFER_ON_GESTURE_CONSUME;  import android.os.Looper; @@ -24,7 +23,8 @@ import android.view.Choreographer;  import android.view.GestureDetector;  import android.view.MotionEvent; -import com.android.systemui.settings.DisplayTracker; +import com.android.systemui.Flags; +import com.android.systemui.dagger.qualifiers.Main;  import com.android.systemui.shared.system.InputChannelCompat;  import com.android.systemui.shared.system.InputMonitorCompat; @@ -42,26 +42,34 @@ public class InputSession {      private final InputChannelCompat.InputEventReceiver mInputEventReceiver;      private final GestureDetector mGestureDetector; +    // Pilfering is a destructive operation. Once pilfering starts, the all events will be captured +    // by the associated monitor. We track whether we're pilfering since initiating pilfering +    // requires reaching out to the InputManagerService, which can be a heavy operation. This is +    // especially costly if this is happening on a continuous stream of motion events. +    private boolean mPilfering; +      /**       * Default session constructor. -     * @param sessionName The session name that will be applied to the underlying -     * {@link InputMonitorCompat}. +     * @param inputMonitor Input monitor to track input events. +     * @param gestureDetector Gesture detector for detecting gestures.       * @param inputEventListener A listener to receive input events. -     * @param gestureListener A listener to receive gesture events. +     * @param choreographer Choreographer to use with the input receiver. +     * @param looper Looper to use with the input receiver       * @param pilferOnGestureConsume Whether touch events should be pilfered after a gesture has       *                               been consumed.       */      @Inject -    public InputSession(@Named(INPUT_SESSION_NAME) String sessionName, +    public InputSession( +            InputMonitorCompat inputMonitor, +            GestureDetector gestureDetector,              InputChannelCompat.InputEventListener inputEventListener, -            GestureDetector.OnGestureListener gestureListener, -            DisplayTracker displayTracker, +            Choreographer choreographer, +            @Main Looper looper,              @Named(PILFER_ON_GESTURE_CONSUME) boolean pilferOnGestureConsume) { -        mInputMonitor = new InputMonitorCompat(sessionName, displayTracker.getDefaultDisplayId()); -        mGestureDetector = new GestureDetector(gestureListener); +        mInputMonitor = inputMonitor; +        mGestureDetector = gestureDetector; -        mInputEventReceiver = mInputMonitor.getInputReceiver(Looper.getMainLooper(), -                Choreographer.getInstance(), +        mInputEventReceiver = mInputMonitor.getInputReceiver(looper, choreographer,                  ev -> {                      // Process event. Since sometimes input may be a prerequisite for some                      // gesture logic, process input first. @@ -69,7 +77,9 @@ public class InputSession {                      if (ev instanceof MotionEvent                              && mGestureDetector.onTouchEvent((MotionEvent) ev) -                            && pilferOnGestureConsume) { +                            && pilferOnGestureConsume +                            && !(mPilfering && Flags.dreamInputSessionPilferOnce())) { +                        mPilfering = true;                          mInputMonitor.pilferPointers();                      }                  }); diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionComponent.java index ad59a2e2b5c3..0b145211cd45 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionComponent.java @@ -24,16 +24,18 @@ import android.view.GestureDetector;  import com.android.systemui.dreams.touch.InputSession;  import com.android.systemui.shared.system.InputChannelCompat; -import javax.inject.Named; -  import dagger.BindsInstance;  import dagger.Subcomponent; +import javax.inject.Named; +  /**   * {@link InputSessionComponent} generates {@link InputSession} with specific instances bound for   * the session name and whether touches should be pilfered when consumed.   */ -@Subcomponent +@Subcomponent( +        modules = { InputSessionModule.class } +)  public interface InputSessionComponent {      /**       * Generates {@link InputSessionComponent}. diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionModule.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionModule.java new file mode 100644 index 000000000000..dfab666d5f59 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionModule.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dreams.touch.dagger; + +import static com.android.systemui.dreams.touch.dagger.DreamTouchModule.INPUT_SESSION_NAME; + +import android.view.GestureDetector; + +import com.android.systemui.settings.DisplayTracker; +import com.android.systemui.shared.system.InputMonitorCompat; + +import dagger.Module; +import dagger.Provides; + +import javax.inject.Named; + + +/** + * Module for providing dependencies to {@link com.android.systemui.dreams.touch.InputSession}. + */ +@Module +public interface InputSessionModule { +    /** */ +    @Provides +    static InputMonitorCompat providesInputMonitorCompat(@Named(INPUT_SESSION_NAME) String name, +            DisplayTracker displayTracker) { +        return new InputMonitorCompat(name, displayTracker.getDefaultDisplayId()); +    } + +    /** */ +    @Provides +    static GestureDetector providesGestureDetector( +            android.view.GestureDetector.OnGestureListener gestureListener) { +        return new GestureDetector(gestureListener); +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt index 037c23b579c3..2d9c14e222e9 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamViewModel.kt @@ -21,13 +21,16 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor  import com.android.systemui.communal.domain.interactor.CommunalInteractor  import com.android.systemui.communal.shared.model.CommunalScenes  import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dump.DumpManager  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING  import com.android.systemui.keyguard.shared.model.TransitionState  import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel  import com.android.systemui.res.R  import com.android.systemui.settings.UserTracker +import com.android.systemui.util.kotlin.FlowDumperImpl  import javax.inject.Inject  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.Flow @@ -49,7 +52,8 @@ constructor(      private val communalInteractor: CommunalInteractor,      private val keyguardUpdateMonitor: KeyguardUpdateMonitor,      private val userTracker: UserTracker, -) { +    dumpManager: DumpManager, +) : FlowDumperImpl(dumpManager) {      fun startTransitionFromDream() {          val showGlanceableHub = @@ -83,6 +87,7 @@ constructor(                  toGlanceableHubTransitionViewModel.dreamAlpha,              )              .distinctUntilChanged() +            .dumpWhileCollecting("dreamAlpha")      val dreamOverlayAlpha: Flow<Float> =          merge( @@ -93,7 +98,7 @@ constructor(              .distinctUntilChanged()      val transitionEnded = -        keyguardTransitionInteractor.fromDreamingTransition.filter { step -> +        keyguardTransitionInteractor.transition(from = DREAMING).filter { step ->              step.transitionState == TransitionState.FINISHED ||                  step.transitionState == TransitionState.CANCELED          } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 640534cc9d34..db6b8fea9235 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -153,11 +153,6 @@ object Flags {      // TODO(b/267722622): Tracking Bug      @JvmField val WALLPAPER_PICKER_UI_FOR_AIWP = releasedFlag("wallpaper_picker_ui_for_aiwp") -    /** Whether to use a new data source for intents to run on keyguard dismissal. */ -    // TODO(b/275069969): Tracking bug. -    @JvmField -    val REFACTOR_KEYGUARD_DISMISS_INTENT = unreleasedFlag("refactor_keyguard_dismiss_intent") -      /** Whether to allow long-press on the lock screen to directly open wallpaper picker. */      // TODO(b/277220285): Tracking bug.      @JvmField @@ -342,11 +337,6 @@ object Flags {              namespace = DeviceConfig.NAMESPACE_WINDOW_MANAGER,          ) -    @Keep -    @JvmField -    val WM_CAPTION_ON_SHELL = -        sysPropBooleanFlag("persist.wm.debug.caption_on_shell", default = true) -      // TODO(b/256873975): Tracking Bug      @JvmField      @Keep diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt index f1620d96b159..4327d18da97e 100644 --- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt +++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffect.kt @@ -27,40 +27,65 @@ import androidx.annotation.VisibleForTesting  import androidx.core.animation.doOnCancel  import androidx.core.animation.doOnEnd  import androidx.core.animation.doOnStart +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor  import com.android.systemui.statusbar.VibratorHelper -import kotlinx.coroutines.CancellationException +import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn  /**   * A class that handles the long press visuo-haptic effect for a QS tile.   *   * The class is also a [View.OnTouchListener] to handle the touch events, clicks and long-press - * gestures of the tile. The class also provides a [State] that can be used to determine the current + * gestures of the tile. The class also provides a [State] tha can be used to determine the current   * state of the long press effect.   *   * @property[vibratorHelper] The [VibratorHelper] to deliver haptic effects.   * @property[effectDuration] The duration of the effect in ms.   */ -class QSLongPressEffect( +// TODO(b/332902869): In addition from being injectable, we can consider making it a singleton +class QSLongPressEffect +@Inject +constructor(      private val vibratorHelper: VibratorHelper?, -    private val effectDuration: Int, +    val keyguardInteractor: KeyguardInteractor, +    @Background bgScope: CoroutineScope,  ) : View.OnTouchListener { +    private var effectDuration = 0 +      /** Current state */ -    var state = State.IDLE -        @VisibleForTesting set +    private var _state = MutableStateFlow(State.IDLE) +    val state = _state.stateIn(bgScope, SharingStarted.Lazily, State.IDLE)      /** Flows for view control and action */      private val _effectProgress = MutableStateFlow<Float?>(null) -    val effectProgress = _effectProgress.asStateFlow() +    val effectProgress = _effectProgress.stateIn(bgScope, SharingStarted.Lazily, null) + +    // Actions to perform +    private val _postedActionType = MutableStateFlow<ActionType?>(null) +    val actionType: StateFlow<ActionType?> = +        combine( +                _postedActionType, +                keyguardInteractor.isKeyguardDismissible, +            ) { action, isDismissible -> +                if (!isDismissible && action == ActionType.LONG_PRESS) { +                    ActionType.RESET_AND_LONG_PRESS +                } else { +                    action +                } +            } +            .stateIn(bgScope, SharingStarted.Lazily, null) -    private val _actionType = MutableStateFlow<ActionType?>(null) -    val actionType = _actionType.asStateFlow() +    // Should a tap timeout countdown begin +    val shouldWaitForTapTimeout: Flow<Boolean> = state.map { it == State.TIMEOUT_WAIT }      /** Haptic effects */      private val durations = @@ -69,41 +94,33 @@ class QSLongPressEffect(              VibrationEffect.Composition.PRIMITIVE_SPIN          ) -    private val longPressHint = -        LongPressHapticBuilder.createLongPressHint( -            durations?.get(0) ?: LongPressHapticBuilder.INVALID_DURATION, -            durations?.get(1) ?: LongPressHapticBuilder.INVALID_DURATION, -            effectDuration -        ) +    private var longPressHint: VibrationEffect? = null      private val snapEffect = LongPressHapticBuilder.createSnapEffect() -    /* A coroutine scope and a timer job that waits for the pressedTimeout */ -    var scope: CoroutineScope? = null -    private var waitJob: Job? = null +    private var effectAnimator: ValueAnimator? = null -    private val effectAnimator = -        ValueAnimator.ofFloat(0f, 1f).apply { -            duration = effectDuration.toLong() -            interpolator = AccelerateDecelerateInterpolator() +    val hasInitialized: Boolean +        get() = longPressHint != null && effectAnimator != null -            doOnStart { handleAnimationStart() } -            addUpdateListener { _effectProgress.value = animatedValue as Float } -            doOnEnd { handleAnimationComplete() } -            doOnCancel { handleAnimationCancel() } -        } +    @VisibleForTesting +    fun setState(state: State) { +        _state.value = state +    }      private fun reverse() { -        val pausedProgress = effectAnimator.animatedFraction -        val effect = -            LongPressHapticBuilder.createReversedEffect( -                pausedProgress, -                durations?.get(0) ?: 0, -                effectDuration, -            ) -        vibratorHelper?.cancel() -        vibrate(effect) -        effectAnimator.reverse() +        effectAnimator?.let { +            val pausedProgress = it.animatedFraction +            val effect = +                LongPressHapticBuilder.createReversedEffect( +                    pausedProgress, +                    durations?.get(0) ?: 0, +                    effectDuration, +                ) +            vibratorHelper?.cancel() +            vibrate(effect) +            it.reverse() +        }      }      private fun vibrate(effect: VibrationEffect?) { @@ -129,52 +146,37 @@ class QSLongPressEffect(      }      private fun handleActionDown() { -        when (state) { +        when (_state.value) {              State.IDLE -> { -                startPressedTimeoutWait() -                state = State.TIMEOUT_WAIT +                setState(State.TIMEOUT_WAIT)              } -            State.RUNNING_BACKWARDS -> effectAnimator.cancel() +            State.RUNNING_BACKWARDS -> effectAnimator?.cancel()              else -> {}          }      } -    private fun startPressedTimeoutWait() { -        waitJob = -            scope?.launch { -                try { -                    delay(PRESSED_TIMEOUT) -                    handleTimeoutComplete() -                } catch (_: CancellationException) { -                    state = State.IDLE -                } -            } -    } -      private fun handleActionUp() { -        when (state) { +        when (_state.value) {              State.TIMEOUT_WAIT -> { -                waitJob?.cancel() -                _actionType.value = ActionType.CLICK -                state = State.IDLE +                _postedActionType.value = ActionType.CLICK +                setState(State.IDLE)              }              State.RUNNING_FORWARD -> {                  reverse() -                state = State.RUNNING_BACKWARDS +                setState(State.RUNNING_BACKWARDS)              }              else -> {}          }      }      private fun handleActionCancel() { -        when (state) { +        when (_state.value) {              State.TIMEOUT_WAIT -> { -                waitJob?.cancel() -                state = State.IDLE +                setState(State.IDLE)              }              State.RUNNING_FORWARD -> {                  reverse() -                state = State.RUNNING_BACKWARDS +                setState(State.RUNNING_BACKWARDS)              }              else -> {}          } @@ -182,54 +184,78 @@ class QSLongPressEffect(      private fun handleAnimationStart() {          vibrate(longPressHint) -        state = State.RUNNING_FORWARD +        setState(State.RUNNING_FORWARD)      }      /** This function is called both when an animator completes or gets cancelled */      private fun handleAnimationComplete() { -        if (state == State.RUNNING_FORWARD) { +        if (_state.value == State.RUNNING_FORWARD) {              vibrate(snapEffect) -            _actionType.value = ActionType.LONG_PRESS +            _postedActionType.value = ActionType.LONG_PRESS              _effectProgress.value = null          } -        if (state != State.TIMEOUT_WAIT) { +        if (_state.value != State.TIMEOUT_WAIT) {              // This will happen if the animator did not finish by being cancelled -            state = State.IDLE +            setState(State.IDLE)          }      }      private fun handleAnimationCancel() { -        _effectProgress.value = 0f -        startPressedTimeoutWait() -        state = State.TIMEOUT_WAIT +        _effectProgress.value = null +        setState(State.TIMEOUT_WAIT)      } -    private fun handleTimeoutComplete() { -        if (state == State.TIMEOUT_WAIT && !effectAnimator.isRunning) { -            effectAnimator.start() +    fun handleTimeoutComplete() { +        if (_state.value == State.TIMEOUT_WAIT && effectAnimator?.isRunning == false) { +            effectAnimator?.start()          }      }      fun clearActionType() { -        _actionType.value = null +        _postedActionType.value = null +    } + +    /** Reset the effect by going back to a default [IDLE] state */ +    fun resetEffect() { +        if (effectAnimator?.isRunning == true) { +            effectAnimator?.cancel() +        } +        longPressHint = null +        effectAnimator = null +        _effectProgress.value = null +        _postedActionType.value = null +        setState(State.IDLE)      }      /**       * Reset the effect with a new effect duration.       * -     * The effect will go back to an [IDLE] state where it can begin its logic with a new duration. -     *       * @param[duration] New duration for the long-press effect +     * @return true if the effect initialized correctly       */ -    fun resetWithDuration(duration: Int) { +    fun initializeEffect(duration: Int): Boolean {          // The effect can't reset if it is running -        if (effectAnimator.isRunning) return +        if (duration <= 0) return false + +        resetEffect() +        effectDuration = duration +        effectAnimator = +            ValueAnimator.ofFloat(0f, 1f).apply { +                this.duration = effectDuration.toLong() +                interpolator = AccelerateDecelerateInterpolator() -        effectAnimator.duration = duration.toLong() -        _effectProgress.value = 0f -        _actionType.value = null -        waitJob?.cancel() -        state = State.IDLE +                doOnStart { handleAnimationStart() } +                addUpdateListener { _effectProgress.value = animatedValue as Float } +                doOnEnd { handleAnimationComplete() } +                doOnCancel { handleAnimationCancel() } +            } +        longPressHint = +            LongPressHapticBuilder.createLongPressHint( +                durations?.get(0) ?: LongPressHapticBuilder.INVALID_DURATION, +                durations?.get(1) ?: LongPressHapticBuilder.INVALID_DURATION, +                effectDuration +            ) +        return true      }      enum class State { @@ -243,6 +269,7 @@ class QSLongPressEffect(      enum class ActionType {          CLICK,          LONG_PRESS, +        RESET_AND_LONG_PRESS,      }      companion object { diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt index f4998a7b8789..ddb9f35c74d9 100644 --- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt @@ -21,56 +21,68 @@ import androidx.lifecycle.repeatOnLifecycle  import com.android.app.tracing.coroutines.launch  import com.android.systemui.lifecycle.repeatWhenAttached  import com.android.systemui.qs.tileimpl.QSTileViewImpl +import kotlinx.coroutines.CancellationException  import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.launch -class QSLongPressEffectViewBinder { - -    private var handle: DisposableHandle? = null -    val isBound: Boolean -        get() = handle != null - +// TODO(b/332903800) +object QSLongPressEffectViewBinder {      fun bind(          tile: QSTileViewImpl, +        qsLongPressEffect: QSLongPressEffect?,          tileSpec: String?, -        effect: QSLongPressEffect?, -    ) { -        if (effect == null) return - -        handle = -            tile.repeatWhenAttached { -                repeatOnLifecycle(Lifecycle.State.CREATED) { -                    effect.scope = this -                    val tag = "${tileSpec ?: "unknownTileSpec"}#LongPressEffect" +    ): DisposableHandle? { +        if (qsLongPressEffect == null) return null -                    launch("$tag#progress") { -                        effect.effectProgress.collect { progress -> -                            progress?.let { -                                if (it == 0f) { -                                    tile.bringToFront() -                                } +        return tile.repeatWhenAttached { +            repeatOnLifecycle(Lifecycle.State.CREATED) { +                val tag = "${tileSpec ?: "unknownTileSpec"}#LongPressEffect" +                // Progress of the effect +                launch("$tag#progress") { +                    qsLongPressEffect.effectProgress.collect { progress -> +                        progress?.let { +                            if (it == 0f) { +                                tile.bringToFront() +                            } else {                                  tile.updateLongPressEffectProperties(it)                              }                          }                      } +                } -                    launch("$tag#action") { -                        effect.actionType.collect { action -> -                            action?.let { -                                when (it) { -                                    QSLongPressEffect.ActionType.CLICK -> tile.performClick() -                                    QSLongPressEffect.ActionType.LONG_PRESS -> -                                        tile.performLongClick() +                // Action to perform +                launch("$tag#action") { +                    qsLongPressEffect.actionType.collect { action -> +                        action?.let { +                            when (it) { +                                QSLongPressEffect.ActionType.CLICK -> tile.performClick() +                                QSLongPressEffect.ActionType.LONG_PRESS -> tile.performLongClick() +                                QSLongPressEffect.ActionType.RESET_AND_LONG_PRESS -> { +                                    tile.resetLongPressEffectProperties() +                                    tile.performLongClick()                                  } -                                effect.clearActionType()                              } +                            qsLongPressEffect.clearActionType()                          }                      }                  } -            } -    } -    fun dispose() { -        handle?.dispose() -        handle = null +                // Tap timeout wait +                launch("$tag#timeout") { +                    qsLongPressEffect.shouldWaitForTapTimeout +                        .filter { it } +                        .collect { +                            try { +                                delay(QSLongPressEffect.PRESSED_TIMEOUT) +                                qsLongPressEffect.handleTimeoutComplete() +                            } catch (_: CancellationException) { +                                qsLongPressEffect.resetEffect() +                            } +                        } +                } +            } +        }      }  } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index 6b53f4ed554f..a5d7e04bf4d0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -63,6 +63,7 @@ import android.view.SurfaceControl;  import android.view.WindowManagerPolicyConstants;  import android.window.IRemoteTransition;  import android.window.IRemoteTransitionFinishedCallback; +import android.window.RemoteTransitionStub;  import android.window.TransitionInfo;  import com.android.internal.annotations.GuardedBy; @@ -187,7 +188,7 @@ public class KeyguardService extends Service {      // Note: Also used for wrapping occlude by Dream animation. It works (with some redundancy).      public static IRemoteTransition wrap(final KeyguardViewMediator keyguardViewMediator,              final IRemoteAnimationRunner runner) { -        return new IRemoteTransition.Stub() { +        return new RemoteTransitionStub() {              @GuardedBy("mLeashMap")              private final ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = new ArrayMap<>(); @@ -253,11 +254,6 @@ public class KeyguardService extends Service {                  }              } -            @Override -            public void onTransitionConsumed(IBinder transition, boolean aborted) { -                // No-op. -            } -              private static void initAlphaForAnimationTargets(@NonNull SurfaceControl.Transaction t,                      @NonNull RemoteAnimationTarget[] targets) {                  for (RemoteAnimationTarget target : targets) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt index e6e6ff6dcadb..c32c226441fe 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -41,7 +41,6 @@ import com.android.keyguard.dagger.KeyguardStatusViewComponent  import com.android.systemui.CoreStartable  import com.android.systemui.common.ui.ConfigurationState  import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.deviceentry.domain.interactor.DeviceEntryHapticsInteractor  import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor  import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor @@ -73,7 +72,6 @@ import com.android.systemui.statusbar.phone.ScreenOffAnimationController  import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator  import dagger.Lazy  import javax.inject.Inject -import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.DisposableHandle  import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -110,7 +108,6 @@ constructor(      private val keyguardBlueprintViewBinder: KeyguardBlueprintViewBinder,      private val clockInteractor: KeyguardClockInteractor,      private val keyguardViewMediator: KeyguardViewMediator, -    @Main private val mainImmediateDispatcher: CoroutineDispatcher,  ) : CoreStartable {      private var rootViewHandle: DisposableHandle? = null @@ -214,7 +211,6 @@ constructor(                  vibratorHelper,                  falsingManager,                  keyguardViewMediator, -                mainImmediateDispatcher,              )      } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 654610e8cae8..2a9dad0162c5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -137,6 +137,7 @@ import com.android.systemui.animation.ActivityTransitionAnimator;  import com.android.systemui.animation.TransitionAnimator;  import com.android.systemui.broadcast.BroadcastDispatcher;  import com.android.systemui.classifier.FalsingCollector; +import com.android.systemui.communal.ui.viewmodel.CommunalTransitionViewModel;  import com.android.systemui.dagger.qualifiers.Main;  import com.android.systemui.dagger.qualifiers.UiBackground;  import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor; @@ -584,7 +585,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,      private CentralSurfaces mCentralSurfaces; -    private IRemoteAnimationFinishedCallback mUnoccludeFromDreamFinishedCallback; +    private IRemoteAnimationFinishedCallback mUnoccludeFinishedCallback;      private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =              new DeviceConfig.OnPropertiesChangedListener() { @@ -1234,10 +1235,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,                              mUnoccludeAnimator.cancel();                          } -                        if (isDream) { +                        if (isDream || mShowCommunalByDefault) {                              initAlphaForAnimationTargets(wallpapers); -                            mDreamViewModel.get().startTransitionFromDream(); -                            mUnoccludeFromDreamFinishedCallback = finishedCallback; +                            if (isDream) { +                                mDreamViewModel.get().startTransitionFromDream(); +                            } +                            mUnoccludeFinishedCallback = finishedCallback;                              return;                          } @@ -1304,7 +1307,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,      private Consumer<Float> getRemoteSurfaceAlphaApplier() {          return (Float alpha) -> { -            if (mRemoteAnimationTarget == null) return; +            if (mRemoteAnimationTarget == null) { +                Log.e(TAG, "Attempting to set alpha on null animation target"); +                return; +            }              final View localView = mKeyguardViewControllerLazy.get().getViewRootImpl().getView();              final SyncRtSurfaceTransactionApplier applier =                      new SyncRtSurfaceTransactionApplier(localView); @@ -1319,10 +1325,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,      private Consumer<TransitionStep> getFinishedCallbackConsumer() {          return (TransitionStep step) -> { -            if (mUnoccludeFromDreamFinishedCallback == null) return; +            if (mUnoccludeFinishedCallback == null) return;              try { -                mUnoccludeFromDreamFinishedCallback.onAnimationFinished(); -                mUnoccludeFromDreamFinishedCallback = null; +                mUnoccludeFinishedCallback.onAnimationFinished(); +                mUnoccludeFinishedCallback = null;              } catch (RemoteException e) {                  Log.e(TAG, "Wasn't able to callback", e);              } @@ -1365,7 +1371,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,      private final SessionTracker mSessionTracker;      private final CoroutineDispatcher mMainDispatcher;      private final Lazy<DreamViewModel> mDreamViewModel; +    private final Lazy<CommunalTransitionViewModel> mCommunalTransitionViewModel;      private RemoteAnimationTarget mRemoteAnimationTarget; +    private Boolean mShowCommunalByDefault;      private final Lazy<WindowManagerLockscreenVisibilityManager> mWmLockscreenVisibilityManager; @@ -1414,6 +1422,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,              SystemClock systemClock,              @Main CoroutineDispatcher mainDispatcher,              Lazy<DreamViewModel> dreamViewModel, +            Lazy<CommunalTransitionViewModel> communalTransitionViewModel,              SystemPropertiesHelper systemPropertiesHelper,              Lazy<WindowManagerLockscreenVisibilityManager> wmLockscreenVisibilityManager,              SelectedUserInteractor selectedUserInteractor, @@ -1485,6 +1494,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,          mSessionTracker = sessionTracker;          mDreamViewModel = dreamViewModel; +        mCommunalTransitionViewModel = communalTransitionViewModel;          mWmLockscreenVisibilityManager = wmLockscreenVisibilityManager;          mMainDispatcher = mainDispatcher; @@ -1615,11 +1625,21 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,              ViewRootImpl viewRootImpl = mKeyguardViewControllerLazy.get().getViewRootImpl();              if (viewRootImpl != null) { -                final DreamViewModel viewModel = mDreamViewModel.get(); -                collectFlow(viewRootImpl.getView(), viewModel.getDreamAlpha(), +                final DreamViewModel dreamViewModel = mDreamViewModel.get(); +                final CommunalTransitionViewModel communalViewModel = +                        mCommunalTransitionViewModel.get(); +                collectFlow(viewRootImpl.getView(), dreamViewModel.getDreamAlpha(),                          getRemoteSurfaceAlphaApplier(), mMainDispatcher); -                collectFlow(viewRootImpl.getView(), viewModel.getTransitionEnded(), +                collectFlow(viewRootImpl.getView(), dreamViewModel.getTransitionEnded(),                          getFinishedCallbackConsumer(), mMainDispatcher); +                collectFlow(viewRootImpl.getView(), communalViewModel.getShowByDefault(), +                        (showByDefault) -> +                                mShowCommunalByDefault = showByDefault, mMainDispatcher); +                collectFlow(viewRootImpl.getView(), +                        communalViewModel.getTransitionFromOccludedEnded(), +                        getFinishedCallbackConsumer(), mMainDispatcher); +            } else { +                Log.e(TAG, "Keyguard ViewRootImpl is null");              }          }          // Most services aren't available until the system reaches the ready state, so we diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt index e101b0ab64aa..a65a8827fa48 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt @@ -29,6 +29,7 @@ import com.android.systemui.flags.FeatureFlags  import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState.GONE  import com.android.systemui.keyguard.shared.model.TransitionState  import com.android.systemui.power.domain.interactor.PowerInteractor  import com.android.systemui.utils.GlobalWindowManager @@ -83,7 +84,7 @@ constructor(          applicationScope.launch(bgDispatcher) {              // We drop 1 to avoid triggering on initial collect(). -            keyguardTransitionInteractor.anyStateToGoneTransition.collect { transition -> +            keyguardTransitionInteractor.transition(to = GONE).collect { transition ->                  if (transition.transitionState == TransitionState.FINISHED) {                      onKeyguardGone()                  } 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 a243b8eec264..7879ab6e1ed2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -39,6 +39,7 @@ import com.android.systemui.animation.ActivityTransitionAnimator;  import com.android.systemui.broadcast.BroadcastDispatcher;  import com.android.systemui.classifier.FalsingCollector;  import com.android.systemui.classifier.FalsingModule; +import com.android.systemui.communal.ui.viewmodel.CommunalTransitionViewModel;  import com.android.systemui.dagger.SysUISingleton;  import com.android.systemui.dagger.qualifiers.Main;  import com.android.systemui.dagger.qualifiers.UiBackground; @@ -161,6 +162,7 @@ public interface KeyguardModule {              SystemClock systemClock,              @Main CoroutineDispatcher mainDispatcher,              Lazy<DreamViewModel> dreamViewModel, +            Lazy<CommunalTransitionViewModel> communalTransitionViewModel,              SystemPropertiesHelper systemPropertiesHelper,              Lazy<WindowManagerLockscreenVisibilityManager> wmLockscreenVisibilityManager,              SelectedUserInteractor selectedUserInteractor, @@ -208,6 +210,7 @@ public interface KeyguardModule {                  systemClock,                  mainDispatcher,                  dreamViewModel, +                communalTransitionViewModel,                  systemPropertiesHelper,                  wmLockscreenVisibilityManager,                  selectedUserInteractor, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt index 3f4d3a8544d0..6c29bce616bc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt @@ -16,6 +16,7 @@  package com.android.systemui.keyguard.data.repository +import android.content.Context  import android.os.UserHandle  import android.provider.Settings  import com.android.keyguard.ClockEventController @@ -24,9 +25,12 @@ import com.android.keyguard.KeyguardClockSwitch.LARGE  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.shared.model.SettingsClockSize  import com.android.systemui.plugins.clocks.ClockController  import com.android.systemui.plugins.clocks.ClockId +import com.android.systemui.res.R  import com.android.systemui.shared.clocks.ClockRegistry  import com.android.systemui.util.settings.SecureSettings  import com.android.systemui.util.settings.SettingsProxyExt.observerFlow @@ -47,7 +51,11 @@ import kotlinx.coroutines.flow.stateIn  import kotlinx.coroutines.withContext  interface KeyguardClockRepository { -    /** clock size determined by notificationPanelViewController, LARGE or SMALL */ +    /** +     * clock size determined by notificationPanelViewController, LARGE or SMALL +     * +     * @deprecated When scene container flag is on use clockSize from domain level. +     */      val clockSize: StateFlow<Int>      /** clock size selected in picker, DYNAMIC or SMALL */ @@ -61,6 +69,9 @@ interface KeyguardClockRepository {      val previewClock: Flow<ClockController>      val clockEventController: ClockEventController + +    val shouldForceSmallClock: Boolean +      fun setClockSize(@ClockSize size: Int)  } @@ -73,6 +84,8 @@ constructor(      override val clockEventController: ClockEventController,      @Background private val backgroundDispatcher: CoroutineDispatcher,      @Application private val applicationScope: CoroutineScope, +    @Application private val applicationContext: Context, +    private val featureFlags: FeatureFlagsClassic,  ) : KeyguardClockRepository {      /** Receive SMALL or LARGE clock should be displayed on keyguard. */ @@ -135,6 +148,12 @@ constructor(              clockRegistry.createCurrentClock()          } +    override val shouldForceSmallClock: Boolean +        get() = +            featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE) && +                // True on small landscape screens +                applicationContext.resources.getBoolean(R.bool.force_small_clock_on_lockscreen) +      private fun getClockSize(): SettingsClockSize {          return if (              secureSettings.getIntForUser( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt index 1298fa5af033..462d8373a430 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt @@ -206,7 +206,11 @@ interface KeyguardRepository {      )      val keyguardDoneAnimationsFinished: Flow<Unit> -    /** Receive whether clock should be centered on lockscreen. */ +    /** +     * Receive whether clock should be centered on lockscreen. +     * +     * @deprecated When scene container flag is on use clockShouldBeCentered from domain level. +     */      val clockShouldBeCentered: Flow<Boolean>      /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt index bef5ee507128..b8ceab3f0a38 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt @@ -30,6 +30,7 @@ import com.android.systemui.keyguard.shared.model.DozeStateModel  import com.android.systemui.keyguard.shared.model.KeyguardState  import com.android.systemui.power.domain.interactor.PowerInteractor  import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine +import com.android.systemui.util.kotlin.sample  import javax.inject.Inject  import kotlin.time.Duration.Companion.milliseconds  import kotlin.time.Duration.Companion.seconds @@ -71,6 +72,7 @@ constructor(          listenForDreamingToAodOrDozing()          listenForTransitionToCamera(scope, keyguardInteractor)          listenForDreamingToGlanceableHub() +        listenForDreamingToPrimaryBouncer()      }      private fun listenForDreamingToGlanceableHub() { @@ -84,6 +86,21 @@ constructor(          }      } +    private fun listenForDreamingToPrimaryBouncer() { +        scope.launch { +            keyguardInteractor.primaryBouncerShowing +                .sample(startedKeyguardTransitionStep, ::Pair) +                .collect { pair -> +                    val (isBouncerShowing, lastStartedTransitionStep) = pair +                    if ( +                        isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.DREAMING +                    ) { +                        startTransitionTo(KeyguardState.PRIMARY_BOUNCER) +                    } +                } +        } +    } +      fun startToLockscreenTransition() {          scope.launch {              KeyguardWmStateRefactor.isUnexpectedlyInLegacyMode() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt index b6289d44e2c3..ee589f4a235c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt @@ -87,12 +87,12 @@ constructor(              scope.launch {                  keyguardOcclusionInteractor.isShowWhenLockedActivityOnTop                      .filterRelevantKeyguardStateAnd { onTop -> !onTop } -                    .sample(communalInteractor.isIdleOnCommunal, ::Pair) -                    .collect { (_, isIdleOnCommunal) -> +                    .sample(communalInteractor.isIdleOnCommunal, communalInteractor.showByDefault) +                    .collect { (_, isIdleOnCommunal, showCommunalByDefault) ->                          // Occlusion signals come from the framework, and should interrupt any                          // existing transition                          val to = -                            if (isIdleOnCommunal) { +                            if (isIdleOnCommunal || showCommunalByDefault) {                                  KeyguardState.GLANCEABLE_HUB                              } else {                                  KeyguardState.LOCKSCREEN @@ -106,15 +106,16 @@ constructor(                      .sample(                          keyguardInteractor.isKeyguardShowing,                          communalInteractor.isIdleOnCommunal, +                        communalInteractor.showByDefault,                      ) -                    .filterRelevantKeyguardStateAnd { (isOccluded, isShowing, _) -> +                    .filterRelevantKeyguardStateAnd { (isOccluded, isShowing, _, _) ->                          !isOccluded && isShowing                      } -                    .collect { (_, _, isIdleOnCommunal) -> +                    .collect { (_, _, isIdleOnCommunal, showCommunalByDefault) ->                          // Occlusion signals come from the framework, and should interrupt any                          // existing transition                          val to = -                            if (isIdleOnCommunal) { +                            if (isIdleOnCommunal || showCommunalByDefault) {                                  KeyguardState.GLANCEABLE_HUB                              } else {                                  KeyguardState.LOCKSCREEN @@ -175,6 +176,7 @@ constructor(              duration =                  when (toState) {                      KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION +                    KeyguardState.GLANCEABLE_HUB -> TO_GLANCEABLE_HUB_DURATION                      else -> DEFAULT_DURATION                  }.inWholeMilliseconds          } @@ -184,6 +186,7 @@ constructor(          const val TAG = "FromOccludedTransitionInteractor"          private val DEFAULT_DURATION = 500.milliseconds          val TO_LOCKSCREEN_DURATION = 933.milliseconds +        val TO_GLANCEABLE_HUB_DURATION = 250.milliseconds          val TO_AOD_DURATION = DEFAULT_DURATION          val TO_DOZING_DURATION = DEFAULT_DURATION      } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt index d39bd3d5eb12..720baec54190 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt @@ -83,19 +83,12 @@ constructor(      private fun updateBlueprint() {          val useSplitShade =              splitShadeStateController.shouldUseSplitNotificationShade(context.resources) -        // TODO(b/326098079): Make ID a constant value. -        val useWeatherClockLayout = -            clockInteractor.currentClock.value?.config?.id == "DIGITAL_CLOCK_WEATHER" && -                ComposeLockscreen.isEnabled          val blueprintId =              when { -                useWeatherClockLayout && useSplitShade -> SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID -                useWeatherClockLayout -> WEATHER_CLOCK_BLUEPRINT_ID                  useSplitShade && !ComposeLockscreen.isEnabled -> SplitShadeKeyguardBlueprint.ID                  else -> DefaultKeyguardBlueprint.DEFAULT              } -          transitionToBlueprint(blueprintId)      } @@ -128,13 +121,4 @@ constructor(      fun getCurrentBlueprint(): KeyguardBlueprint {          return keyguardBlueprintRepository.blueprint.value      } - -    companion object { -        /** -         * These values live here because classes in the composable package do not exist in some -         * systems. -         */ -        const val WEATHER_CLOCK_BLUEPRINT_ID = "weather-clock" -        const val SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID = "split-shade-weather-clock" -    }  } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt index d551c9b9a4de..f7f60a5a72a4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt @@ -21,23 +21,48 @@ import android.util.Log  import com.android.keyguard.ClockEventController  import com.android.keyguard.KeyguardClockSwitch  import com.android.keyguard.KeyguardClockSwitch.ClockSize +import com.android.keyguard.KeyguardClockSwitch.LARGE +import com.android.keyguard.KeyguardClockSwitch.SMALL  import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.keyguard.data.repository.KeyguardClockRepository +import com.android.systemui.keyguard.shared.model.KeyguardState  import com.android.systemui.keyguard.shared.model.SettingsClockSize +import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor  import com.android.systemui.plugins.clocks.ClockController  import com.android.systemui.plugins.clocks.ClockId +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.shade.domain.interactor.ShadeInteractor +import com.android.systemui.shade.shared.model.ShadeMode +import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor +import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor +import com.android.systemui.util.kotlin.combine  import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted  import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn  private val TAG = KeyguardClockInteractor::class.simpleName -/** Manages and ecapsulates the clock components of the lockscreen root view. */ +/** Manages and encapsulates the clock components of the lockscreen root view. */  @SysUISingleton  class KeyguardClockInteractor  @Inject  constructor( +    mediaCarouselInteractor: MediaCarouselInteractor, +    activeNotificationsInteractor: ActiveNotificationsInteractor, +    shadeInteractor: ShadeInteractor, +    keyguardInteractor: KeyguardInteractor, +    keyguardTransitionInteractor: KeyguardTransitionInteractor, +    headsUpNotificationInteractor: HeadsUpNotificationInteractor, +    @Application private val applicationScope: CoroutineScope,      private val keyguardClockRepository: KeyguardClockRepository,  ) { +    private val isOnAod: Flow<Boolean> = +        keyguardTransitionInteractor.currentKeyguardState.map { it == KeyguardState.AOD }      val selectedClockSize: StateFlow<SettingsClockSize> = keyguardClockRepository.selectedClockSize @@ -51,7 +76,64 @@ constructor(      var clock: ClockController? by keyguardClockRepository.clockEventController::clock -    val clockSize: StateFlow<Int> = keyguardClockRepository.clockSize +    // TODO (b/333389512): Convert this into a more readable enum. +    val clockSize: StateFlow<Int> = +        if (SceneContainerFlag.isEnabled) { +            combine( +                    shadeInteractor.shadeMode, +                    activeNotificationsInteractor.areAnyNotificationsPresent, +                    mediaCarouselInteractor.hasActiveMediaOrRecommendation, +                    keyguardInteractor.isDozing, +                    isOnAod, +                ) { shadeMode, hasNotifs, hasMedia, isDozing, isOnAod -> +                    return@combine when { +                        keyguardClockRepository.shouldForceSmallClock && !isOnAod -> SMALL +                        shadeMode == ShadeMode.Single && (hasNotifs || hasMedia) -> SMALL +                        shadeMode == ShadeMode.Single -> LARGE +                        hasMedia && !isDozing -> SMALL +                        else -> LARGE +                    } +                } +                .stateIn( +                    scope = applicationScope, +                    started = SharingStarted.WhileSubscribed(), +                    initialValue = LARGE +                ) +        } else { +            SceneContainerFlag.assertInLegacyMode() +            keyguardClockRepository.clockSize +        } + +    val clockShouldBeCentered: Flow<Boolean> = +        if (SceneContainerFlag.isEnabled) { +            combine( +                shadeInteractor.shadeMode, +                activeNotificationsInteractor.areAnyNotificationsPresent, +                keyguardInteractor.isActiveDreamLockscreenHosted, +                isOnAod, +                headsUpNotificationInteractor.isHeadsUpOrAnimatingAway, +                keyguardInteractor.isDozing, +            ) { +                shadeMode, +                areAnyNotificationsPresent, +                isActiveDreamLockscreenHosted, +                isOnAod, +                isHeadsUp, +                isDozing -> +                when { +                    shadeMode != ShadeMode.Split -> true +                    !areAnyNotificationsPresent -> true +                    isActiveDreamLockscreenHosted -> true +                    // Pulsing notification appears on the right. Move clock left to avoid overlap. +                    isHeadsUp && isDozing -> false +                    else -> isOnAod +                } +            } +        } else { +            SceneContainerFlag.assertInLegacyMode() +            keyguardInteractor.clockShouldBeCentered +        } +      fun setClockSize(@ClockSize size: Int) {          keyguardClockRepository.setClockSize(size)      } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index 2182fe378d2f..c4769488646d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -210,7 +210,8 @@ constructor(                  keyguardTransitionInteractor                      .transitionValue(GONE)                      .map { it == 1f } -                    .onStart { emit(false) }, +                    .onStart { emit(false) } +                    .distinctUntilChanged(),                  repository.topClippingBounds              ) { _, isGone, topClippingBounds ->                  if (!isGone) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt index 97081d93892a..a18579d9c8e0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt @@ -20,19 +20,14 @@ package com.android.systemui.keyguard.domain.interactor  import android.util.Log  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.keyguard.data.repository.KeyguardRepository  import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.Edge  import com.android.systemui.keyguard.shared.model.KeyguardState  import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER  import com.android.systemui.keyguard.shared.model.KeyguardState.AOD  import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING -import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING -import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING_LOCKSCREEN_HOSTED -import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB -import com.android.systemui.keyguard.shared.model.KeyguardState.GONE  import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN -import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED  import com.android.systemui.keyguard.shared.model.KeyguardState.OFF  import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER  import com.android.systemui.keyguard.shared.model.TransitionInfo @@ -40,7 +35,6 @@ import com.android.systemui.keyguard.shared.model.TransitionState  import com.android.systemui.keyguard.shared.model.TransitionStep  import com.android.systemui.util.kotlin.pairwise  import javax.inject.Inject -import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.channels.BufferOverflow @@ -53,6 +47,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged  import kotlinx.coroutines.flow.filter  import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.flow.onStart  import kotlinx.coroutines.flow.shareIn  import kotlinx.coroutines.flow.stateIn  import kotlinx.coroutines.launch @@ -64,7 +59,6 @@ class KeyguardTransitionInteractor  @Inject  constructor(      @Application val scope: CoroutineScope, -    @Main private val mainDispatcher: CoroutineDispatcher,      private val keyguardRepository: KeyguardRepository,      private val repository: KeyguardTransitionRepository,      private val fromLockscreenTransitionInteractor: dagger.Lazy<FromLockscreenTransitionInteractor>, @@ -75,14 +69,13 @@ constructor(          dagger.Lazy<FromAlternateBouncerTransitionInteractor>,      private val fromDozingTransitionInteractor: dagger.Lazy<FromDozingTransitionInteractor>,  ) { -    private val TAG = this::class.simpleName - -    private val transitionValueCache = mutableMapOf<KeyguardState, MutableSharedFlow<Float>>() +    private val transitionMap = mutableMapOf<Edge, MutableSharedFlow<TransitionStep>>()      /**       * Numerous flows are derived from, or care directly about, the transition value in and out of a       * single state. This prevent the redundant filters from running.       */ +    private val transitionValueCache = mutableMapOf<KeyguardState, MutableSharedFlow<Float>>()      private fun getTransitionValueFlow(state: KeyguardState): MutableSharedFlow<Float> {          return transitionValueCache.getOrPut(state) {              MutableSharedFlow<Float>( @@ -94,6 +87,7 @@ constructor(          }      } +    @Deprecated("Not performant - Use something else in this class")      val transitions = repository.transitions      /** @@ -106,14 +100,14 @@ constructor(       * from when we were canceled.       */      val startedStepWithPrecedingStep = -        transitions +        repository.transitions              .pairwise()              .filter { it.newValue.transitionState == TransitionState.STARTED }              .shareIn(scope, SharingStarted.Eagerly)      init {          // Collect non-canceled steps and emit transition values. -        scope.launch(mainDispatcher) { +        scope.launch {              repository.transitions                  .filter { it.transitionState != TransitionState.CANCELED }                  .collect { step -> @@ -122,11 +116,22 @@ constructor(                  }          } +        scope.launch { +            repository.transitions.collect { +                // FROM->TO +                transitionMap[Edge(it.from, it.to)]?.emit(it) +                // FROM->(ANY) +                transitionMap[Edge(it.from, null)]?.emit(it) +                // (ANY)->TO +                transitionMap[Edge(null, it.to)]?.emit(it) +            } +        } +          // If a transition from state A -> B is canceled in favor of a transition from B -> C, we          // need to ensure we emit transitionValue(A) = 0f, since no further steps will be emitted          // where the from or to states are A. This would leave transitionValue(A) stuck at an          // arbitrary non-zero value. -        scope.launch(mainDispatcher) { +        scope.launch {              startedStepWithPrecedingStep.collect { (prevStep, startedStep) ->                  if (                      prevStep.transitionState == TransitionState.CANCELED && @@ -138,116 +143,42 @@ constructor(          }      } -    /** (any)->GONE transition information */ -    val anyStateToGoneTransition: Flow<TransitionStep> = -        repository.transitions.filter { step -> step.to == GONE } - -    /** (any)->AOD transition information */ -    val anyStateToAodTransition: Flow<TransitionStep> = -        repository.transitions.filter { step -> step.to == AOD } - -    /** DREAMING->(any) transition information. */ -    val fromDreamingTransition: Flow<TransitionStep> = -        repository.transitions.filter { step -> step.from == DREAMING } - -    /** LOCKSCREEN->(any) transition information. */ -    val fromLockscreenTransition: Flow<TransitionStep> = -        repository.transitions.filter { step -> step.from == LOCKSCREEN } - -    /** (any)->Lockscreen transition information */ -    val anyStateToLockscreenTransition: Flow<TransitionStep> = -        repository.transitions.filter { step -> step.to == LOCKSCREEN } - -    /** (any)->Occluded transition information */ -    val anyStateToOccludedTransition: Flow<TransitionStep> = -        repository.transitions.filter { step -> step.to == OCCLUDED } - -    /** (any)->PrimaryBouncer transition information */ -    val anyStateToPrimaryBouncerTransition: Flow<TransitionStep> = -        repository.transitions.filter { step -> step.to == PRIMARY_BOUNCER } - -    /** (any)->Dreaming transition information */ -    val anyStateToDreamingTransition: Flow<TransitionStep> = -        repository.transitions.filter { step -> step.to == DREAMING } - -    /** (any)->AlternateBouncer transition information */ -    val anyStateToAlternateBouncerTransition: Flow<TransitionStep> = -        repository.transitions.filter { step -> step.to == ALTERNATE_BOUNCER } - -    /** AOD->LOCKSCREEN transition information. */ -    val aodToLockscreenTransition: Flow<TransitionStep> = repository.transition(AOD, LOCKSCREEN) - -    /** DREAMING->LOCKSCREEN transition information. */ -    val dreamingToLockscreenTransition: Flow<TransitionStep> = -        repository.transition(DREAMING, LOCKSCREEN) - -    /** DREAMING_LOCKSCREEN_HOSTED->LOCKSCREEN transition information. */ -    val dreamingLockscreenHostedToLockscreenTransition: Flow<TransitionStep> = -        repository.transition(DREAMING_LOCKSCREEN_HOSTED, LOCKSCREEN) - -    /** GONE->AOD transition information. */ -    val goneToAodTransition: Flow<TransitionStep> = repository.transition(GONE, AOD) - -    /** GONE->DREAMING transition information. */ -    val goneToDreamingTransition: Flow<TransitionStep> = repository.transition(GONE, DREAMING) - -    /** GONE->DREAMING_LOCKSCREEN_HOSTED transition information. */ -    val goneToDreamingLockscreenHostedTransition: Flow<TransitionStep> = -        repository.transition(GONE, DREAMING_LOCKSCREEN_HOSTED) - -    /** GONE->LOCKSCREEN transition information. */ -    val goneToLockscreenTransition: Flow<TransitionStep> = repository.transition(GONE, LOCKSCREEN) - -    /** LOCKSCREEN->AOD transition information. */ -    val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD) - -    /** LOCKSCREEN->DOZING transition information. */ -    val lockscreenToDozingTransition: Flow<TransitionStep> = -        repository.transition(LOCKSCREEN, DOZING) - -    /** LOCKSCREEN->DREAMING transition information. */ -    val lockscreenToDreamingTransition: Flow<TransitionStep> = -        repository.transition(LOCKSCREEN, DREAMING) - -    /** LOCKSCREEN->DREAMING_LOCKSCREEN_HOSTED transition information. */ -    val lockscreenToDreamingLockscreenHostedTransition: Flow<TransitionStep> = -        repository.transition(LOCKSCREEN, DREAMING_LOCKSCREEN_HOSTED) - -    /** LOCKSCREEN->GLANCEABLE_HUB transition information. */ -    val lockscreenToGlanceableHubTransition: Flow<TransitionStep> = -        repository.transition(LOCKSCREEN, GLANCEABLE_HUB) - -    /** LOCKSCREEN->OCCLUDED transition information. */ -    val lockscreenToOccludedTransition: Flow<TransitionStep> = -        repository.transition(LOCKSCREEN, OCCLUDED) - -    /** GLANCEABLE_HUB->LOCKSCREEN transition information. */ -    val glanceableHubToLockscreenTransition: Flow<TransitionStep> = -        repository.transition(GLANCEABLE_HUB, LOCKSCREEN) - -    /** OCCLUDED->LOCKSCREEN transition information. */ -    val occludedToLockscreenTransition: Flow<TransitionStep> = -        repository.transition(OCCLUDED, LOCKSCREEN) - -    /** PRIMARY_BOUNCER->GONE transition information. */ -    val primaryBouncerToGoneTransition: Flow<TransitionStep> = -        repository.transition(PRIMARY_BOUNCER, GONE) - -    /** OFF->LOCKSCREEN transition information. */ -    val offToLockscreenTransition: Flow<TransitionStep> = repository.transition(OFF, LOCKSCREEN) +    /** Given an [edge], return a SharedFlow to collect only relevant [TransitionStep]. */ +    fun getOrCreateFlow(edge: Edge): MutableSharedFlow<TransitionStep> { +        return transitionMap.getOrPut(edge) { +            MutableSharedFlow<TransitionStep>( +                extraBufferCapacity = 10, +                onBufferOverflow = BufferOverflow.DROP_OLDEST +            ) +        } +    } -    /** DOZING->LOCKSCREEN transition information. */ -    val dozingToLockscreenTransition: Flow<TransitionStep> = -        repository.transition(DOZING, LOCKSCREEN) +    /** +     * Receive all [TransitionStep] matching a filter of [from]->[to]. Allow nulls in order to match +     * any transition, for instance (any)->GONE. +     */ +    fun transition(from: KeyguardState? = null, to: KeyguardState? = null): Flow<TransitionStep> { +        if (from == null && to == null) { +            throw IllegalArgumentException("from and to cannot both be null") +        } +        return getOrCreateFlow(Edge(from = from, to = to)) +    } -    /** Receive all [TransitionStep] matching a filter of [from]->[to] */ -    fun transition(from: KeyguardState, to: KeyguardState): Flow<TransitionStep> { -        return repository.transition(from, to) +    /** +     * The amount of transition into or out of the given [KeyguardState]. +     * +     * The value will be `0` (or close to `0`, due to float point arithmetic) if not in this step or +     * `1` when fully in the given state. +     */ +    fun transitionValue( +        state: KeyguardState, +    ): Flow<Float> { +        return getTransitionValueFlow(state)      }      /** -     * AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <-> -     * Lockscreen (0f). +     * AOD<->* transition information, mapped to dozeAmount range of AOD (1f) <-> +     * * (0f).       */      val dozeAmountTransition: Flow<TransitionStep> =          repository.transitions @@ -265,10 +196,6 @@ constructor(      val startedKeyguardTransitionStep: Flow<TransitionStep> =          repository.transitions.filter { step -> step.transitionState == TransitionState.STARTED } -    /** The last [TransitionStep] with a [TransitionState] of CANCELED */ -    val canceledKeyguardTransitionStep: Flow<TransitionStep> = -        repository.transitions.filter { step -> step.transitionState == TransitionState.CANCELED } -      /** The last [TransitionStep] with a [TransitionState] of FINISHED */      val finishedKeyguardTransitionStep: Flow<TransitionStep> =          repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED } @@ -364,10 +291,6 @@ constructor(       * case, the smartspace will never be set to alpha = 1f and you'll have a half-faded smartspace       * during the LS -> GONE transition.       * -     * If you need special-case handling for cancellations (such as conditional handling depending -     * on which [KeyguardState] was canceled) you can collect [canceledKeyguardTransitionStep] -     * directly. -     *       * As a helpful footnote, here's the values of [finishedKeyguardState] and       * [currentKeyguardState] during a sequence with two cancellations:       * 1. We're FINISHED in GONE. currentKeyguardState=GONE; finishedKeyguardState=GONE. @@ -390,7 +313,7 @@ constructor(                  }              }              .distinctUntilChanged() -            .shareIn(scope, SharingStarted.Eagerly, replay = 1) +            .stateIn(scope, SharingStarted.Eagerly, KeyguardState.OFF)      /**       * The [TransitionInfo] of the most recent call to @@ -420,24 +343,12 @@ constructor(      /** Whether we've currently STARTED a transition and haven't yet FINISHED it. */      val isInTransitionToAnyState = isInTransitionWhere({ true }, { true }) -    /** -     * The amount of transition into or out of the given [KeyguardState]. -     * -     * The value will be `0` (or close to `0`, due to float point arithmetic) if not in this step or -     * `1` when fully in the given state. -     */ -    fun transitionValue( -        state: KeyguardState, -    ): Flow<Float> { -        return getTransitionValueFlow(state) -    } -      fun transitionStepsFromState(fromState: KeyguardState): Flow<TransitionStep> { -        return repository.transitions.filter { step -> step.from == fromState } +        return getOrCreateFlow(Edge(from = fromState, to = null))      }      fun transitionStepsToState(toState: KeyguardState): Flow<TransitionStep> { -        return repository.transitions.filter { step -> step.to == toState } +        return getOrCreateFlow(Edge(from = null, to = toState))      }      /** @@ -464,17 +375,24 @@ constructor(      fun isInTransitionToState(          state: KeyguardState,      ): Flow<Boolean> { -        return isInTransitionToStateWhere { it == state } +        return getOrCreateFlow(Edge(from = null, to = state)) +            .mapLatest { it.transitionState.isTransitioning() } +            .onStart { emit(false) } +            .distinctUntilChanged()      }      /** -     * Whether we're in a transition to a [KeyguardState] that matches the given predicate, but -     * haven't yet completed it. +     * Whether we're in a transition to and from the given [KeyguardState]s, but haven't yet +     * completed it.       */ -    fun isInTransitionToStateWhere( -        stateMatcher: (KeyguardState) -> Boolean, +    fun isInTransition( +        from: KeyguardState, +        to: KeyguardState,      ): Flow<Boolean> { -        return isInTransitionWhere(fromStatePredicate = { true }, toStatePredicate = stateMatcher) +        return getOrCreateFlow(Edge(from = from, to = to)) +            .mapLatest { it.transitionState.isTransitioning() } +            .onStart { emit(false) } +            .distinctUntilChanged()      }      /** @@ -483,12 +401,29 @@ constructor(      fun isInTransitionFromState(          state: KeyguardState,      ): Flow<Boolean> { -        return isInTransitionFromStateWhere { it == state } +        return getOrCreateFlow(Edge(from = state, to = null)) +            .mapLatest { it.transitionState.isTransitioning() } +            .onStart { emit(false) } +            .distinctUntilChanged() +    } + +    /** +     * Whether we're in a transition to a [KeyguardState] that matches the given predicate, but +     * haven't yet completed it. +     * +     * If you only care about a single state, instead use the optimized [isInTransitionToState]. +     */ +    fun isInTransitionToStateWhere( +        stateMatcher: (KeyguardState) -> Boolean, +    ): Flow<Boolean> { +        return isInTransitionWhere(fromStatePredicate = { true }, toStatePredicate = stateMatcher)      }      /**       * Whether we're in a transition out of a [KeyguardState] that matches the given predicate, but       * haven't yet completed it. +     * +     * If you only care about a single state, instead use the optimized [isInTransitionFromState].       */      fun isInTransitionFromStateWhere(          stateMatcher: (KeyguardState) -> Boolean, @@ -499,6 +434,9 @@ constructor(      /**       * Whether we're in a transition between two [KeyguardState]s that match the given predicates,       * but haven't yet completed it. +     * +     * If you only care about a single state for both from and to, instead use the optimized +     * [isInTransition].       */      fun isInTransitionWhere(          fromStatePredicate: (KeyguardState) -> Boolean, @@ -507,6 +445,13 @@ constructor(          return isInTransitionWhere { from, to -> fromStatePredicate(from) && toStatePredicate(to) }      } +    /** +     * Whether we're in a transition between two [KeyguardState]s that match the given predicates, +     * but haven't yet completed it. +     * +     * If you only care about a single state for both from and to, instead use the optimized +     * [isInTransition]. +     */      fun isInTransitionWhere(          fromToStatePredicate: (KeyguardState, KeyguardState) -> Boolean      ): Flow<Boolean> { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/RefactorKeyguardDismissIntent.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/RefactorKeyguardDismissIntent.kt new file mode 100644 index 000000000000..a43eb710e880 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/RefactorKeyguardDismissIntent.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.keyguard.shared + +import com.android.systemui.Flags +import com.android.systemui.flags.FlagToken +import com.android.systemui.flags.RefactorFlagUtils + +/** Helper for reading or using the refactor_keyguard_dismiss_intent flag. */ +@Suppress("NOTHING_TO_INLINE") +object RefactorKeyguardDismissIntent { +    /** The aconfig flag name */ +    const val FLAG_NAME = Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT + +    /** A token used for dependency declaration */ +    val token: FlagToken +        get() = FlagToken(FLAG_NAME, isEnabled) + +    /** Is the refactor enabled */ +    @JvmStatic +    inline val isEnabled +        get() = Flags.refactorKeyguardDismissIntent() + +    /** +     * Called to ensure code is only run when the flag is enabled. This protects users from the +     * unintended behaviors caused by accidentally running new logic, while also crashing on an eng +     * build to ensure that the refactor author catches issues in testing. +     */ +    @JvmStatic +    inline fun isUnexpectedlyInLegacyMode() = +        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME) + +    /** +     * Called to ensure code is only run when the flag is disabled. This will throw an exception if +     * the flag is enabled to ensure that the refactor author catches issues in testing. +     */ +    @JvmStatic +    inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt index 38a93b50ea97..1cd188c9dc1a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt @@ -18,11 +18,21 @@ package com.android.systemui.keyguard.shared.model  /** Possible states for a running transition between [State] */  enum class TransitionState {      /* Transition has begun. */ -    STARTED, +    STARTED { +        override fun isTransitioning() = true +    },      /* Transition is actively running. */ -    RUNNING, +    RUNNING { +        override fun isTransitioning() = true +    },      /* Transition has completed successfully. */ -    FINISHED, +    FINISHED { +        override fun isTransitioning() = false +    },      /* Transition has been interrupted, and not completed successfully. */ -    CANCELED, +    CANCELED { +        override fun isTransitioning() = false +    }; + +    abstract fun isTransitioning(): Boolean  } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt index 5de1a61d61b5..735b10907c73 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt @@ -19,8 +19,6 @@ import android.view.animation.Interpolator  import com.android.app.animation.Interpolators.LINEAR  import com.android.keyguard.logging.KeyguardTransitionAnimationLogger  import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor  import com.android.systemui.keyguard.shared.model.Edge  import com.android.systemui.keyguard.shared.model.KeyguardState @@ -35,15 +33,10 @@ import kotlin.math.max  import kotlin.math.min  import kotlin.time.Duration  import kotlin.time.Duration.Companion.milliseconds -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.channels.BufferOverflow  import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow  import kotlinx.coroutines.flow.distinctUntilChanged  import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.mapNotNull -import kotlinx.coroutines.launch  /**   * Assists in creating sub-flows for a KeyguardTransition. Call [setup] once for a transition, and @@ -53,35 +46,9 @@ import kotlinx.coroutines.launch  class KeyguardTransitionAnimationFlow  @Inject  constructor( -    @Application private val scope: CoroutineScope, -    @Main private val mainDispatcher: CoroutineDispatcher,      private val transitionInteractor: KeyguardTransitionInteractor,      private val logger: KeyguardTransitionAnimationLogger,  ) { -    private val transitionMap = mutableMapOf<Edge, MutableSharedFlow<TransitionStep>>() - -    init { -        scope.launch(mainDispatcher) { -            transitionInteractor.transitions.collect { -                // FROM->TO -                transitionMap[Edge(it.from, it.to)]?.emit(it) -                // FROM->(ANY) -                transitionMap[Edge(it.from, null)]?.emit(it) -                // (ANY)->TO -                transitionMap[Edge(null, it.to)]?.emit(it) -            } -        } -    } - -    private fun getOrCreateFlow(edge: Edge): MutableSharedFlow<TransitionStep> { -        return transitionMap.getOrPut(edge) { -            MutableSharedFlow<TransitionStep>( -                extraBufferCapacity = 10, -                onBufferOverflow = BufferOverflow.DROP_OLDEST -            ) -        } -    } -      /** Invoke once per transition between FROM->TO states to get access to a shared flow. */      fun setup(          duration: Duration, @@ -185,7 +152,8 @@ constructor(                  }?.let { onStep(interpolator.getInterpolation(it)) }              } -            return getOrCreateFlow(edge) +            return transitionInteractor +                .getOrCreateFlow(edge)                  .map { step ->                      StateToValue(                              from = step.from, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt index e423fe0bd8a0..f46a207b273a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt @@ -25,7 +25,6 @@ import android.view.View  import androidx.core.view.isInvisible  import androidx.lifecycle.Lifecycle  import androidx.lifecycle.repeatOnLifecycle -import com.android.app.tracing.coroutines.launch  import com.android.systemui.common.ui.view.LongPressHandlingView  import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor  import com.android.systemui.keyguard.ui.view.DeviceEntryIconView @@ -35,15 +34,13 @@ import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel  import com.android.systemui.lifecycle.repeatWhenAttached  import com.android.systemui.plugins.FalsingManager  import com.android.systemui.statusbar.VibratorHelper -import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.launch  @ExperimentalCoroutinesApi  object DeviceEntryIconViewBinder { -    private const val TAG = "DeviceEntryIconViewBinder" -      /**       * Updates UI for:       * - device entry containing view (parent view for the below views) @@ -61,7 +58,6 @@ object DeviceEntryIconViewBinder {          bgViewModel: DeviceEntryBackgroundViewModel,          falsingManager: FalsingManager,          vibratorHelper: VibratorHelper, -        mainImmediateDispatcher: CoroutineDispatcher,      ) {          DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()          val longPressHandlingView = view.longPressHandlingView @@ -77,33 +73,31 @@ object DeviceEntryIconViewBinder {                          view,                          HapticFeedbackConstants.CONFIRM,                      ) -                    applicationScope.launch("$TAG#viewModel.onLongPress") { -                        viewModel.onLongPress() -                    } +                    applicationScope.launch { viewModel.onLongPress() }                  }              } -        view.repeatWhenAttached(mainImmediateDispatcher) { +        view.repeatWhenAttached {              // Repeat on CREATED so that the view will always observe the entire              // GONE => AOD transition (even though the view may not be visible until the middle              // of the transition.              repeatOnLifecycle(Lifecycle.State.CREATED) { -                launch("$TAG#viewModel.isVisible") { +                launch {                      viewModel.isVisible.collect { isVisible ->                          longPressHandlingView.isInvisible = !isVisible                      }                  } -                launch("$TAG#viewModel.isLongPressEnabled") { +                launch {                      viewModel.isLongPressEnabled.collect { isEnabled ->                          longPressHandlingView.setLongPressHandlingEnabled(isEnabled)                      }                  } -                launch("$TAG#viewModel.accessibilityDelegateHint") { +                launch {                      viewModel.accessibilityDelegateHint.collect { hint ->                          view.accessibilityHintType = hint                      }                  } -                launch("$TAG#viewModel.useBackgroundProtection") { +                launch {                      viewModel.useBackgroundProtection.collect { useBackgroundProtection ->                          if (useBackgroundProtection) {                              bgView.visibility = View.VISIBLE @@ -112,7 +106,7 @@ object DeviceEntryIconViewBinder {                          }                      }                  } -                launch("$TAG#viewModel.burnInOffsets") { +                launch {                      viewModel.burnInOffsets.collect { burnInOffsets ->                          view.translationX = burnInOffsets.x.toFloat()                          view.translationY = burnInOffsets.y.toFloat() @@ -120,17 +114,15 @@ object DeviceEntryIconViewBinder {                      }                  } -                launch("$TAG#viewModel.deviceEntryViewAlpha") { -                    viewModel.deviceEntryViewAlpha.collect { alpha -> view.alpha = alpha } -                } +                launch { viewModel.deviceEntryViewAlpha.collect { alpha -> view.alpha = alpha } }              }          } -        fgIconView.repeatWhenAttached(mainImmediateDispatcher) { +        fgIconView.repeatWhenAttached {              repeatOnLifecycle(Lifecycle.State.STARTED) {                  // Start with an empty state                  fgIconView.setImageState(StateSet.NOTHING, /* merge */ false) -                launch("$TAG#fgViewModel.viewModel") { +                launch {                      fgViewModel.viewModel.collect { viewModel ->                          fgIconView.setImageState(                              view.getIconState(viewModel.type, viewModel.useAodVariant), @@ -150,10 +142,8 @@ object DeviceEntryIconViewBinder {          bgView.repeatWhenAttached {              repeatOnLifecycle(Lifecycle.State.CREATED) { -                launch("$TAG#bgViewModel.alpha") { -                    bgViewModel.alpha.collect { alpha -> bgView.alpha = alpha } -                } -                launch("$TAG#bgViewModel.color") { +                launch { bgViewModel.alpha.collect { alpha -> bgView.alpha = alpha } } +                launch {                      bgViewModel.color.collect { color ->                          bgView.imageTintList = ColorStateList.valueOf(color)                      } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt index 1b06a69213b9..6255f0d44609 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt @@ -26,7 +26,6 @@ import androidx.constraintlayout.widget.ConstraintLayout  import androidx.constraintlayout.widget.ConstraintSet  import androidx.lifecycle.Lifecycle  import androidx.lifecycle.repeatOnLifecycle -import com.android.app.tracing.coroutines.launch  import com.android.keyguard.KeyguardClockSwitch.LARGE  import com.android.keyguard.KeyguardClockSwitch.SMALL  import com.android.systemui.keyguard.MigrateClocksToBlueprint @@ -38,10 +37,10 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel  import com.android.systemui.lifecycle.repeatWhenAttached  import com.android.systemui.plugins.clocks.ClockController  import com.android.systemui.shared.clocks.DEFAULT_CLOCK_ID -import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.launch  object KeyguardClockViewBinder { -    private const val TAG = "KeyguardClockViewBinder" +    private val TAG = KeyguardClockViewBinder::class.simpleName!!      // When changing to new clock, we need to remove old clock views from burnInLayer      private var lastClock: ClockController? = null      @JvmStatic @@ -51,12 +50,15 @@ object KeyguardClockViewBinder {          viewModel: KeyguardClockViewModel,          keyguardClockInteractor: KeyguardClockInteractor,          blueprintInteractor: KeyguardBlueprintInteractor, -    ): DisposableHandle { -        keyguardClockInteractor.clockEventController.registerListeners(keyguardRootView) - -        return keyguardRootView.repeatWhenAttached { +    ) { +        keyguardRootView.repeatWhenAttached { +            repeatOnLifecycle(Lifecycle.State.CREATED) { +                keyguardClockInteractor.clockEventController.registerListeners(keyguardRootView) +            } +        } +        keyguardRootView.repeatWhenAttached {              repeatOnLifecycle(Lifecycle.State.CREATED) { -                launch("$TAG#viewModel.currentClock") { +                launch {                      if (!MigrateClocksToBlueprint.isEnabled) return@launch                      viewModel.currentClock.collect { currentClock ->                          cleanupClockViews(currentClock, keyguardRootView, viewModel.burnInLayer) @@ -65,14 +67,14 @@ object KeyguardClockViewBinder {                          applyConstraints(clockSection, keyguardRootView, true)                      }                  } -                launch("$TAG#viewModel.clockSize") { +                launch {                      if (!MigrateClocksToBlueprint.isEnabled) return@launch                      viewModel.clockSize.collect {                          updateBurnInLayer(keyguardRootView, viewModel)                          blueprintInteractor.refreshBlueprint(Type.ClockSize)                      }                  } -                launch("$TAG#viewModel.clockShouldBeCentered") { +                launch {                      if (!MigrateClocksToBlueprint.isEnabled) return@launch                      viewModel.clockShouldBeCentered.collect { clockShouldBeCentered ->                          viewModel.currentClock.value?.let { @@ -89,7 +91,7 @@ object KeyguardClockViewBinder {                          }                      }                  } -                launch("$TAG#viewModel.isAodIconsVisible") { +                launch {                      if (!MigrateClocksToBlueprint.isEnabled) return@launch                      viewModel.isAodIconsVisible.collect { isAodIconsVisible ->                          viewModel.currentClock.value?.let { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt index d5add61822b1..93b3ba561eb3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissActionBinder.kt @@ -19,9 +19,8 @@ import com.android.keyguard.logging.KeyguardLogger  import com.android.systemui.CoreStartable  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.flags.FeatureFlagsClassic -import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor +import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent  import com.android.systemui.log.core.LogLevel  import com.android.systemui.util.kotlin.sample  import javax.inject.Inject @@ -38,11 +37,10 @@ constructor(      private val interactor: KeyguardDismissActionInteractor,      @Application private val scope: CoroutineScope,      private val keyguardLogger: KeyguardLogger, -    private val featureFlags: FeatureFlagsClassic,  ) : CoreStartable {      override fun start() { -        if (!featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +        if (!RefactorKeyguardDismissIntent.isEnabled) {              return          } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt index 87d8164e1cb9..f77d01208dc2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardDismissBinder.kt @@ -21,8 +21,8 @@ import com.android.systemui.CoreStartable  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.flags.FeatureFlagsClassic -import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.domain.interactor.KeyguardDismissInteractor +import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent  import com.android.systemui.keyguard.shared.model.KeyguardDone  import com.android.systemui.log.core.LogLevel  import com.android.systemui.user.domain.interactor.SelectedUserInteractor @@ -44,7 +44,7 @@ constructor(  ) : CoreStartable {      override fun start() { -        if (!featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +        if (!RefactorKeyguardDismissIntent.isEnabled) {              return          } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt index 486320af45a2..3ff32bfcfd46 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt @@ -44,6 +44,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel  import com.android.systemui.lifecycle.repeatWhenAttached  import com.android.systemui.plugins.clocks.ClockController  import com.android.systemui.res.R +import com.android.systemui.shared.clocks.ClockRegistry  import com.android.systemui.util.Utils  import kotlin.reflect.KSuspendFunction1 @@ -77,37 +78,42 @@ object KeyguardPreviewClockViewBinder {          context: Context,          rootView: ConstraintLayout,          viewModel: KeyguardPreviewClockViewModel, +        clockRegistry: ClockRegistry,          updateClockAppearance: KSuspendFunction1<ClockController, Unit>,      ) {          rootView.repeatWhenAttached {              repeatOnLifecycle(Lifecycle.State.STARTED) { +                var lastClock: ClockController? = null                  launch("$TAG#viewModel.previewClock") { -                    var lastClock: ClockController? = null -                    viewModel.previewClock.collect { currentClock -> -                        lastClock?.let { clock -> -                            (clock.largeClock.layout.views + clock.smallClock.layout.views) -                                .forEach { rootView.removeView(it) } -                        } -                        lastClock = currentClock -                        updateClockAppearance(currentClock) +                        viewModel.previewClock.collect { currentClock -> +                            lastClock?.let { clock -> +                                (clock.largeClock.layout.views + clock.smallClock.layout.views) +                                    .forEach { rootView.removeView(it) } +                            } +                            lastClock = currentClock +                            updateClockAppearance(currentClock) -                        if (viewModel.shouldHighlightSelectedAffordance) { -                            (currentClock.largeClock.layout.views + -                                    currentClock.smallClock.layout.views) -                                .forEach { it.alpha = KeyguardPreviewRenderer.DIM_ALPHA } -                        } -                        currentClock.largeClock.layout.views.forEach { -                            (it.parent as? ViewGroup)?.removeView(it) -                            rootView.addView(it) -                        } +                            if (viewModel.shouldHighlightSelectedAffordance) { +                                (currentClock.largeClock.layout.views + +                                        currentClock.smallClock.layout.views) +                                    .forEach { it.alpha = KeyguardPreviewRenderer.DIM_ALPHA } +                            } +                            currentClock.largeClock.layout.views.forEach { +                                (it.parent as? ViewGroup)?.removeView(it) +                                rootView.addView(it) +                            } -                        currentClock.smallClock.layout.views.forEach { -                            (it.parent as? ViewGroup)?.removeView(it) -                            rootView.addView(it) +                            currentClock.smallClock.layout.views.forEach { +                                (it.parent as? ViewGroup)?.removeView(it) +                                rootView.addView(it) +                            } +                            applyPreviewConstraints(context, rootView, currentClock, viewModel)                          } -                        applyPreviewConstraints(context, rootView, currentClock, viewModel)                      } -                } +                    .invokeOnCompletion { +                        // recover seed color especially for Transit clock +                        lastClock?.events?.onSeedColorChanged(clockRegistry.seedColor) +                    }              }          }      } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt index 49ae35a43c23..88d907469f69 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt @@ -32,7 +32,7 @@ object KeyguardPreviewSmartspaceViewBinder {      @JvmStatic      fun bind( -        context: Context, +        previewContext: Context,          smartspace: View,          splitShadePreview: Boolean,          viewModel: KeyguardPreviewSmartspaceViewModel, @@ -46,10 +46,12 @@ object KeyguardPreviewSmartspaceViewBinder {                                  SettingsClockSize.DYNAMIC ->                                      viewModel.getLargeClockSmartspaceTopPadding(                                          splitShadePreview, +                                        previewContext,                                      )                                  SettingsClockSize.SMALL ->                                      viewModel.getSmallClockSmartspaceTopPadding(                                          splitShadePreview, +                                        previewContext,                                      )                              }                          smartspace.setTopPadding(topPadding) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt index 6c21e6cdb3bc..abd79ab793d5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt @@ -30,7 +30,6 @@ import androidx.core.view.isVisible  import androidx.core.view.updateLayoutParams  import androidx.lifecycle.Lifecycle  import androidx.lifecycle.repeatOnLifecycle -import com.android.app.tracing.coroutines.launch  import com.android.settingslib.Utils  import com.android.systemui.animation.Expandable  import com.android.systemui.animation.view.LaunchableImageView @@ -42,11 +41,11 @@ import com.android.systemui.plugins.FalsingManager  import com.android.systemui.res.R  import com.android.systemui.statusbar.VibratorHelper  import com.android.systemui.util.doOnEnd -import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.flow.combine  import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch  /** This is only for a SINGLE Quick affordance */  object KeyguardQuickAffordanceViewBinder { @@ -54,7 +53,6 @@ object KeyguardQuickAffordanceViewBinder {      private const val EXIT_DOZE_BUTTON_REVEAL_ANIMATION_DURATION_MS = 250L      private const val SCALE_SELECTED_BUTTON = 1.23f      private const val DIM_ALPHA = 0.3f -    private const val TAG = "KeyguardQuickAffordanceViewBinder"      /**       * Defines interface for an object that acts as the binding between the view and its view-model. @@ -76,15 +74,14 @@ object KeyguardQuickAffordanceViewBinder {          alpha: Flow<Float>,          falsingManager: FalsingManager?,          vibratorHelper: VibratorHelper?, -        mainImmediateDispatcher: CoroutineDispatcher,          messageDisplayer: (Int) -> Unit,      ): Binding {          val button = view as ImageView          val configurationBasedDimensions = MutableStateFlow(loadFromResources(view))          val disposableHandle = -            view.repeatWhenAttached(mainImmediateDispatcher) { +            view.repeatWhenAttached {                  repeatOnLifecycle(Lifecycle.State.STARTED) { -                    launch("$TAG#viewModel.collect") { +                    launch {                          viewModel.collect { buttonModel ->                              updateButton(                                  view = button, @@ -96,7 +93,7 @@ object KeyguardQuickAffordanceViewBinder {                          }                      } -                    launch("$TAG#updateButtonAlpha") { +                    launch {                          updateButtonAlpha(                              view = button,                              viewModel = viewModel, @@ -104,7 +101,7 @@ object KeyguardQuickAffordanceViewBinder {                          )                      } -                    launch("$TAG#configurationBasedDimensions") { +                    launch {                          configurationBasedDimensions.collect { dimensions ->                              button.updateLayoutParams<ViewGroup.LayoutParams> {                                  width = dimensions.buttonSizePx.width diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt index 44fd58267250..5ee35e4f8eb6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt @@ -33,7 +33,6 @@ import android.view.WindowInsets  import androidx.lifecycle.Lifecycle  import androidx.lifecycle.repeatOnLifecycle  import com.android.app.animation.Interpolators -import com.android.app.tracing.coroutines.launch  import com.android.internal.jank.InteractionJankMonitor  import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD  import com.android.systemui.Flags.newAodTransition @@ -73,7 +72,6 @@ import com.android.systemui.util.ui.isAnimating  import com.android.systemui.util.ui.stopAnimating  import com.android.systemui.util.ui.value  import kotlin.math.min -import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.DisposableHandle  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.coroutineScope @@ -81,6 +79,7 @@ import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.flow.stateIn  import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch  /** Bind occludingAppDeviceEntryMessageViewModel to run whenever the keyguard view is attached. */  @OptIn(ExperimentalCoroutinesApi::class) @@ -101,7 +100,6 @@ object KeyguardRootViewBinder {          vibratorHelper: VibratorHelper?,          falsingManager: FalsingManager?,          keyguardViewMediator: KeyguardViewMediator?, -        mainImmediateDispatcher: CoroutineDispatcher,      ): DisposableHandle {          val disposables = DisposableHandles()          val childViews = mutableMapOf<Int, View>() @@ -125,9 +123,9 @@ object KeyguardRootViewBinder {              )          disposables += -            view.repeatWhenAttached(mainImmediateDispatcher) { +            view.repeatWhenAttached {                  repeatOnLifecycle(Lifecycle.State.CREATED) { -                    launch("$TAG#occludingAppDeviceEntryMessageViewModel.message") { +                    launch {                          occludingAppDeviceEntryMessageViewModel.message.collect { biometricMessage                              ->                              if (biometricMessage?.message != null) { @@ -146,7 +144,7 @@ object KeyguardRootViewBinder {                      if (                          KeyguardBottomAreaRefactor.isEnabled || DeviceEntryUdfpsRefactor.isEnabled                      ) { -                        launch("$TAG#viewModel.alpha") { +                        launch {                              viewModel.alpha(viewState).collect { alpha ->                                  view.alpha = alpha                                  if (KeyguardBottomAreaRefactor.isEnabled) { @@ -158,21 +156,21 @@ object KeyguardRootViewBinder {                      }                      if (MigrateClocksToBlueprint.isEnabled) { -                        launch("$TAG#viewModel.burnInLayerVisibility") { +                        launch {                              viewModel.burnInLayerVisibility.collect { visibility ->                                  childViews[burnInLayerId]?.visibility = visibility                                  childViews[aodNotificationIconContainerId]?.visibility = visibility                              }                          } -                        launch("$TAG#viewModel.burnInLayerAlpha") { +                        launch {                              viewModel.burnInLayerAlpha.collect { alpha ->                                  childViews[statusViewId]?.alpha = alpha                                  childViews[aodNotificationIconContainerId]?.alpha = alpha                              }                          } -                        launch("$TAG#viewModel.topClippingBounds") { +                        launch {                              val clipBounds = Rect()                              viewModel.topClippingBounds.collect { clipTop ->                                  if (clipTop == null) { @@ -189,13 +187,13 @@ object KeyguardRootViewBinder {                              }                          } -                        launch("$TAG#viewModel.lockscreenStateAlpha") { +                        launch {                              viewModel.lockscreenStateAlpha(viewState).collect { alpha ->                                  childViews[statusViewId]?.alpha = alpha                              }                          } -                        launch("$TAG#viewModel.translationY") { +                        launch {                              // When translation happens in burnInLayer, it won't be weather clock                              // large clock isn't added to burnInLayer due to its scale transition                              // so we also need to add translation to it here @@ -207,7 +205,7 @@ object KeyguardRootViewBinder {                              }                          } -                        launch("$TAG#viewModel.translationX") { +                        launch {                              viewModel.translationX.collect { state ->                                  val px = state.value ?: return@collect                                  when { @@ -234,7 +232,7 @@ object KeyguardRootViewBinder {                              }                          } -                        launch("$TAG#viewModel.scale") { +                        launch {                              viewModel.scale.collect { scaleViewModel ->                                  if (scaleViewModel.scaleClockOnly) {                                      // For clocks except weather clock, we have scale transition @@ -265,7 +263,7 @@ object KeyguardRootViewBinder {                          }                          if (NotificationIconContainerRefactor.isEnabled) { -                            launch("$TAG#viewModel.isNotifIconContainerVisible") { +                            launch {                                  val iconsAppearTranslationPx =                                      configuration                                          .getDimensionPixelSize(R.dimen.shelf_appear_translation) @@ -282,7 +280,7 @@ object KeyguardRootViewBinder {                          }                          interactionJankMonitor?.let { jankMonitor -> -                            launch("$TAG#viewModel.goneToAodTransition") { +                            launch {                                  viewModel.goneToAodTransition.collect {                                      when (it.transitionState) {                                          TransitionState.STARTED -> { @@ -308,7 +306,7 @@ object KeyguardRootViewBinder {                          }                      } -                    launch("$TAG#shadeInteractor.isAnyFullyExpanded") { +                    launch {                          shadeInteractor.isAnyFullyExpanded.collect { isFullyAnyExpanded ->                              view.visibility =                                  if (isFullyAnyExpanded) { @@ -319,12 +317,10 @@ object KeyguardRootViewBinder {                          }                      } -                    launch("$TAG#burnInParams.collect") { -                        burnInParams.collect { viewModel.updateBurnInParams(it) } -                    } +                    launch { burnInParams.collect { viewModel.updateBurnInParams(it) } }                      if (deviceEntryHapticsInteractor != null && vibratorHelper != null) { -                        launch("$TAG#deviceEntryHapticsInteractor.playSuccessHaptic") { +                        launch {                              deviceEntryHapticsInteractor.playSuccessHaptic.collect {                                  vibratorHelper.performHapticFeedback(                                      view, @@ -334,7 +330,7 @@ object KeyguardRootViewBinder {                              }                          } -                        launch("$TAG#deviceEntryHapticsInteractor.playErrorHaptic") { +                        launch {                              deviceEntryHapticsInteractor.playErrorHaptic.collect {                                  vibratorHelper.performHapticFeedback(                                      view, @@ -589,5 +585,4 @@ object KeyguardRootViewBinder {      private const val ID = "occluding_app_device_entry_unlock_msg"      private const val AOD_ICONS_APPEAR_DURATION: Long = 200 -    private const val TAG = "KeyguardRootViewBinder"  } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt index ce1aed08ab49..bda5be4f6533 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt @@ -327,9 +327,12 @@ constructor(          smartSpaceView = lockscreenSmartspaceController.buildAndConnectDateView(parentView)          val topPadding: Int = -            smartspaceViewModel.getLargeClockSmartspaceTopPadding(previewInSplitShade()) -        val startPadding: Int = smartspaceViewModel.getSmartspaceStartPadding() -        val endPadding: Int = smartspaceViewModel.getSmartspaceEndPadding() +            smartspaceViewModel.getLargeClockSmartspaceTopPadding( +                previewInSplitShade(), +                previewContext, +            ) +        val startPadding: Int = smartspaceViewModel.getSmartspaceStartPadding(previewContext) +        val endPadding: Int = smartspaceViewModel.getSmartspaceEndPadding(previewContext)          smartSpaceView?.let {              it.setPaddingRelative(startPadding, topPadding, endPadding, 0) @@ -387,7 +390,6 @@ constructor(                      null, // device entry haptics not required for preview mode                      null, // falsing manager not required for preview mode                      null, // keyguard view mediator is not required for preview mode -                    mainDispatcher,                  )          }          rootView.addView( @@ -411,10 +413,11 @@ constructor(              setUpClock(previewContext, rootView)              if (MigrateClocksToBlueprint.isEnabled) {                  KeyguardPreviewClockViewBinder.bind( -                    context, +                    previewContext,                      keyguardRootView,                      clockViewModel, -                    ::updateClockAppearance +                    clockRegistry, +                    ::updateClockAppearance,                  )              } else {                  KeyguardPreviewClockViewBinder.bind( @@ -429,7 +432,7 @@ constructor(          smartSpaceView?.let {              KeyguardPreviewSmartspaceViewBinder.bind( -                context, +                previewContext,                  it,                  previewInSplitShade(),                  smartspaceViewModel @@ -454,7 +457,6 @@ constructor(                      alpha = flowOf(1f),                      falsingManager = falsingManager,                      vibratorHelper = vibratorHelper, -                    mainImmediateDispatcher = mainDispatcher,                  ) { message ->                      indicationController.showTransientIndication(message)                  } @@ -469,7 +471,6 @@ constructor(                      alpha = flowOf(1f),                      falsingManager = falsingManager,                      vibratorHelper = vibratorHelper, -                    mainImmediateDispatcher = mainDispatcher,                  ) { message ->                      indicationController.showTransientIndication(message)                  } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt index b4e57cc93962..04ac7bf1178e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt @@ -17,13 +17,9 @@  package com.android.systemui.keyguard.ui.view.layout.blueprints -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID  import com.android.systemui.keyguard.shared.model.KeyguardBlueprint -import com.android.systemui.keyguard.shared.model.KeyguardSection  import dagger.Binds  import dagger.Module -import dagger.Provides  import dagger.multibindings.IntoSet  @Module @@ -45,26 +41,4 @@ abstract class KeyguardBlueprintModule {      abstract fun bindShortcutsBesideUdfpsLockscreenBlueprint(          shortcutsBesideUdfpsLockscreenBlueprint: ShortcutsBesideUdfpsKeyguardBlueprint      ): KeyguardBlueprint - -    companion object { -        /** This is a place holder for weather clock in compose. */ -        @Provides -        @IntoSet -        fun bindWeatherClockBlueprintPlaceHolder(): KeyguardBlueprint { -            return object : KeyguardBlueprint { -                override val id: String = WEATHER_CLOCK_BLUEPRINT_ID -                override val sections: List<KeyguardSection> = listOf() -            } -        } - -        /** This is a place holder for weather clock in compose. */ -        @Provides -        @IntoSet -        fun bindSplitShadeWeatherClockBlueprintPlaceHolder(): KeyguardBlueprint { -            return object : KeyguardBlueprint { -                override val id: String = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID -                override val sections: List<KeyguardSection> = listOf() -            } -        } -    }  } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt index 5404729d1819..2e9663897f89 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt @@ -36,7 +36,6 @@ import com.android.systemui.res.R  import com.android.systemui.statusbar.KeyguardIndicationController  import com.android.systemui.statusbar.VibratorHelper  import javax.inject.Inject -import kotlinx.coroutines.CoroutineDispatcher  class AlignShortcutsToUdfpsSection  @Inject @@ -48,7 +47,6 @@ constructor(      private val falsingManager: FalsingManager,      private val indicationController: KeyguardIndicationController,      private val vibratorHelper: VibratorHelper, -    @Main private val mainImmediateDispatcher: CoroutineDispatcher,  ) : BaseShortcutSection() {      override fun addViews(constraintLayout: ConstraintLayout) {          if (KeyguardBottomAreaRefactor.isEnabled) { @@ -66,7 +64,6 @@ constructor(                      keyguardQuickAffordancesCombinedViewModel.transitionAlpha,                      falsingManager,                      vibratorHelper, -                    mainImmediateDispatcher,                  ) {                      indicationController.showTransientIndication(it)                  } @@ -77,7 +74,6 @@ constructor(                      keyguardQuickAffordancesCombinedViewModel.transitionAlpha,                      falsingManager,                      vibratorHelper, -                    mainImmediateDispatcher,                  ) {                      indicationController.showTransientIndication(it)                  } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt index e0bf8152d11f..78a1fcfe4258 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt @@ -45,7 +45,6 @@ import com.android.systemui.res.R  import com.android.systemui.shared.R as sharedR  import dagger.Lazy  import javax.inject.Inject -import kotlinx.coroutines.DisposableHandle  internal fun ConstraintSet.setVisibility(      views: Iterable<View>, @@ -66,23 +65,19 @@ constructor(      val smartspaceViewModel: KeyguardSmartspaceViewModel,      val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,  ) : KeyguardSection() { -    private var handle: DisposableHandle? = null -      override fun addViews(constraintLayout: ConstraintLayout) {}      override fun bindData(constraintLayout: ConstraintLayout) {          if (!MigrateClocksToBlueprint.isEnabled) {              return          } -        handle?.dispose() -        handle = -            KeyguardClockViewBinder.bind( -                this, -                constraintLayout, -                keyguardClockViewModel, -                clockInteractor, -                blueprintInteractor.get() -            ) +        KeyguardClockViewBinder.bind( +            this, +            constraintLayout, +            keyguardClockViewModel, +            clockInteractor, +            blueprintInteractor.get() +        )      }      override fun applyConstraints(constraintSet: ConstraintSet) { @@ -94,13 +89,7 @@ constructor(          }      } -    override fun removeViews(constraintLayout: ConstraintLayout) { -        if (!MigrateClocksToBlueprint.isEnabled) { -            return -        } -        handle?.dispose() -        handle = null -    } +    override fun removeViews(constraintLayout: ConstraintLayout) {}      private fun buildConstraints(          clock: ClockController, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt index 865e989c5b68..29041d1665c3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt @@ -30,7 +30,6 @@ import com.android.keyguard.LockIconView  import com.android.keyguard.LockIconViewController  import com.android.systemui.biometrics.AuthController  import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor  import com.android.systemui.flags.FeatureFlags  import com.android.systemui.flags.Flags @@ -48,7 +47,6 @@ import com.android.systemui.shade.NotificationPanelView  import com.android.systemui.statusbar.VibratorHelper  import dagger.Lazy  import javax.inject.Inject -import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -69,7 +67,6 @@ constructor(      private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,      private val falsingManager: Lazy<FalsingManager>,      private val vibratorHelper: Lazy<VibratorHelper>, -    @Main private val mainImmediateDispatcher: CoroutineDispatcher,  ) : KeyguardSection() {      private val deviceEntryIconViewId = R.id.device_entry_icon_view @@ -107,7 +104,6 @@ constructor(                      deviceEntryBackgroundViewModel.get(),                      falsingManager.get(),                      vibratorHelper.get(), -                    mainImmediateDispatcher,                  )              }          } else { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt index 27ca5cdbad17..45b82576c6c4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt @@ -35,7 +35,6 @@ import com.android.systemui.res.R  import com.android.systemui.statusbar.KeyguardIndicationController  import com.android.systemui.statusbar.VibratorHelper  import javax.inject.Inject -import kotlinx.coroutines.CoroutineDispatcher  class DefaultShortcutsSection  @Inject @@ -47,7 +46,6 @@ constructor(      private val falsingManager: FalsingManager,      private val indicationController: KeyguardIndicationController,      private val vibratorHelper: VibratorHelper, -    @Main private val mainImmediateDispatcher: CoroutineDispatcher,  ) : BaseShortcutSection() {      override fun addViews(constraintLayout: ConstraintLayout) {          if (KeyguardBottomAreaRefactor.isEnabled) { @@ -65,7 +63,6 @@ constructor(                      keyguardQuickAffordancesCombinedViewModel.transitionAlpha,                      falsingManager,                      vibratorHelper, -                    mainImmediateDispatcher,                  ) {                      indicationController.showTransientIndication(it)                  } @@ -76,7 +73,6 @@ constructor(                      keyguardQuickAffordancesCombinedViewModel.transitionAlpha,                      falsingManager,                      vibratorHelper, -                    mainImmediateDispatcher,                  ) {                      indicationController.showTransientIndication(it)                  } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt index 4d3a78d32b3a..91f76a4df771 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt @@ -169,10 +169,7 @@ class ClockSizeTransition(                      return@OnPreDrawListener true                  } -                anim.duration = duration -                anim.startDelay = startDelay -                anim.interpolator = interpolator -                anim.addListener( +                val listener =                      object : AnimatorListenerAdapter() {                          override fun onAnimationStart(anim: Animator) {                              assignAnimValues("start", 0f, fromVis) @@ -183,8 +180,21 @@ class ClockSizeTransition(                              if (sendToBack) toView.translationZ = 0f                              toView.viewTreeObserver.removeOnPreDrawListener(predrawCallback)                          } + +                        override fun onAnimationPause(anim: Animator) { +                            toView.viewTreeObserver.removeOnPreDrawListener(predrawCallback) +                        } + +                        override fun onAnimationResume(anim: Animator) { +                            toView.viewTreeObserver.addOnPreDrawListener(predrawCallback) +                        }                      } -                ) + +                anim.duration = duration +                anim.startDelay = startDelay +                anim.interpolator = interpolator +                anim.addListener(listener) +                anim.addPauseListener(listener)                  assignAnimValues("init", 0f, fromVis)                  toView.viewTreeObserver.addOnPreDrawListener(predrawCallback) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModel.kt index 7814576eff01..5cf100e78e6e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModel.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel  import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor  import com.android.systemui.keyguard.shared.model.KeyguardState -import com.android.systemui.keyguard.shared.model.TransitionState  import javax.inject.Inject  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.Flow @@ -38,12 +37,9 @@ constructor(      private val deviceSupportsAlternateBouncer: Flow<Boolean> =          alternateBouncerInteractor.alternateBouncerSupported      private val isTransitioningToOrFromOrShowingAlternateBouncer: Flow<Boolean> = -        keyguardTransitionInteractor.transitions -            .map { -                it.to == KeyguardState.ALTERNATE_BOUNCER || -                    (it.from == KeyguardState.ALTERNATE_BOUNCER && -                        it.transitionState != TransitionState.FINISHED) -            } +        keyguardTransitionInteractor +            .transitionValue(KeyguardState.ALTERNATE_BOUNCER) +            .map { it > 0f }              .distinctUntilChanged()      val alternateBouncerWindowRequired: Flow<Boolean> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt index 4ddd57110b38..d4844e2af335 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt @@ -29,9 +29,6 @@ import com.android.systemui.keyguard.domain.interactor.BurnInInteractor  import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor  import com.android.systemui.keyguard.shared.model.BurnInModel -import com.android.systemui.keyguard.shared.model.TransitionState -import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING -import com.android.systemui.keyguard.shared.model.TransitionState.STARTED  import com.android.systemui.keyguard.ui.StateToValue  import com.android.systemui.res.R  import javax.inject.Inject @@ -97,9 +94,9 @@ constructor(                      occludedToLockscreen,                      aodToLockscreen ->                      val translationY = -                        if (isInTransition(aodToLockscreen.transitionState)) { +                        if (aodToLockscreen.transitionState.isTransitioning()) {                              aodToLockscreen.value ?: 0f -                        } else if (isInTransition(goneToAod.transitionState)) { +                        } else if (goneToAod.transitionState.isTransitioning()) {                              (goneToAod.value ?: 0f) + burnInModel.translationY                          } else {                              burnInModel.translationY + occludedToLockscreen + keyguardTranslationY @@ -110,10 +107,6 @@ constructor(              .distinctUntilChanged()      } -    private fun isInTransition(state: TransitionState): Boolean { -        return state == STARTED || state == RUNNING -    } -      private fun burnIn(          params: BurnInParameters,      ): Flow<BurnInModel> { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt index fe88b8169c89..24429fae93ac 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt @@ -18,9 +18,8 @@ package com.android.systemui.keyguard.ui.viewmodel  import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor -import com.android.systemui.flags.FeatureFlagsClassic -import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor +import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent  import com.android.systemui.keyguard.shared.model.KeyguardState  import com.android.systemui.keyguard.shared.model.KeyguardState.GONE  import com.android.systemui.keyguard.shared.model.ScrimAlpha @@ -44,13 +43,12 @@ constructor(      private val statusBarStateController: SysuiStatusBarStateController,      private val primaryBouncerInteractor: PrimaryBouncerInteractor,      private val keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>, -    private val featureFlags: FeatureFlagsClassic,      private val shadeInteractor: ShadeInteractor,      private val animationFlow: KeyguardTransitionAnimationFlow,  ) {      /** Common fade for scrim alpha values during *BOUNCER->GONE */      fun scrimAlpha(duration: Duration, fromState: KeyguardState): Flow<ScrimAlpha> { -        return if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +        return if (RefactorKeyguardDismissIntent.isEnabled) {              keyguardDismissActionInteractor                  .get()                  .willAnimateDismissActionOnLockscreen @@ -104,7 +102,7 @@ constructor(                  to = GONE,              ) -        return shadeInteractor.shadeExpansion.flatMapLatest { shadeExpansion -> +        return shadeInteractor.isAnyExpanded.flatMapLatest { isAnyExpanded ->              transitionAnimation                  .sharedFlow(                      duration = duration, @@ -112,7 +110,7 @@ constructor(                      onStart = {                          leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide()                          willRunDismissFromKeyguard = willRunAnimationOnKeyguard() -                        isShadeExpanded = shadeExpansion > 0f +                        isShadeExpanded = isAnyExpanded                      },                      onStep = { 1f - it },                  ) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt index c9251c7c5473..f6da033f1bd3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt @@ -26,7 +26,6 @@ import com.android.systemui.customization.R as customizationR  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor  import com.android.systemui.keyguard.shared.ComposeLockscreen  import com.android.systemui.keyguard.shared.model.SettingsClockSize  import com.android.systemui.res.R @@ -46,11 +45,10 @@ import kotlinx.coroutines.flow.stateIn  class KeyguardClockViewModel  @Inject  constructor( -    keyguardInteractor: KeyguardInteractor, -    private val keyguardClockInteractor: KeyguardClockInteractor, +    keyguardClockInteractor: KeyguardClockInteractor,      @Application private val applicationScope: CoroutineScope,      notifsKeyguardInteractor: NotificationsKeyguardInteractor, -    @VisibleForTesting val shadeInteractor: ShadeInteractor, +    @get:VisibleForTesting val shadeInteractor: ShadeInteractor,  ) {      var burnInLayer: Layer? = null      val useLargeClock: Boolean @@ -99,7 +97,7 @@ constructor(              )      val clockShouldBeCentered: StateFlow<Boolean> = -        keyguardInteractor.clockShouldBeCentered.stateIn( +        keyguardClockInteractor.clockShouldBeCentered.stateIn(              scope = applicationScope,              started = SharingStarted.WhileSubscribed(),              initialValue = false @@ -113,18 +111,38 @@ constructor(          )      val currentClockLayout: StateFlow<ClockLayout> = -        combine(isLargeClockVisible, clockShouldBeCentered, shadeInteractor.shadeMode) { +        combine(                  isLargeClockVisible,                  clockShouldBeCentered, -                shadeMode -> +                shadeInteractor.shadeMode, +                currentClock +            ) { isLargeClockVisible, clockShouldBeCentered, shadeMode, currentClock ->                  val shouldUseSplitShade = shadeMode == ShadeMode.Split -                when { -                    shouldUseSplitShade && clockShouldBeCentered -> ClockLayout.LARGE_CLOCK -                    shouldUseSplitShade && isLargeClockVisible -> -                        ClockLayout.SPLIT_SHADE_LARGE_CLOCK -                    shouldUseSplitShade -> ClockLayout.SPLIT_SHADE_SMALL_CLOCK -                    isLargeClockVisible -> ClockLayout.LARGE_CLOCK -                    else -> ClockLayout.SMALL_CLOCK +                // TODO(b/326098079): make id a constant field in config +                if (currentClock?.config?.id == "DIGITAL_CLOCK_WEATHER") { +                    val weatherClockLayout = +                        when { +                            shouldUseSplitShade && clockShouldBeCentered -> +                                ClockLayout.WEATHER_LARGE_CLOCK +                            shouldUseSplitShade && isLargeClockVisible -> +                                ClockLayout.SPLIT_SHADE_WEATHER_LARGE_CLOCK +                            shouldUseSplitShade -> ClockLayout.SPLIT_SHADE_SMALL_CLOCK +                            isLargeClockVisible -> ClockLayout.WEATHER_LARGE_CLOCK +                            else -> ClockLayout.SMALL_CLOCK +                        } +                    weatherClockLayout +                } else { +                    val clockLayout = +                        when { +                            shouldUseSplitShade && clockShouldBeCentered -> ClockLayout.LARGE_CLOCK +                            shouldUseSplitShade && isLargeClockVisible -> +                                ClockLayout.SPLIT_SHADE_LARGE_CLOCK +                            shouldUseSplitShade -> ClockLayout.SPLIT_SHADE_SMALL_CLOCK +                            isLargeClockVisible -> ClockLayout.LARGE_CLOCK +                            else -> ClockLayout.SMALL_CLOCK +                        } + +                    clockLayout                  }              }              .stateIn( @@ -179,5 +197,7 @@ constructor(          SMALL_CLOCK,          SPLIT_SHADE_LARGE_CLOCK,          SPLIT_SHADE_SMALL_CLOCK, +        WEATHER_LARGE_CLOCK, +        SPLIT_SHADE_WEATHER_LARGE_CLOCK,      }  } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt index 4f2c6f576904..730015202a21 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockViewModel.kt @@ -16,13 +16,10 @@  package com.android.systemui.keyguard.ui.viewmodel -import android.content.Context -import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor  import com.android.systemui.keyguard.shared.model.SettingsClockSize  import com.android.systemui.plugins.clocks.ClockController  import javax.inject.Inject -import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.StateFlow  import kotlinx.coroutines.flow.map @@ -31,9 +28,7 @@ import kotlinx.coroutines.flow.map  class KeyguardPreviewClockViewModel  @Inject  constructor( -    @Application private val context: Context,      interactor: KeyguardClockInteractor, -    @Application private val applicationScope: CoroutineScope,  ) {      var shouldHighlightSelectedAffordance: Boolean = false diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt index b57e3ecbe05b..528b14c6bbd7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt @@ -17,7 +17,6 @@  package com.android.systemui.keyguard.ui.viewmodel  import android.content.Context -import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor  import com.android.systemui.keyguard.shared.model.SettingsClockSize  import com.android.systemui.res.R @@ -31,7 +30,6 @@ import kotlinx.coroutines.flow.map  class KeyguardPreviewSmartspaceViewModel  @Inject  constructor( -    @Application private val context: Context,      interactor: KeyguardClockInteractor,      val smartspaceViewModel: KeyguardSmartspaceViewModel,      val clockViewModel: KeyguardClockViewModel, @@ -55,29 +53,29 @@ constructor(                  }              } -    fun getSmartspaceStartPadding(): Int { +    fun getSmartspaceStartPadding(context: Context): Int {          return KeyguardSmartspaceViewModel.getSmartspaceStartMargin(context)      } -    fun getSmartspaceEndPadding(): Int { +    fun getSmartspaceEndPadding(context: Context): Int {          return KeyguardSmartspaceViewModel.getSmartspaceEndMargin(context)      } -    fun getSmallClockSmartspaceTopPadding(splitShadePreview: Boolean): Int { -        return getSmallClockTopPadding(splitShadePreview) + +    fun getSmallClockSmartspaceTopPadding(splitShadePreview: Boolean, context: Context): Int { +        return getSmallClockTopPadding(splitShadePreview, context) +              context.resources.getDimensionPixelSize(                  com.android.systemui.customization.R.dimen.small_clock_height              )      } -    fun getLargeClockSmartspaceTopPadding(splitShadePreview: Boolean): Int { -        return getSmallClockTopPadding(splitShadePreview) +    fun getLargeClockSmartspaceTopPadding(splitShadePreview: Boolean, context: Context): Int { +        return getSmallClockTopPadding(splitShadePreview, context)      }      /*       * SmallClockTopPadding decides the top position of smartspace       */ -    private fun getSmallClockTopPadding(splitShadePreview: Boolean): Int { +    private fun getSmallClockTopPadding(splitShadePreview: Boolean, context: Context): Int {          return with(context.resources) {              if (splitShadePreview) {                  getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt index 64e15659d08b..24a7c512a6a9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt @@ -42,6 +42,7 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor  import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor  import com.android.systemui.statusbar.phone.DozeParameters  import com.android.systemui.statusbar.phone.ScreenOffAnimationController +import com.android.systemui.util.kotlin.BooleanFlowOperators.or  import com.android.systemui.util.kotlin.pairwise  import com.android.systemui.util.kotlin.sample  import com.android.systemui.util.ui.AnimatableEvent @@ -133,22 +134,18 @@ constructor(      private val isOnLockscreen: Flow<Boolean> =          combine(                  keyguardTransitionInteractor.isFinishedInState(LOCKSCREEN).onStart { emit(false) }, -                keyguardTransitionInteractor -                    .isInTransitionWhere { from, to -> from == LOCKSCREEN || to == LOCKSCREEN } -                    .onStart { emit(false) } +                or( +                    keyguardTransitionInteractor.isInTransitionToState(LOCKSCREEN), +                    keyguardTransitionInteractor.isInTransitionFromState(LOCKSCREEN), +                ),              ) { onLockscreen, transitioningToOrFromLockscreen ->                  onLockscreen || transitioningToOrFromLockscreen              }              .distinctUntilChanged() -    private val lockscreenToGoneTransitionRunning: Flow<Boolean> = -        keyguardTransitionInteractor -            .isInTransitionWhere { from, to -> from == LOCKSCREEN && to == GONE } -            .onStart { emit(false) } -      private val alphaOnShadeExpansion: Flow<Float> =          combineTransform( -                lockscreenToGoneTransitionRunning, +                keyguardTransitionInteractor.isInTransition(from = LOCKSCREEN, to = GONE),                  isOnLockscreen,                  shadeInteractor.qsExpansion,                  shadeInteractor.shadeExpansion, @@ -185,8 +182,12 @@ constructor(                      .transitionValue(OCCLUDED)                      .map { it == 1f }                      .onStart { emit(false) }, -            ) { isIdleOnCommunal, isGone, isOccluded -> -                isIdleOnCommunal || isGone || isOccluded +                keyguardTransitionInteractor +                    .transitionValue(KeyguardState.DREAMING) +                    .map { it == 1f } +                    .onStart { emit(false) }, +            ) { isIdleOnCommunal, isGone, isOccluded, isDreaming -> +                isIdleOnCommunal || isGone || isOccluded || isDreaming              }              .distinctUntilChanged() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt index 993e81bfbf69..d4c8456e0d71 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt @@ -37,6 +37,8 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.SharingStarted  import kotlinx.coroutines.flow.StateFlow  import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf  import kotlinx.coroutines.flow.stateIn  /** Models UI state and handles user input for the lockscreen scene. */ @@ -52,16 +54,23 @@ constructor(      val notifications: NotificationsPlaceholderViewModel,  ) {      val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = -        combine( -                deviceEntryInteractor.isUnlocked, -                communalInteractor.isCommunalAvailable, -                shadeInteractor.shadeMode, -            ) { isDeviceUnlocked, isCommunalAvailable, shadeMode -> -                destinationScenes( -                    isDeviceUnlocked = isDeviceUnlocked, -                    isCommunalAvailable = isCommunalAvailable, -                    shadeMode = shadeMode, -                ) +        shadeInteractor.isShadeTouchable +            .flatMapLatest { isShadeTouchable -> +                if (!isShadeTouchable) { +                    flowOf(emptyMap()) +                } else { +                    combine( +                        deviceEntryInteractor.isUnlocked, +                        communalInteractor.isCommunalAvailable, +                        shadeInteractor.shadeMode, +                    ) { isDeviceUnlocked, isCommunalAvailable, shadeMode -> +                        destinationScenes( +                            isDeviceUnlocked = isDeviceUnlocked, +                            isCommunalAvailable = isCommunalAvailable, +                            shadeMode = shadeMode, +                        ) +                    } +                }              }              .stateIn(                  scope = applicationScope, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModel.kt new file mode 100644 index 000000000000..d2c9cfbd71b8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModel.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow + +/** Breaks down OCCLUDED->GONE transition into discrete steps for corresponding views to consume. */ +@ExperimentalCoroutinesApi +@SysUISingleton +class OccludedToGoneTransitionViewModel +@Inject +constructor( +    animationFlow: KeyguardTransitionAnimationFlow, +) { +    private val transitionAnimation = +        animationFlow.setup( +            duration = DEFAULT_DURATION, +            from = KeyguardState.OCCLUDED, +            to = KeyguardState.GONE, +        ) + +    fun notificationAlpha(viewState: ViewStateAccessor): Flow<Float> { +        var currentAlpha = 0f +        return transitionAnimation.sharedFlow( +            duration = DEFAULT_DURATION, +            onStart = { currentAlpha = viewState.alpha() }, +            onStep = { currentAlpha }, +            onFinish = { 1f }, +        ) +    } + +    companion object { +        val DEFAULT_DURATION = 300.milliseconds +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt index 3a19780c7017..a09d58ac381b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt @@ -21,15 +21,21 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor  import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor  import com.android.systemui.keyguard.shared.model.KeyguardState  import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow  import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition  import com.android.systemui.res.R +import com.android.systemui.util.kotlin.pairwise  import javax.inject.Inject  import kotlin.time.Duration.Companion.milliseconds  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter  import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge  /**   * Breaks down OCCLUDED->LOCKSCREEN transition into discrete steps for corresponding views to @@ -43,6 +49,8 @@ constructor(      deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,      configurationInteractor: ConfigurationInteractor,      animationFlow: KeyguardTransitionAnimationFlow, +    keyguardInteractor: KeyguardInteractor, +    keyguardTransitionInteractor: KeyguardTransitionInteractor,  ) : DeviceEntryIconTransition {      private val transitionAnimation = @@ -74,11 +82,28 @@ constructor(      /** Lockscreen views alpha */      val lockscreenAlpha: Flow<Float> = -        transitionAnimation.sharedFlow( -            startTime = 233.milliseconds, -            duration = 250.milliseconds, -            onStep = { it }, -            name = "OCCLUDED->LOCKSCREEN: lockscreenAlpha", +        merge( +            transitionAnimation.sharedFlow( +                startTime = 233.milliseconds, +                duration = 250.milliseconds, +                onStep = { it }, +                name = "OCCLUDED->LOCKSCREEN: lockscreenAlpha", +            ), +            // Required to fix a bug where the shade expands while lockscreenAlpha=1f, due to a call +            // to setOccluded(false) triggering a reset() call in KeyguardViewMediator. The +            // permanent solution is to only expand the shade once the keyguard transition from +            // OCCLUDED starts, but that requires more refactoring of expansion amounts. For now, +            // emit alpha = 0f for OCCLUDED -> LOCKSCREEN whenever isOccluded flips from true to +            // false while currentState == OCCLUDED, so that alpha = 0f when that expansion occurs. +            // TODO(b/332946323): Remove this once it's no longer needed. +            keyguardInteractor.isKeyguardOccluded +                .pairwise() +                .filter { (wasOccluded, isOccluded) -> +                    wasOccluded && +                        !isOccluded && +                        keyguardTransitionInteractor.getCurrentState() == KeyguardState.OCCLUDED +                } +                .map { 0f }          )      val deviceEntryBackgroundViewAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt index 05878265dd6d..a08a234f85d4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt @@ -18,10 +18,9 @@ package com.android.systemui.keyguard.ui.viewmodel  import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor  import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.flags.FeatureFlagsClassic -import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION  import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor +import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent  import com.android.systemui.keyguard.shared.model.KeyguardState.GONE  import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER  import com.android.systemui.keyguard.shared.model.ScrimAlpha @@ -46,7 +45,6 @@ constructor(      private val statusBarStateController: SysuiStatusBarStateController,      private val primaryBouncerInteractor: PrimaryBouncerInteractor,      keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>, -    featureFlags: FeatureFlagsClassic,      bouncerToGoneFlows: BouncerToGoneFlows,      animationFlow: KeyguardTransitionAnimationFlow,  ) { @@ -82,7 +80,7 @@ constructor(      /** Bouncer container alpha */      val bouncerAlpha: Flow<Float> = -        if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +        if (RefactorKeyguardDismissIntent.isEnabled) {              keyguardDismissActionInteractor                  .get()                  .willAnimateDismissActionOnLockscreen @@ -106,7 +104,7 @@ constructor(      /** Lockscreen alpha */      val lockscreenAlpha: Flow<Float> = -        if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +        if (RefactorKeyguardDismissIntent.isEnabled) {              keyguardDismissActionInteractor                  .get()                  .willAnimateDismissActionOnLockscreen diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt index df34169c9a50..9dc5900296c2 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt @@ -19,7 +19,9 @@ package com.android.systemui.media.controls.data.repository  import com.android.internal.logging.InstanceId  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.media.controls.shared.model.MediaData +import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel  import com.android.systemui.media.controls.shared.model.SmartspaceMediaData +import com.android.systemui.media.controls.shared.model.SmartspaceMediaLoadingModel  import javax.inject.Inject  import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.flow.StateFlow @@ -46,6 +48,16 @@ class MediaFilterRepository @Inject constructor() {          MutableStateFlow(LinkedHashMap())      val allUserEntries: StateFlow<Map<String, MediaData>> = _allUserEntries.asStateFlow() +    private val _mediaDataLoadedStates: MutableStateFlow<List<MediaDataLoadingModel>> = +        MutableStateFlow(mutableListOf()) +    val mediaDataLoadedStates: StateFlow<List<MediaDataLoadingModel>> = +        _mediaDataLoadedStates.asStateFlow() + +    private val _recommendationsLoadingState: MutableStateFlow<SmartspaceMediaLoadingModel> = +        MutableStateFlow(SmartspaceMediaLoadingModel.Unknown) +    val recommendationsLoadingState: StateFlow<SmartspaceMediaLoadingModel> = +        _recommendationsLoadingState.asStateFlow() +      fun addMediaEntry(key: String, data: MediaData) {          val entries = LinkedHashMap<String, MediaData>(_allUserEntries.value)          entries[key] = data @@ -110,4 +122,25 @@ class MediaFilterRepository @Inject constructor() {      fun setReactivatedId(instanceId: InstanceId?) {          _reactivatedId.value = instanceId      } + +    fun addMediaDataLoadingState(mediaDataLoadingModel: MediaDataLoadingModel) { +        // Filter out previous loading state that has same [InstanceId]. +        val loadedStates = +            _mediaDataLoadedStates.value.filter { loadedModel -> +                loadedModel !is MediaDataLoadingModel.Loaded || +                    !loadedModel.equalInstanceIds(mediaDataLoadingModel) +            } + +        _mediaDataLoadedStates.value = +            loadedStates + +                if (mediaDataLoadingModel is MediaDataLoadingModel.Loaded) { +                    listOf(mediaDataLoadingModel) +                } else { +                    emptyList() +                } +    } + +    fun setRecommedationsLoadingState(smartspaceMediaLoadingModel: SmartspaceMediaLoadingModel) { +        _recommendationsLoadingState.value = smartspaceMediaLoadingModel +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt index d40069c4b3da..a30e5826529a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt @@ -28,7 +28,9 @@ import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.media.controls.data.repository.MediaFilterRepository  import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_RESUME  import com.android.systemui.media.controls.shared.model.MediaData +import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel  import com.android.systemui.media.controls.shared.model.SmartspaceMediaData +import com.android.systemui.media.controls.shared.model.SmartspaceMediaLoadingModel  import com.android.systemui.media.controls.util.MediaFlags  import com.android.systemui.media.controls.util.MediaUiEventLogger  import com.android.systemui.settings.UserTracker @@ -67,9 +69,6 @@ constructor(      private val mediaFlags: MediaFlags,      private val mediaFilterRepository: MediaFilterRepository,  ) : MediaDataManager.Listener { -    private val _listeners: MutableSet<Listener> = mutableSetOf() -    val listeners: Set<Listener> -        get() = _listeners.toSet()      lateinit var mediaDataManager: MediaDataManager      // Ensure the field (and associated reference) isn't removed during optimization. @@ -111,8 +110,9 @@ constructor(          mediaFilterRepository.addSelectedUserMediaEntry(data) -        // Notify listeners -        listeners.forEach { it.onMediaDataLoaded(data.instanceId) } +        mediaFilterRepository.addMediaDataLoadingState( +            MediaDataLoadingModel.Loaded(data.instanceId) +        )      }      override fun onSmartspaceMediaDataLoaded( @@ -159,7 +159,7 @@ constructor(              // reactivate.              if (shouldReactivate) {                  val lastActiveId = sorted.lastKey() // most recently active id -                // Notify listeners to consider this media active +                // Update loading state to consider this media active                  Log.d(TAG, "reactivating $lastActiveId instead of smartspace")                  mediaFilterRepository.setReactivatedId(lastActiveId)                  val mediaData = sorted[lastActiveId]!!.copy(active = true) @@ -168,15 +168,9 @@ constructor(                      mediaData.packageName,                      mediaData.instanceId                  ) -                listeners.forEach { -                    it.onMediaDataLoaded( -                        lastActiveId, -                        receivedSmartspaceCardLatency = -                            (systemClock.currentTimeMillis() - data.headphoneConnectionTimeMillis) -                                .toInt(), -                        isSsReactivated = true -                    ) -                } +                mediaFilterRepository.addMediaDataLoadingState( +                    MediaDataLoadingModel.Loaded(lastActiveId) +                )              }          } else if (data.isActive) {              // Mark to prioritize Smartspace card if no recent media. @@ -192,15 +186,18 @@ constructor(              smartspaceMediaData.packageName,              smartspaceMediaData.instanceId          ) -        listeners.forEach { it.onSmartspaceMediaDataLoaded(key, shouldPrioritizeMutable) } +        mediaFilterRepository.setRecommedationsLoadingState( +            SmartspaceMediaLoadingModel.Loaded(key, shouldPrioritizeMutable) +        )      }      override fun onMediaDataRemoved(key: String) {          mediaFilterRepository.removeMediaEntry(key)?.let { mediaData ->              val instanceId = mediaData.instanceId              mediaFilterRepository.removeSelectedUserMediaEntry(instanceId)?.let { -                // Only notify listeners if something actually changed -                listeners.forEach { it.onMediaDataRemoved(instanceId) } +                mediaFilterRepository.addMediaDataLoadingState( +                    MediaDataLoadingModel.Removed(instanceId) +                )              }          }      } @@ -210,11 +207,11 @@ constructor(          mediaFilterRepository.reactivatedId.value?.let { lastActiveId ->              mediaFilterRepository.setReactivatedId(null)              Log.d(TAG, "expiring reactivated key $lastActiveId") -            // Notify listeners to update with actual active value +            // Update loading state with actual active value              mediaFilterRepository.selectedUserEntries.value[lastActiveId]?.let { -                listeners.forEach { listener -> -                    listener.onMediaDataLoaded(lastActiveId, immediately) -                } +                mediaFilterRepository.addMediaDataLoadingState( +                    MediaDataLoadingModel.Loaded(lastActiveId, immediately) +                )              }          } @@ -227,7 +224,9 @@ constructor(                  )              )          } -        listeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) } +        mediaFilterRepository.setRecommedationsLoadingState( +            SmartspaceMediaLoadingModel.Removed(key, immediately) +        )      }      @VisibleForTesting @@ -238,29 +237,37 @@ constructor(                  // Only remove media when the profile is unavailable.                  if (DEBUG) Log.d(TAG, "Removing $key after profile change")                  mediaFilterRepository.removeSelectedUserMediaEntry(data.instanceId, data) -                listeners.forEach { listener -> listener.onMediaDataRemoved(data.instanceId) } +                mediaFilterRepository.addMediaDataLoadingState( +                    MediaDataLoadingModel.Removed(data.instanceId) +                )              }          }      }      @VisibleForTesting      internal fun handleUserSwitched() { -        // If the user changes, remove all current MediaData objects and inform listeners -        val listenersCopy = listeners +        // If the user changes, remove all current MediaData objects.          val keyCopy = mediaFilterRepository.selectedUserEntries.value.keys.toMutableList() -        // Clear the list first, to make sure callbacks from listeners if we have any entries -        // are up to date +        // Clear the list first and update loading state to remove media from UI.          mediaFilterRepository.clearSelectedUserMedia()          keyCopy.forEach { instanceId ->              if (DEBUG) Log.d(TAG, "Removing $instanceId after user change") -            listenersCopy.forEach { listener -> listener.onMediaDataRemoved(instanceId) } +            mediaFilterRepository.addMediaDataLoadingState( +                MediaDataLoadingModel.Removed(instanceId) +            )          }          mediaFilterRepository.allUserEntries.value.forEach { (key, data) ->              if (lockscreenUserManager.isCurrentProfile(data.userId)) { -                if (DEBUG) Log.d(TAG, "Re-adding $key after user change") +                if (DEBUG) +                    Log.d( +                        TAG, +                        "Re-adding $key with instanceId=${data.instanceId} after user change" +                    )                  mediaFilterRepository.addSelectedUserMediaEntry(data) -                listenersCopy.forEach { listener -> listener.onMediaDataLoaded(data.instanceId) } +                mediaFilterRepository.addMediaDataLoadingState( +                    MediaDataLoadingModel.Loaded(data.instanceId) +                )              }          }      } @@ -310,12 +317,6 @@ constructor(          }      } -    /** Add a listener for filtered [MediaData] changes */ -    fun addListener(listener: Listener) = _listeners.add(listener) - -    /** Remove a listener that was registered with addListener */ -    fun removeListener(listener: Listener) = _listeners.remove(listener) -      /**       * Return the time since last active for the most-recent media.       * @@ -335,48 +336,6 @@ constructor(          return sortedEntries[lastActiveInstanceId]?.let { now - it.lastActive } ?: Long.MAX_VALUE      } -    interface Listener { -        /** -         * Called whenever there's new MediaData Loaded for the consumption in views. -         * -         * @param immediately indicates should apply the UI changes immediately, otherwise wait -         *   until the next refresh-round before UI becomes visible. True by default to take in -         *   place immediately. -         * @param receivedSmartspaceCardLatency is the latency between headphone connects and sysUI -         *   displays Smartspace media targets. Will be 0 if the data is not activated by Smartspace -         *   signal. -         * @param isSsReactivated indicates resume media card is reactivated by Smartspace -         *   recommendation signal -         */ -        fun onMediaDataLoaded( -            instanceId: InstanceId, -            immediately: Boolean = true, -            receivedSmartspaceCardLatency: Int = 0, -            isSsReactivated: Boolean = false, -        ) - -        /** -         * Called whenever there's new Smartspace media data loaded. -         * -         * @param shouldPrioritize indicates the sorting priority of the Smartspace card. If true, -         *   it will be prioritized as the first card. Otherwise, it will show up as the last card -         *   as default. -         */ -        fun onSmartspaceMediaDataLoaded(key: String, shouldPrioritize: Boolean = false) - -        /** Called whenever a previously existing Media notification was removed. */ -        fun onMediaDataRemoved(instanceId: InstanceId) - -        /** -         * Called whenever a previously existing Smartspace media data was removed. -         * -         * @param immediately indicates should apply the UI changes immediately, otherwise wait -         *   until the next refresh-round before UI becomes visible. True by default to take in -         *   place immediately. -         */ -        fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean = true) -    } -      companion object {          /**           * Maximum age of a media control to re-activate on smartspace signal. If there is no media diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt index 7412290e8fc5..1d7c0256b2ef 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt @@ -590,7 +590,7 @@ class MediaDataProcessor(      }      /** Dismiss a media entry. Returns false if the key was not found. */ -    fun dismissMediaData(key: String, delay: Long): Boolean { +    fun dismissMediaData(key: String, delayMs: Long): Boolean {          val existed = mediaDataRepository.mediaEntries.value[key] != null          backgroundExecutor.execute {              mediaDataRepository.mediaEntries.value[key]?.let { mediaData -> @@ -602,10 +602,21 @@ class MediaDataProcessor(                  }              }          } -        foregroundExecutor.executeDelayed({ removeEntry(key) }, delay) +        foregroundExecutor.executeDelayed({ removeEntry(key) }, delayMs)          return existed      } +    /** Dismiss a media entry. Returns false if the corresponding key was not found. */ +    fun dismissMediaData(instanceId: InstanceId, delayMs: Long): Boolean { +        val mediaEntries = mediaDataRepository.mediaEntries.value +        val filteredEntries = mediaEntries.filter { (_, data) -> data.instanceId == instanceId } +        return if (filteredEntries.isNotEmpty()) { +            dismissMediaData(filteredEntries.keys.first(), delayMs) +        } else { +            false +        } +    } +      /**       * Called whenever the recommendation has been expired or removed by the user. This will remove       * the recommendation card entirely from the carousel. diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt index 7dbca0ae4cda..cdcf3636e148 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt @@ -34,11 +34,14 @@ import com.android.systemui.media.controls.domain.pipeline.MediaDeviceManager  import com.android.systemui.media.controls.domain.pipeline.MediaSessionBasedFilter  import com.android.systemui.media.controls.domain.pipeline.MediaTimeoutListener  import com.android.systemui.media.controls.domain.resume.MediaResumeListener +import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel +import com.android.systemui.media.controls.shared.model.SmartspaceMediaLoadingModel  import com.android.systemui.media.controls.util.MediaFlags  import java.io.PrintWriter  import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.SharingStarted  import kotlinx.coroutines.flow.StateFlow  import kotlinx.coroutines.flow.combine @@ -109,6 +112,14 @@ constructor(              .distinctUntilChanged()              .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false) +    /** The most recent list of loaded media controls. */ +    val mediaDataLoadedStates: Flow<List<MediaDataLoadingModel>> = +        mediaFilterRepository.mediaDataLoadedStates + +    /** The most recent change to loaded media recommendations. */ +    val recommendationsLoadingState: Flow<SmartspaceMediaLoadingModel> = +        mediaFilterRepository.recommendationsLoadingState +      override fun start() {          if (!mediaFlags.isMediaControlsRefactorEnabled()) {              return diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt index 5a0388de444e..74cd2fee94ec 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt @@ -16,20 +16,49 @@  package com.android.systemui.media.controls.domain.pipeline.interactor +import android.app.ActivityOptions +import android.app.BroadcastOptions +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.media.session.MediaController +import android.media.session.MediaSession +import android.media.session.PlaybackState +import android.provider.Settings +import android.util.Log +import com.android.internal.jank.Cuj  import com.android.internal.logging.InstanceId +import com.android.systemui.ActivityIntentHelper +import com.android.systemui.animation.DialogCuj +import com.android.systemui.animation.DialogTransitionAnimator +import com.android.systemui.animation.Expandable +import com.android.systemui.bluetooth.BroadcastDialogController +import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.media.controls.data.repository.MediaFilterRepository  import com.android.systemui.media.controls.domain.pipeline.MediaDataProcessor  import com.android.systemui.media.controls.shared.model.MediaControlModel  import com.android.systemui.media.controls.shared.model.MediaData +import com.android.systemui.media.dialog.MediaOutputDialogManager +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.statusbar.NotificationLockscreenUserManager +import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.util.kotlin.pairwiseBy  import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.distinctUntilChanged  import kotlinx.coroutines.flow.map  /** Encapsulates business logic for single media control. */  class MediaControlInteractor( -    instanceId: InstanceId, +    @Application applicationContext: Context, +    private val instanceId: InstanceId,      repository: MediaFilterRepository,      private val mediaDataProcessor: MediaDataProcessor, +    private val keyguardStateController: KeyguardStateController, +    private val activityStarter: ActivityStarter, +    private val activityIntentHelper: ActivityIntentHelper, +    private val lockscreenUserManager: NotificationLockscreenUserManager, +    private val mediaOutputDialogManager: MediaOutputDialogManager, +    private val broadcastDialogController: BroadcastDialogController,  ) {      val mediaControl: Flow<MediaControlModel?> = @@ -37,8 +66,32 @@ class MediaControlInteractor(              .map { entries -> entries[instanceId]?.let { toMediaControlModel(it) } }              .distinctUntilChanged() -    fun removeMediaControl(key: String, delayMs: Long): Boolean { -        return mediaDataProcessor.dismissMediaData(key, delayMs) +    val isStartedPlaying: Flow<Boolean> = +        mediaControl +            .map { mediaControl -> +                mediaControl?.token?.let { token -> +                    MediaController(applicationContext, token).playbackState?.let { +                        it.state == PlaybackState.STATE_PLAYING +                    } +                } +                    ?: false +            } +            .pairwiseBy(initialValue = false) { wasPlaying, isPlaying -> !wasPlaying && isPlaying } +            .distinctUntilChanged() + +    fun removeMediaControl( +        token: MediaSession.Token?, +        instanceId: InstanceId, +        delayMs: Long +    ): Boolean { +        val dismissed = mediaDataProcessor.dismissMediaData(instanceId, delayMs) +        if (!dismissed) { +            Log.w( +                TAG, +                "Manager failed to dismiss media of instanceId=$instanceId, Token uid=${token?.uid}" +            ) +        } +        return dismissed      }      private fun toMediaControlModel(data: MediaData): MediaControlModel { @@ -53,14 +106,89 @@ class MediaControlInteractor(                  appName = app,                  songName = song,                  artistName = artist, +                showExplicit = isExplicit,                  artwork = artwork,                  deviceData = device,                  semanticActionButtons = semanticActions,                  notificationActionButtons = actions,                  actionsToShowInCollapsed = actionsToShowInCompact, +                isDismissible = isClearable,                  isResume = resumption,                  resumeProgress = resumeProgress,              )          }      } + +    fun startSettings() { +        activityStarter.startActivity(SETTINGS_INTENT, /* dismissShade= */ true) +    } + +    fun startClickIntent(expandable: Expandable, clickIntent: PendingIntent) { +        if (!launchOverLockscreen(clickIntent)) { +            activityStarter.postStartActivityDismissingKeyguard( +                clickIntent, +                expandable.activityTransitionController(Cuj.CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER) +            ) +        } +    } + +    fun startDeviceIntent(deviceIntent: PendingIntent) { +        if (deviceIntent.isActivity) { +            if (!launchOverLockscreen(deviceIntent)) { +                activityStarter.postStartActivityDismissingKeyguard(deviceIntent) +            } +        } else { +            Log.w(TAG, "Device pending intent of instanceId=$instanceId is not an activity.") +        } +    } + +    private fun launchOverLockscreen(pendingIntent: PendingIntent): Boolean { +        val showOverLockscreen = +            keyguardStateController.isShowing && +                activityIntentHelper.wouldPendingShowOverLockscreen( +                    pendingIntent, +                    lockscreenUserManager.currentUserId +                ) +        if (showOverLockscreen) { +            try { +                val options = BroadcastOptions.makeBasic() +                options.isInteractive = true +                options.pendingIntentBackgroundActivityStartMode = +                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED +                pendingIntent.send(options.toBundle()) +            } catch (e: PendingIntent.CanceledException) { +                Log.e(TAG, "pending intent of $instanceId was canceled") +            } +            return true +        } +        return false +    } + +    fun startMediaOutputDialog(expandable: Expandable, packageName: String) { +        mediaOutputDialogManager.createAndShowWithController( +            packageName, +            true, +            expandable.dialogController() +        ) +    } + +    fun startBroadcastDialog(expandable: Expandable, broadcastApp: String, packageName: String) { +        broadcastDialogController.createBroadcastDialogWithController( +            broadcastApp, +            packageName, +            expandable.dialogTransitionController() +        ) +    } + +    private fun Expandable.dialogController(): DialogTransitionAnimator.Controller? { +        return dialogTransitionController( +            cuj = +                DialogCuj(Cuj.CUJ_SHADE_DIALOG_OPEN, MediaOutputDialogManager.INTERACTION_JANK_TAG) +        ) +    } + +    companion object { +        private const val TAG = "MediaControlInteractor" +        private val SETTINGS_INTENT = Intent(Settings.ACTION_MEDIA_CONTROLS_SETTINGS) +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaControlModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaControlModel.kt index d4e34b5af260..f9134f52b58f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaControlModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaControlModel.kt @@ -33,6 +33,7 @@ data class MediaControlModel(      val appName: String?,      val songName: CharSequence?,      val artistName: CharSequence?, +    val showExplicit: Boolean,      val artwork: Icon?,      val deviceData: MediaDeviceData?,      /** [MediaButton] contains [MediaAction] objects which represent specific buttons in the UI */ @@ -43,6 +44,7 @@ data class MediaControlModel(       * [Notification.MediaStyle.setShowActionsInCompactView].       */      val actionsToShowInCollapsed: List<Int>, +    val isDismissible: Boolean,      /** Whether player is in resumption state. */      val isResume: Boolean,      /** Track seek bar progress (0 - 1) when [isResume] is true. */ diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaDataLoadingModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaDataLoadingModel.kt new file mode 100644 index 000000000000..bd42a4df7262 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaDataLoadingModel.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.controls.shared.model + +import com.android.internal.logging.InstanceId + +/** Models media data loading state. */ +sealed class MediaDataLoadingModel { +    /** The initial loading state when no media data has yet loaded. */ +    data object Unknown : MediaDataLoadingModel() + +    /** Media data has been loaded. */ +    data class Loaded( +        val instanceId: InstanceId, +        val immediatelyUpdateUi: Boolean = true, +    ) : MediaDataLoadingModel() { + +        /** Returns true if [other] has the same instance id, false otherwise. */ +        fun equalInstanceIds(other: MediaDataLoadingModel): Boolean { +            return when (other) { +                is Loaded -> other.instanceId == instanceId +                is Removed -> other.instanceId == instanceId +                Unknown -> false +            } +        } +    } + +    /** Media data has been removed. */ +    data class Removed( +        val instanceId: InstanceId, +    ) : MediaDataLoadingModel() +} diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/SmartspaceMediaLoadingModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/SmartspaceMediaLoadingModel.kt new file mode 100644 index 000000000000..6c1e536f8c02 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/SmartspaceMediaLoadingModel.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.controls.shared.model + +/** Models smartspace media loading state. */ +sealed class SmartspaceMediaLoadingModel { +    /** The initial loading state when no smartspace media has yet loaded. */ +    data object Unknown : SmartspaceMediaLoadingModel() + +    /** Smartspace media has been loaded. */ +    data class Loaded( +        val key: String, +        val isPrioritized: Boolean = false, +    ) : SmartspaceMediaLoadingModel() + +    /** Smartspace media has been removed. */ +    data class Removed( +        val key: String, +        val immediatelyUpdateUi: Boolean = true, +    ) : SmartspaceMediaLoadingModel() +} diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt index 963c602b3d1e..c02ce3b0a6c0 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt @@ -297,6 +297,7 @@ constructor(          }      } -    private val activeContainer: ViewGroup? = -        if (useSplitShade) splitShadeContainer else singlePaneContainer +    // This field is only used to log current active container. +    private val activeContainer: ViewGroup? +        get() = if (useSplitShade) splitShadeContainer else singlePaneContainer  } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt index c3c1e83546df..d15d45a477d7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt @@ -46,6 +46,8 @@ import com.android.systemui.dagger.qualifiers.Main  import com.android.systemui.dump.DumpManager  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor  import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.KeyguardState.GONE +import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN  import com.android.systemui.keyguard.shared.model.TransitionState  import com.android.systemui.lifecycle.repeatWhenAttached  import com.android.systemui.media.controls.domain.pipeline.MediaDataManager @@ -600,7 +602,8 @@ constructor(      @VisibleForTesting      internal fun listenForAnyStateToGoneKeyguardTransition(scope: CoroutineScope): Job {          return scope.launch { -            keyguardTransitionInteractor.anyStateToGoneTransition +            keyguardTransitionInteractor +                .transition(to = GONE)                  .filter { it.transitionState == TransitionState.FINISHED }                  .collect {                      showMediaCarousel() @@ -612,7 +615,8 @@ constructor(      @VisibleForTesting      internal fun listenForAnyStateToLockscreenTransition(scope: CoroutineScope): Job {          return scope.launch { -            keyguardTransitionInteractor.anyStateToLockscreenTransition +            keyguardTransitionInteractor +                .transition(to = LOCKSCREEN)                  .filter { it.transitionState == TransitionState.FINISHED }                  .collect {                      if (!allowMediaPlayerOnLockScreen) { diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java index 899b9ed103cd..1a56a9b1dda6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java @@ -118,8 +118,9 @@ import com.android.systemui.res.R;  import com.android.systemui.shared.system.SysUiStatsLog;  import com.android.systemui.statusbar.NotificationLockscreenUserManager;  import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.surfaceeffects.PaintDrawCallback;  import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect; -import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState; +import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.AnimationState;  import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView;  import com.android.systemui.surfaceeffects.ripple.MultiRippleController;  import com.android.systemui.surfaceeffects.ripple.MultiRippleView; @@ -264,15 +265,15 @@ public class MediaControlPanel {      private boolean mWasPlaying = false;      private boolean mButtonClicked = false; -    private final LoadingEffect.Companion.PaintDrawCallback mNoiseDrawCallback = -            new LoadingEffect.Companion.PaintDrawCallback() { +    private final PaintDrawCallback mNoiseDrawCallback = +            new PaintDrawCallback() {                  @Override -                public void onDraw(@NonNull Paint loadingPaint) { -                    mMediaViewHolder.getLoadingEffectView().draw(loadingPaint); +                public void onDraw(@NonNull Paint paint) { +                    mMediaViewHolder.getLoadingEffectView().draw(paint);                  }              }; -    private final LoadingEffect.Companion.AnimationStateChangedCallback mStateChangedCallback = -            new LoadingEffect.Companion.AnimationStateChangedCallback() { +    private final LoadingEffect.AnimationStateChangedCallback mStateChangedCallback = +            new LoadingEffect.AnimationStateChangedCallback() {                  @Override                  public void onStateChanged(@NonNull AnimationState oldState,                          @NonNull AnimationState newState) { @@ -747,18 +748,23 @@ public class MediaControlPanel {                              boolean showOverLockscreen = mKeyguardStateController.isShowing()                                      && mActivityIntentHelper.wouldPendingShowOverLockscreen(                                          deviceIntent, mLockscreenUserManager.getCurrentUserId()); -                            if (deviceIntent.isActivity() && !showOverLockscreen) { -                                mActivityStarter.postStartActivityDismissingKeyguard(deviceIntent); -                            } else { -                                try { -                                    BroadcastOptions options = BroadcastOptions.makeBasic(); -                                    options.setInteractive(true); -                                    options.setPendingIntentBackgroundActivityStartMode( +                            if (deviceIntent.isActivity()) { +                                if (!showOverLockscreen) { +                                    mActivityStarter.postStartActivityDismissingKeyguard( +                                            deviceIntent); +                                } else { +                                    try { +                                        BroadcastOptions options = BroadcastOptions.makeBasic(); +                                        options.setInteractive(true); +                                        options.setPendingIntentBackgroundActivityStartMode(                                              ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED); -                                    deviceIntent.send(options.toBundle()); -                                } catch (PendingIntent.CanceledException e) { -                                    Log.e(TAG, "Device pending intent was canceled"); +                                        deviceIntent.send(options.toBundle()); +                                    } catch (PendingIntent.CanceledException e) { +                                        Log.e(TAG, "Device pending intent was canceled"); +                                    }                                  } +                            } else { +                                Log.w(TAG, "Device pending intent is not an activity.");                              }                          } else {                              mMediaOutputDialogManager.createAndShow(mPackageName, true, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt index eec43a68adfd..3b09f4138658 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt @@ -18,6 +18,7 @@ package com.android.systemui.media.controls.ui.util  import android.app.WallpaperColors  import android.content.Context +import android.content.pm.PackageManager  import android.graphics.Rect  import android.graphics.drawable.Drawable  import android.graphics.drawable.GradientDrawable @@ -27,6 +28,7 @@ import android.util.Log  import com.android.systemui.media.controls.ui.animation.backgroundEndFromScheme  import com.android.systemui.media.controls.ui.animation.backgroundStartFromScheme  import com.android.systemui.monet.ColorScheme +import com.android.systemui.monet.Style  import com.android.systemui.util.getColorWithAlpha  import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.withContext @@ -94,4 +96,21 @@ object MediaArtworkHelper {              )          return LayerDrawable(arrayOf(albumArt, gradient))      } + +    /** Returns [ColorScheme] of media app given its [packageName]. */ +    fun getColorScheme( +        applicationContext: Context, +        packageName: String, +        tag: String, +        style: Style = Style.TONAL_SPOT +    ): ColorScheme? { +        return try { +            // Set up media source app's logo. +            val icon = applicationContext.packageManager.getApplicationIcon(packageName) +            ColorScheme(WallpaperColors.fromDrawable(icon), darkTheme = true, style) +        } catch (e: PackageManager.NameNotFoundException) { +            Log.w(tag, "Fail to get media app info", e) +            null +        } +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaActionViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaActionViewModel.kt new file mode 100644 index 000000000000..1e67a77250ee --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaActionViewModel.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.controls.ui.viewmodel + +import android.graphics.drawable.Drawable +import androidx.constraintlayout.widget.ConstraintSet + +/** Models UI state of media buttons in media control. */ +data class MediaActionViewModel( +    val icon: Drawable?, +    val contentDescription: CharSequence?, +    val background: Drawable?, +    val isVisible: Boolean = true, +    val notVisibleValue: Int = ConstraintSet.GONE, +    val showInCollapsed: Boolean, +    val rebindId: Int? = null, +    val buttonId: Int? = null, +    val isEnabled: Boolean, +    val onClicked: (Int) -> Unit, +) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt new file mode 100644 index 000000000000..117b2af3046c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.controls.ui.viewmodel + +import android.content.Context +import android.content.pm.PackageManager +import android.media.session.MediaSession.Token +import android.text.TextUtils +import android.util.Log +import androidx.constraintlayout.widget.ConstraintSet +import com.android.internal.logging.InstanceId +import com.android.settingslib.flags.Flags.legacyLeAudioSharing +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.media.controls.domain.pipeline.interactor.MediaControlInteractor +import com.android.systemui.media.controls.shared.model.MediaAction +import com.android.systemui.media.controls.shared.model.MediaButton +import com.android.systemui.media.controls.shared.model.MediaControlModel +import com.android.systemui.media.controls.ui.animation.accentPrimaryFromScheme +import com.android.systemui.media.controls.ui.animation.surfaceFromScheme +import com.android.systemui.media.controls.ui.animation.textPrimaryFromScheme +import com.android.systemui.media.controls.ui.util.MediaArtworkHelper +import com.android.systemui.media.controls.util.MediaUiEventLogger +import com.android.systemui.monet.ColorScheme +import com.android.systemui.monet.Style +import com.android.systemui.res.R +import com.android.systemui.util.kotlin.sample +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOn + +/** Models UI state and handles user input for a media control. */ +class MediaControlViewModel( +    @Application private val applicationContext: Context, +    @Background private val backgroundDispatcher: CoroutineDispatcher, +    private val interactor: MediaControlInteractor, +    private val logger: MediaUiEventLogger, +) { + +    private val isAnyButtonClicked: MutableStateFlow<Boolean> = MutableStateFlow(false) + +    private val playTurbulenceNoise: Flow<Boolean> = +        interactor.mediaControl.sample( +            combine(isAnyButtonClicked, interactor.isStartedPlaying) { +                    isButtonClicked, +                    isStartedPlaying -> +                    isButtonClicked && isStartedPlaying +                } +                .distinctUntilChanged() +        ) + +    val player: Flow<MediaPlayerViewModel?> = +        combine(playTurbulenceNoise, interactor.mediaControl) { playTurbulenceNoise, mediaControl -> +                mediaControl?.let { toViewModel(it, playTurbulenceNoise) } +            } +            .distinctUntilChanged() +            .flowOn(backgroundDispatcher) + +    private fun onDismissMediaData( +        token: Token?, +        uid: Int, +        packageName: String, +        instanceId: InstanceId +    ) { +        logger.logLongPressDismiss(uid, packageName, instanceId) +        interactor.removeMediaControl(token, instanceId, MEDIA_PLAYER_ANIMATION_DELAY) +    } + +    private suspend fun toViewModel( +        model: MediaControlModel, +        playTurbulenceNoise: Boolean +    ): MediaPlayerViewModel? { +        val wallpaperColors = +            MediaArtworkHelper.getWallpaperColor( +                applicationContext, +                backgroundDispatcher, +                model.artwork, +                TAG +            ) +        val scheme = +            wallpaperColors?.let { ColorScheme(it, true, Style.CONTENT) } +                ?: MediaArtworkHelper.getColorScheme( +                    applicationContext, +                    model.packageName, +                    TAG, +                    Style.CONTENT +                ) +                    ?: return null + +        val gutsViewModel = toGutsViewModel(model, scheme) + +        // Resetting button clicks state. +        isAnyButtonClicked.value = false + +        return MediaPlayerViewModel( +            contentDescription = { gutsVisible -> +                if (gutsVisible) { +                    gutsViewModel.gutsText +                } else { +                    applicationContext.getString( +                        R.string.controls_media_playing_item_description, +                        model.songName, +                        model.artistName, +                        model.appName +                    ) +                } +            }, +            backgroundCover = model.artwork, +            appIcon = getAppIcon(model.appIcon, model.isResume, model.packageName), +            useGrayColorFilter = model.appIcon == null || model.isResume, +            artistName = model.artistName ?: "", +            titleName = model.songName ?: "", +            isExplicitVisible = model.showExplicit, +            colorScheme = scheme, +            isTimeVisible = canShowScrubbingTimeViews(model.semanticActionButtons), +            playTurbulenceNoise = playTurbulenceNoise, +            useSemanticActions = model.semanticActionButtons != null, +            actionButtons = toActionViewModels(model), +            outputSwitcher = toOutputSwitcherViewModel(model), +            gutsMenu = gutsViewModel, +            onClicked = { expandable -> +                model.clickIntent?.let { clickIntent -> +                    logger.logTapContentView(model.uid, model.packageName, model.instanceId) +                    // TODO (b/330897926) log smartspace card reported (SMARTSPACE_CARD_CLICK_EVENT) +                    interactor.startClickIntent(expandable, clickIntent) +                } +            }, +            onLongClicked = { +                logger.logLongPressOpen(model.uid, model.packageName, model.instanceId) +            }, +        ) +    } + +    private fun toOutputSwitcherViewModel(model: MediaControlModel): MediaOutputSwitcherViewModel { +        val device = model.deviceData +        val showBroadcastButton = legacyLeAudioSharing() && device?.showBroadcastButton == true + +        // TODO(b/233698402): Use the package name instead of app label to avoid the unexpected +        //  result. +        val isCurrentBroadcastApp = +            device?.name?.let { +                TextUtils.equals( +                    it, +                    applicationContext.getString(R.string.broadcasting_description_is_broadcasting) +                ) +            } +                ?: false +        val useDisabledAlpha = +            if (showBroadcastButton) { +                !isCurrentBroadcastApp +            } else { +                device?.enabled == false || model.isResume +            } +        val deviceString = +            device?.name +                ?: if (showBroadcastButton) { +                    applicationContext.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name) +                } else { +                    applicationContext.getString(R.string.media_seamless_other_device) +                } +        return MediaOutputSwitcherViewModel( +            isTapEnabled = showBroadcastButton || !useDisabledAlpha, +            deviceString = deviceString, +            deviceIcon = device?.icon?.let { Icon.Loaded(it, null) } +                    ?: if (showBroadcastButton) { +                        Icon.Resource(R.drawable.settings_input_antenna, null) +                    } else { +                        Icon.Resource(R.drawable.ic_media_home_devices, null) +                    }, +            isCurrentBroadcastApp = isCurrentBroadcastApp, +            isIntentValid = device?.intent != null, +            alpha = +                if (useDisabledAlpha) { +                    DISABLED_ALPHA +                } else { +                    1.0f +                }, +            isVisible = showBroadcastButton, +            onClicked = { expandable -> +                if (showBroadcastButton) { +                    // If the current media app is not broadcasted and users press the outputer +                    // button, we should pop up the broadcast dialog to check do they want to +                    // switch broadcast to the other media app, otherwise we still pop up the +                    // media output dialog. +                    if (!isCurrentBroadcastApp) { +                        logger.logOpenBroadcastDialog( +                            model.uid, +                            model.packageName, +                            model.instanceId +                        ) +                        interactor.startBroadcastDialog( +                            expandable, +                            device?.name.toString(), +                            model.packageName +                        ) +                    } else { +                        logger.logOpenOutputSwitcher(model.uid, model.packageName, model.instanceId) +                        interactor.startMediaOutputDialog(expandable, model.packageName) +                    } +                } else { +                    logger.logOpenOutputSwitcher(model.uid, model.packageName, model.instanceId) +                    device?.intent?.let { interactor.startDeviceIntent(it) } +                        ?: interactor.startMediaOutputDialog(expandable, model.packageName) +                } +            } +        ) +    } + +    private fun toGutsViewModel(model: MediaControlModel, scheme: ColorScheme): GutsViewModel { +        return GutsViewModel( +            gutsText = +                if (model.isDismissible) { +                    applicationContext.getString( +                        R.string.controls_media_close_session, +                        model.appName +                    ) +                } else { +                    applicationContext.getString(R.string.controls_media_active_session) +                }, +            textColor = textPrimaryFromScheme(scheme), +            buttonBackgroundColor = accentPrimaryFromScheme(scheme), +            buttonTextColor = surfaceFromScheme(scheme), +            isDismissEnabled = model.isDismissible, +            onDismissClicked = { +                onDismissMediaData(model.token, model.uid, model.packageName, model.instanceId) +            }, +            cancelTextBackground = +                if (model.isDismissible) { +                    applicationContext.getDrawable(R.drawable.qs_media_outline_button) +                } else { +                    applicationContext.getDrawable(R.drawable.qs_media_solid_button) +                }, +            onSettingsClicked = { +                logger.logLongPressSettings(model.uid, model.packageName, model.instanceId) +                interactor.startSettings() +            }, +        ) +    } + +    private fun toActionViewModels(model: MediaControlModel): List<MediaActionViewModel?> { +        val semanticActionButtons = +            model.semanticActionButtons?.let { mediaButton -> +                with(mediaButton) { +                    val isScrubbingTimeEnabled = canShowScrubbingTimeViews(mediaButton) +                    SEMANTIC_ACTIONS_ALL.map { buttonId -> +                        getActionById(buttonId)?.let { +                            toSemanticActionViewModel(model, it, buttonId, isScrubbingTimeEnabled) +                        } +                    } +                } +            } +        val notifActionButtons = +            model.notificationActionButtons.mapIndexed { index, mediaAction -> +                toNotifActionViewModel(model, mediaAction, index) +            } +        return semanticActionButtons ?: notifActionButtons +    } + +    private fun toSemanticActionViewModel( +        model: MediaControlModel, +        mediaAction: MediaAction, +        buttonId: Int, +        isScrubbingTimeEnabled: Boolean +    ): MediaActionViewModel { +        val showInCollapsed = SEMANTIC_ACTIONS_COMPACT.contains(buttonId) +        val hideWhenScrubbing = SEMANTIC_ACTIONS_HIDE_WHEN_SCRUBBING.contains(buttonId) +        val shouldHideDueToScrubbing = isScrubbingTimeEnabled && hideWhenScrubbing +        return MediaActionViewModel( +            icon = mediaAction.icon, +            contentDescription = mediaAction.contentDescription, +            background = mediaAction.background, +            isVisible = !shouldHideDueToScrubbing, +            notVisibleValue = +                if ( +                    (buttonId == R.id.actionPrev && model.semanticActionButtons!!.reservePrev) || +                        (buttonId == R.id.actionNext && model.semanticActionButtons!!.reserveNext) +                ) { +                    ConstraintSet.INVISIBLE +                } else { +                    ConstraintSet.GONE +                }, +            showInCollapsed = showInCollapsed, +            rebindId = mediaAction.rebindId, +            buttonId = buttonId, +            isEnabled = mediaAction.action != null, +            onClicked = { id -> +                mediaAction.action?.let { +                    onButtonClicked(id, model.uid, model.packageName, model.instanceId, it) +                } +            }, +        ) +    } + +    private fun toNotifActionViewModel( +        model: MediaControlModel, +        mediaAction: MediaAction, +        index: Int +    ): MediaActionViewModel { +        return MediaActionViewModel( +            icon = mediaAction.icon, +            contentDescription = mediaAction.contentDescription, +            background = mediaAction.background, +            showInCollapsed = model.actionsToShowInCollapsed.contains(index), +            rebindId = mediaAction.rebindId, +            isEnabled = mediaAction.action != null, +            onClicked = { id -> +                mediaAction.action?.let { +                    onButtonClicked(id, model.uid, model.packageName, model.instanceId, it) +                } +            }, +        ) +    } + +    private fun onButtonClicked( +        id: Int, +        uid: Int, +        packageName: String, +        instanceId: InstanceId, +        action: Runnable +    ) { +        logger.logTapAction(id, uid, packageName, instanceId) +        // TODO (b/330897926) log smartspace card reported (SMARTSPACE_CARD_CLICK_EVENT) +        isAnyButtonClicked.value = true +        action.run() +    } + +    private fun getAppIcon( +        icon: android.graphics.drawable.Icon?, +        isResume: Boolean, +        packageName: String +    ): Icon { +        if (icon != null && !isResume) { +            icon.loadDrawable(applicationContext)?.let { drawable -> +                return Icon.Loaded(drawable, null) +            } +        } +        return getIconFromApp(packageName) +    } + +    private fun getIconFromApp(packageName: String): Icon { +        return try { +            Icon.Loaded(applicationContext.packageManager.getApplicationIcon(packageName), null) +        } catch (e: PackageManager.NameNotFoundException) { +            Log.w(TAG, "Cannot find icon for package $packageName", e) +            Icon.Resource(R.drawable.ic_music_note, null) +        } +    } + +    private fun canShowScrubbingTimeViews(semanticActions: MediaButton?): Boolean { +        // The scrubbing time views replace the SEMANTIC_ACTIONS_HIDE_WHEN_SCRUBBING action views, +        // so we should only allow scrubbing times to be shown if those action views are present. +        return semanticActions?.let { +            SEMANTIC_ACTIONS_HIDE_WHEN_SCRUBBING.stream().allMatch { id: Int -> +                semanticActions.getActionById(id) != null +            } +        } +            ?: false +    } + +    companion object { +        private const val TAG = "MediaControlViewModel" +        private const val MEDIA_PLAYER_ANIMATION_DELAY = 334L +        private const val DISABLED_ALPHA = 0.38f + +        /** Buttons to show in small player when using semantic actions */ +        private val SEMANTIC_ACTIONS_COMPACT = +            listOf(R.id.actionPlayPause, R.id.actionPrev, R.id.actionNext) + +        /** +         * Buttons that should get hidden when we are scrubbing (they will be replaced with the +         * views showing scrubbing time) +         */ +        private val SEMANTIC_ACTIONS_HIDE_WHEN_SCRUBBING = listOf(R.id.actionPrev, R.id.actionNext) + +        /** Buttons to show in player when using semantic actions. */ +        private val SEMANTIC_ACTIONS_ALL = +            listOf( +                R.id.actionPlayPause, +                R.id.actionPrev, +                R.id.actionNext, +                R.id.action0, +                R.id.action1 +            ) +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaOutputSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaOutputSwitcherViewModel.kt new file mode 100644 index 000000000000..9df9bccdf522 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaOutputSwitcherViewModel.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.controls.ui.viewmodel + +import com.android.systemui.animation.Expandable +import com.android.systemui.common.shared.model.Icon + +/** Models UI state of output switcher chip. */ +data class MediaOutputSwitcherViewModel( +    val isTapEnabled: Boolean, +    val deviceString: CharSequence, +    val deviceIcon: Icon, +    val isCurrentBroadcastApp: Boolean, +    val isIntentValid: Boolean, +    val alpha: Float, +    val isVisible: Boolean, +    val onClicked: (Expandable) -> Unit, +) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt new file mode 100644 index 000000000000..9029a65bd9ee --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaPlayerViewModel.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.controls.ui.viewmodel + +import com.android.systemui.animation.Expandable +import com.android.systemui.common.shared.model.Icon +import com.android.systemui.monet.ColorScheme + +/** Models UI state for media player. */ +data class MediaPlayerViewModel( +    val contentDescription: (Boolean) -> CharSequence, +    val backgroundCover: android.graphics.drawable.Icon?, +    val appIcon: Icon, +    val useGrayColorFilter: Boolean, +    val artistName: CharSequence, +    val titleName: CharSequence, +    val isExplicitVisible: Boolean, +    val colorScheme: ColorScheme, +    val isTimeVisible: Boolean, +    val playTurbulenceNoise: Boolean, +    val useSemanticActions: Boolean, +    val actionButtons: List<MediaActionViewModel?>, +    val outputSwitcher: MediaOutputSwitcherViewModel, +    val gutsMenu: GutsViewModel, +    val onClicked: (Expandable) -> Unit, +    val onLongClicked: () -> Unit, +) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt index 19ea00d439b2..b0375f0c939b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt @@ -16,10 +16,8 @@  package com.android.systemui.media.controls.ui.viewmodel -import android.app.WallpaperColors  import android.content.Context  import android.content.Intent -import android.content.pm.PackageManager  import android.graphics.Bitmap  import android.graphics.Color  import android.graphics.drawable.BitmapDrawable @@ -122,7 +120,9 @@ constructor(              return null          } -        val scheme = getColorScheme(model.packageName) ?: return null +        val scheme = +            MediaArtworkHelper.getColorScheme(applicationContext, model.packageName, TAG) +                ?: return null          // Capture width & height from views in foreground for artwork scaling in background          val width = @@ -304,20 +304,6 @@ constructor(          }      } -    private fun getColorScheme(packageName: String): ColorScheme? { -        // Set up recommendation card's header. -        return try { -            val packageManager = applicationContext.packageManager -            val applicationInfo = packageManager.getApplicationInfo(packageName, 0 /* flags */) -            // Set up media source app's logo. -            val icon = packageManager.getApplicationIcon(applicationInfo) -            ColorScheme(WallpaperColors.fromDrawable(icon), darkTheme = true) -        } catch (e: PackageManager.NameNotFoundException) { -            Log.w(TAG, "Fail to get media recommendation's app info", e) -            null -        } -    } -      /** Returns a [Drawable] of a given [artworkIcon] scaled to [width]x[height] size, . */      private fun getScaledRecommendationCover(          artworkIcon: Icon, diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java index 6e7e0f241dd8..da852348b4e6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSwitcherDialogUI.java @@ -18,6 +18,7 @@ package com.android.systemui.media.dialog;  import android.annotation.MainThread;  import android.content.Context; +import android.os.UserHandle;  import android.text.TextUtils;  import android.util.Log; @@ -52,8 +53,9 @@ public class MediaOutputSwitcherDialogUI implements CoreStartable, CommandQueue.      @Override      @MainThread -    public void showMediaOutputSwitcher(String packageName) { +    public void showMediaOutputSwitcher(String packageName, UserHandle userHandle) {          if (!TextUtils.isEmpty(packageName)) { +            // TODO: b/279555229 - Pass the userHandle into the output dialog manager.              mMediaOutputDialogManager.createAndShow(packageName, false, null);          } else {              Log.e(TAG, "Unable to launch media output dialog. Package name is empty."); diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt index 3e9b546d58c9..2dbe2aa4ef2d 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt @@ -18,7 +18,9 @@ package com.android.systemui.mediaprojection.appselector.data  import android.annotation.ColorInt  import android.annotation.UserIdInt +import android.app.ActivityManager.RecentTaskInfo  import android.content.ComponentName +import com.android.wm.shell.util.SplitBounds  data class RecentTask(      val taskId: Int, @@ -29,7 +31,25 @@ data class RecentTask(      @ColorInt val colorBackground: Int?,      val isForegroundTask: Boolean,      val userType: UserType, +    val splitBounds: SplitBounds?,  ) { +    constructor( +        taskInfo: RecentTaskInfo, +        isForegroundTask: Boolean, +        userType: UserType, +        splitBounds: SplitBounds? = null +    ) : this( +        taskInfo.taskId, +        taskInfo.displayId, +        taskInfo.userId, +        taskInfo.topActivity, +        taskInfo.baseIntent?.component, +        taskInfo.taskDescription?.backgroundColor, +        isForegroundTask, +        userType, +        splitBounds +    ) +      enum class UserType {          STANDARD,          WORK, diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt index a6049c8b556d..596c18f04134 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt @@ -58,20 +58,27 @@ constructor(              val foregroundTaskId1 = foregroundGroup?.taskInfo1?.taskId              val foregroundTaskId2 = foregroundGroup?.taskInfo2?.taskId              val foregroundTaskIds = listOfNotNull(foregroundTaskId1, foregroundTaskId2) -            groupedTasks -                .flatMap { listOfNotNull(it.taskInfo1, it.taskInfo2) } -                .map { +            groupedTasks.flatMap { +                val task1 =                      RecentTask( -                        it.taskId, -                        it.displayId, -                        it.userId, -                        it.topActivity, -                        it.baseIntent?.component, -                        it.taskDescription?.backgroundColor, -                        isForegroundTask = it.taskId in foregroundTaskIds && it.isVisible, -                        userType = userManager.getUserInfo(it.userId).toUserType(), +                        it.taskInfo1, +                        it.taskInfo1.taskId in foregroundTaskIds && it.taskInfo1.isVisible, +                        userManager.getUserInfo(it.taskInfo1.userId).toUserType(), +                        it.splitBounds                      ) -                } + +                val task2 = +                    if (it.taskInfo2 != null) { +                        RecentTask( +                            it.taskInfo2!!, +                            it.taskInfo2!!.taskId in foregroundTaskIds && it.taskInfo2!!.isVisible, +                            userManager.getUserInfo(it.taskInfo2!!.userId).toUserType(), +                            it.splitBounds +                        ) +                    } else null + +                listOfNotNull(task1, task2) +            }          }      private suspend fun RecentTasks.getTasks(): List<GroupedRecentTaskInfo> = diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt index 7c7efd0be8ed..9549ab1cab3e 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt @@ -24,9 +24,12 @@ import android.graphics.Rect  import android.view.LayoutInflater  import android.view.View  import android.view.ViewGroup +import android.window.RemoteTransition  import androidx.recyclerview.widget.LinearLayoutManager  import androidx.recyclerview.widget.RecyclerView  import com.android.systemui.Flags.pssAppSelectorAbruptExitFix +import com.android.systemui.Flags.pssAppSelectorRecentsSplitScreen +import com.android.systemui.display.naturalBounds  import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler  import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorScope  import com.android.systemui.mediaprojection.appselector.data.RecentTask @@ -34,6 +37,11 @@ import com.android.systemui.mediaprojection.appselector.view.RecentTasksAdapter.  import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener  import com.android.systemui.res.R  import com.android.systemui.util.recycler.HorizontalSpacerItemDecoration +import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT +import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT +import com.android.wm.shell.splitscreen.SplitScreen +import com.android.wm.shell.util.SplitBounds +import java.util.Optional  import javax.inject.Inject  /** @@ -48,6 +56,7 @@ constructor(      private val taskViewSizeProvider: TaskPreviewSizeProvider,      private val activityTaskManager: IActivityTaskManager,      private val resultHandler: MediaProjectionAppSelectorResultHandler, +    private val splitScreen: Optional<SplitScreen>,  ) : RecentTaskClickListener, TaskPreviewSizeListener {      private var views: Views? = null @@ -63,11 +72,11 @@ constructor(      fun createView(parent: ViewGroup): ViewGroup =          views?.root              ?: createRecentViews(parent) -                .also { -                    views = it -                    lastBoundData?.let { recents -> bind(recents) } -                } -                .root +                    .also { +                        views = it +                        lastBoundData?.let { recents -> bind(recents) } +                    } +                    .root      fun bind(recentTasks: List<RecentTask>) {          views?.apply { @@ -93,8 +102,10 @@ constructor(      private fun createRecentViews(parent: ViewGroup): Views {          val recentsRoot =              LayoutInflater.from(parent.context) -                .inflate(R.layout.media_projection_recent_tasks, parent, /* attachToRoot= */ false) -                as ViewGroup +                    .inflate(R.layout.media_projection_recent_tasks, +                        parent, /* attachToRoot= */ +                        false) +                    as ViewGroup          val container =              recentsRoot.requireViewById<View>(R.id.media_projection_recent_tasks_container) @@ -121,18 +132,34 @@ constructor(          return Views(recentsRoot, container, progress, recycler)      } +    private fun RecentTask.isLaunchingInSplitScreen(): Boolean { +        return splitScreen.isPresent && splitBounds != null +    } +      override fun onRecentAppClicked(task: RecentTask, view: View) {          val launchCookie = LaunchCookie()          val activityOptions = createAnimation(task, view)          activityOptions.pendingIntentBackgroundActivityStartMode =              MODE_BACKGROUND_ACTIVITY_START_ALLOWED -        activityOptions.setLaunchCookie(launchCookie)          activityOptions.launchDisplayId = task.displayId +        activityOptions.setLaunchCookie(launchCookie) + +        val handleResult: () -> Unit = { resultHandler.returnSelectedApp(launchCookie)} + +        val taskId = task.taskId +        val splitBounds = task.splitBounds -        activityTaskManager.startActivityFromRecents(task.taskId, activityOptions.toBundle()) -        resultHandler.returnSelectedApp(launchCookie) +        if (pssAppSelectorRecentsSplitScreen() && +            task.isLaunchingInSplitScreen() && +            !task.isForegroundTask) { +            startSplitScreenTask(view, taskId, splitBounds!!, handleResult, activityOptions) +        } else { +            activityTaskManager.startActivityFromRecents(taskId, activityOptions.toBundle()) +            handleResult() +        }      } +      private fun createAnimation(task: RecentTask, view: View): ActivityOptions =          if (pssAppSelectorAbruptExitFix() && task.isForegroundTask) {              // When the selected task is in the foreground, the scale up animation doesn't work. @@ -145,7 +172,14 @@ constructor(                  /* startedListener = */ null,                  /* finishedListener = */ null              ) +        } else if (task.isLaunchingInSplitScreen()) { +            // When the selected task isn't in the foreground, but is launching in split screen, +            // then we don't need to specify an animation, since we'll already be passing a +            // manually built remote animation to SplitScreenController +            ActivityOptions.makeBasic()          } else { +            // The default case is a selected task not in the foreground and launching fullscreen, +            // so for this we can use the default ActivityOptions animation              ActivityOptions.makeScaleUpAnimation(                  view,                  /* startX= */ 0, @@ -155,6 +189,29 @@ constructor(              )          } +    private fun startSplitScreenTask( +        view: View, +        taskId: Int, +        splitBounds: SplitBounds, +        handleResult: () -> Unit, +        activityOptions: ActivityOptions, +    ) { +        val isLeftTopTask = taskId == splitBounds.leftTopTaskId +        val task2Id = +            if (isLeftTopTask) splitBounds.rightBottomTaskId else splitBounds.leftTopTaskId +        val splitPosition = +            if (isLeftTopTask) SPLIT_POSITION_TOP_OR_LEFT else SPLIT_POSITION_BOTTOM_OR_RIGHT + +        val animationRunner = RemoteRecentSplitTaskTransitionRunner(taskId, task2Id, +            view.locationOnScreen, view.context.display.naturalBounds, handleResult) +        val remoteTransition = RemoteTransition(animationRunner, +            view.context.iApplicationThread, "startSplitScreenTask") + +        splitScreen.get().startTasks(taskId, activityOptions.toBundle(), task2Id, null, +            splitPosition, splitBounds.snapPosition, remoteTransition, null) +    } + +      override fun onTaskSizeChanged(size: Rect) {          views?.recentsContainer?.setTaskHeightSize()      } @@ -163,12 +220,12 @@ constructor(          val thumbnailHeight = taskViewSizeProvider.size.height()          val itemHeight =              thumbnailHeight + -                context.resources.getDimensionPixelSize( -                    R.dimen.media_projection_app_selector_task_icon_size -                ) + -                context.resources.getDimensionPixelSize( -                    R.dimen.media_projection_app_selector_task_icon_margin -                ) * 2 +                    context.resources.getDimensionPixelSize( +                        R.dimen.media_projection_app_selector_task_icon_size +                    ) + +                    context.resources.getDimensionPixelSize( +                        R.dimen.media_projection_app_selector_task_icon_margin +                    ) * 2          layoutParams = layoutParams.apply { height = itemHeight }      } diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RemoteRecentSplitTaskTransitionRunner.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RemoteRecentSplitTaskTransitionRunner.kt new file mode 100644 index 000000000000..9514c4ab8f2d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RemoteRecentSplitTaskTransitionRunner.kt @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.mediaprojection.appselector.view + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.AnimatorSet +import android.animation.ValueAnimator +import android.annotation.UiThread +import android.graphics.Rect +import android.os.IBinder +import android.os.RemoteException +import android.util.Log +import android.view.SurfaceControl +import android.view.animation.DecelerateInterpolator +import android.window.IRemoteTransition +import android.window.IRemoteTransitionFinishedCallback +import android.window.TransitionInfo +import android.window.WindowContainerToken +import com.android.app.viewcapture.ViewCapture +import com.android.internal.policy.TransitionAnimation +import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity.Companion.TAG + +class RemoteRecentSplitTaskTransitionRunner( +    private val firstTaskId: Int, +    private val secondTaskId: Int, +    private val viewPosition: IntArray, +    private val screenBounds: Rect, +    private val handleResult: () -> Unit, +) : IRemoteTransition.Stub() { +    override fun startAnimation( +        transition: IBinder?, +        info: TransitionInfo?, +        t: SurfaceControl.Transaction?, +        finishedCallback: IRemoteTransitionFinishedCallback +    ) { +        val launchAnimation = AnimatorSet() +        var rootCandidate = +            info!!.changes.firstOrNull { +                it.taskInfo?.taskId == firstTaskId || it.taskInfo?.taskId == secondTaskId +            } + +        // If we could not find a proper root candidate, something went wrong. +        check(rootCandidate != null) { "Could not find a split root candidate" } + +        // Recurse up the tree until parent is null, then we've found our root. +        var parentToken: WindowContainerToken? = rootCandidate.parent +        while (parentToken != null) { +            rootCandidate = info.getChange(parentToken) ?: break +            parentToken = rootCandidate.parent +        } + +        // Make sure nothing weird happened, like getChange() returning null. +        check(rootCandidate != null) { "Failed to find a root leash" } + +        // Ending position is the full device screen. +        val startingScale = 0.25f + +        val startX = viewPosition[0] +        val startY = viewPosition[1] +        val endX = screenBounds.left +        val endY = screenBounds.top + +        ViewCapture.MAIN_EXECUTOR.execute { +            val progressUpdater = ValueAnimator.ofFloat(0f, 1f) +            with(progressUpdater) { +                interpolator = DecelerateInterpolator(1.5f) +                setDuration(TransitionAnimation.DEFAULT_APP_TRANSITION_DURATION.toLong()) + +                addUpdateListener { valueAnimator -> +                    val progress = valueAnimator.animatedFraction + +                    val x = startX + ((endX - startX) * progress) +                    val y = startY + ((endY - startY) * progress) +                    val scale = startingScale + ((1 - startingScale) * progress) + +                    t!! +                        .setPosition(rootCandidate.leash, x, y) +                        .setScale(rootCandidate.leash, scale, scale) +                        .setAlpha(rootCandidate.leash, progress) +                        .apply() +                } + +                addListener( +                    object : AnimatorListenerAdapter() { +                        override fun onAnimationEnd(animation: Animator) { +                            try { +                                onTransitionFinished() +                                finishedCallback.onTransitionFinished(null, null) +                            } catch (e: RemoteException) { +                                Log.e(TAG, "Failed to call transition finished callback", e) +                            } +                        } +                    } +                ) +            } + +            launchAnimation.play(progressUpdater) +            launchAnimation.start() +        } +    } + +    override fun mergeAnimation( +        transition: IBinder?, +        info: TransitionInfo?, +        t: SurfaceControl.Transaction?, +        mergeTarget: IBinder?, +        finishedCallback: IRemoteTransitionFinishedCallback? +    ) {} + +    @Throws(RemoteException::class) +    override fun onTransitionConsumed(transition: IBinder, aborted: Boolean) { +        Log.w(TAG, "unexpected consumption of app selector transition: aborted=$aborted") +    } + +    @UiThread +    private fun onTransitionFinished() { +        // After finished transition, then invoke callback to close the app selector, so that +        // finish animation of app selector does not override the launch animation of the split +        // tasks +        handleResult() +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java index da9e00ddb6c2..e861ddf69aa6 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java @@ -16,8 +16,11 @@  package com.android.systemui.mediaprojection.permission; +import static android.Manifest.permission.LOG_COMPAT_CHANGE; +import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;  import static android.media.projection.IMediaProjectionManager.EXTRA_PACKAGE_REUSING_GRANTED_CONSENT;  import static android.media.projection.IMediaProjectionManager.EXTRA_USER_REVIEW_GRANTED_CONSENT; +import static android.media.projection.MediaProjectionManager.OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION;  import static android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL;  import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY;  import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; @@ -26,11 +29,13 @@ import static com.android.systemui.mediaprojection.permission.ScreenShareOptionK  import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.SINGLE_APP;  import android.annotation.Nullable; +import android.annotation.RequiresPermission;  import android.app.Activity;  import android.app.ActivityManager;  import android.app.ActivityOptions.LaunchCookie;  import android.app.AlertDialog;  import android.app.StatusBarManager; +import android.app.compat.CompatChanges;  import android.content.Context;  import android.content.DialogInterface;  import android.content.Intent; @@ -108,6 +113,7 @@ public class MediaProjectionPermissionActivity extends Activity      }      @Override +    @RequiresPermission(allOf = {READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE})      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState); @@ -235,6 +241,10 @@ public class MediaProjectionPermissionActivity extends Activity          // the correct screen width when in split screen.          Context dialogContext = getApplicationContext();          if (isPartialScreenSharingEnabled()) { +            final boolean overrideDisableSingleAppOption = +                    CompatChanges.isChangeEnabled( +                            OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION, +                            mPackageName, getHostUserHandle());              MediaProjectionPermissionDialogDelegate delegate =                      new MediaProjectionPermissionDialogDelegate(                              dialogContext, @@ -246,6 +256,7 @@ public class MediaProjectionPermissionActivity extends Activity                              },                              () -> finish(RECORD_CANCEL, /* projection= */ null),                              appName, +                            overrideDisableSingleAppOption,                              mUid,                              mMediaProjectionMetricsLogger);              mDialog = diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt index 0f54e934f3cf..8858041ae529 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt @@ -30,11 +30,12 @@ class MediaProjectionPermissionDialogDelegate(      private val onStartRecordingClicked: Consumer<MediaProjectionPermissionDialogDelegate>,      private val onCancelClicked: Runnable,      private val appName: String?, +    private val forceShowPartialScreenshare: Boolean,      hostUid: Int,      mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,  ) :      BaseMediaProjectionPermissionDialogDelegate<AlertDialog>( -        createOptionList(context, appName, mediaProjectionConfig), +        createOptionList(context, appName, mediaProjectionConfig, forceShowPartialScreenshare),          appName,          hostUid,          mediaProjectionMetricsLogger @@ -65,7 +66,8 @@ class MediaProjectionPermissionDialogDelegate(          private fun createOptionList(              context: Context,              appName: String?, -            mediaProjectionConfig: MediaProjectionConfig? +            mediaProjectionConfig: MediaProjectionConfig?, +            overrideDisableSingleAppOption: Boolean = false,          ): List<ScreenShareOption> {              val singleAppWarningText =                  if (appName == null) { @@ -80,8 +82,13 @@ class MediaProjectionPermissionDialogDelegate(                      R.string.media_projection_entry_app_permission_dialog_warning_entire_screen                  } +            // The single app option should only be disabled if there is an app name provided, +            // the client has setup a MediaProjection with +            // MediaProjectionConfig#createConfigForDefaultDisplay, AND it hasn't been overridden by +            // the OVERRIDE_DISABLE_SINGLE_APP_OPTION per-app override.              val singleAppOptionDisabled =                  appName != null && +                    !overrideDisableSingleAppOption &&                      mediaProjectionConfig?.regionToCapture ==                          MediaProjectionConfig.CAPTURE_REGION_FIXED_DISPLAY diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java index 55dc4859cf90..b8c3c1a2af5f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java @@ -29,6 +29,7 @@ import androidx.annotation.Nullable;  import com.android.internal.logging.MetricsLogger;  import com.android.internal.logging.UiEventLogger;  import com.android.systemui.dump.DumpManager; +import com.android.systemui.haptics.qs.QSLongPressEffect;  import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager;  import com.android.systemui.media.controls.ui.view.MediaHost;  import com.android.systemui.media.controls.ui.view.MediaHostState; @@ -41,13 +42,13 @@ import com.android.systemui.settings.brightness.BrightnessController;  import com.android.systemui.settings.brightness.BrightnessMirrorHandler;  import com.android.systemui.settings.brightness.BrightnessSliderController;  import com.android.systemui.settings.brightness.MirrorController; -import com.android.systemui.statusbar.VibratorHelper;  import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;  import com.android.systemui.statusbar.policy.SplitShadeStateController;  import com.android.systemui.tuner.TunerService;  import javax.inject.Inject;  import javax.inject.Named; +import javax.inject.Provider;  /**   * Controller for {@link QSPanel}. @@ -94,10 +95,10 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {              StatusBarKeyguardViewManager statusBarKeyguardViewManager,              SplitShadeStateController splitShadeStateController,              SceneContainerFlags sceneContainerFlags, -            VibratorHelper vibratorHelper) { +            Provider<QSLongPressEffect> longPRessEffectProvider) {          super(view, qsHost, qsCustomizerController, usingMediaPlayer, mediaHost,                  metricsLogger, uiEventLogger, qsLogger, dumpManager, splitShadeStateController, -                vibratorHelper); +                longPRessEffectProvider);          mTunerService = tunerService;          mQsCustomizerController = qsCustomizerController;          mQsTileRevealControllerFactory = qsTileRevealControllerFactory; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java index d8e81875bbbf..583cfb9ab47e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java @@ -17,6 +17,7 @@  package com.android.systemui.qs;  import static com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import static com.android.systemui.Flags.quickSettingsVisualHapticsLongpress;  import android.annotation.NonNull;  import android.annotation.Nullable; @@ -32,6 +33,7 @@ import com.android.internal.logging.MetricsLogger;  import com.android.internal.logging.UiEventLogger;  import com.android.systemui.Dumpable;  import com.android.systemui.dump.DumpManager; +import com.android.systemui.haptics.qs.QSLongPressEffect;  import com.android.systemui.media.controls.ui.view.MediaHost;  import com.android.systemui.plugins.qs.QSTile;  import com.android.systemui.plugins.qs.QSTileView; @@ -39,7 +41,6 @@ import com.android.systemui.qs.customize.QSCustomizerController;  import com.android.systemui.qs.external.CustomTile;  import com.android.systemui.qs.logging.QSLogger;  import com.android.systemui.qs.tileimpl.QSTileViewImpl; -import com.android.systemui.statusbar.VibratorHelper;  import com.android.systemui.statusbar.policy.SplitShadeStateController;  import com.android.systemui.util.ViewController;  import com.android.systemui.util.animation.DisappearParameters; @@ -55,6 +56,8 @@ import java.util.Objects;  import java.util.function.Consumer;  import java.util.stream.Collectors; +import javax.inject.Provider; +  /**   * Controller for QSPanel views.   * @@ -88,7 +91,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr      private SplitShadeStateController mSplitShadeStateController; -    private final VibratorHelper mVibratorHelper; +    private final Provider<QSLongPressEffect> mLongPressEffectProvider;      @VisibleForTesting      protected final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener = @@ -148,7 +151,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr              QSLogger qsLogger,              DumpManager dumpManager,              SplitShadeStateController splitShadeStateController, -            VibratorHelper vibratorHelper +            Provider<QSLongPressEffect> longPressEffectProvider      ) {          super(view);          mHost = host; @@ -162,7 +165,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr          mSplitShadeStateController = splitShadeStateController;          mShouldUseSplitNotificationShade =                  mSplitShadeStateController.shouldUseSplitNotificationShade(getResources()); -        mVibratorHelper = vibratorHelper; +        mLongPressEffectProvider = longPressEffectProvider;      }      @Override @@ -305,8 +308,14 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr      }      private void addTile(final QSTile tile, boolean collapsedView) { +        QSLongPressEffect longPressEffect; +        if (quickSettingsVisualHapticsLongpress()) { +            longPressEffect = mLongPressEffectProvider.get(); +        } else { +            longPressEffect = null; +        }          final QSTileViewImpl tileView = new QSTileViewImpl( -                getContext(), collapsedView, mVibratorHelper); +                getContext(), collapsedView, longPressEffect);          final TileRecord r = new TileRecord(tile, tileView);          // TODO(b/250618218): Remove the QSLogger in QSTileViewImpl once we know the root cause of          // b/250618218. diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java index 05bb08813cc5..6cda740dd1a8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java @@ -25,6 +25,7 @@ import androidx.annotation.VisibleForTesting;  import com.android.internal.logging.MetricsLogger;  import com.android.internal.logging.UiEventLogger;  import com.android.systemui.dump.DumpManager; +import com.android.systemui.haptics.qs.QSLongPressEffect;  import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager;  import com.android.systemui.media.controls.ui.view.MediaHost;  import com.android.systemui.plugins.qs.QSTile; @@ -32,7 +33,6 @@ import com.android.systemui.qs.customize.QSCustomizerController;  import com.android.systemui.qs.dagger.QSScope;  import com.android.systemui.qs.logging.QSLogger;  import com.android.systemui.res.R; -import com.android.systemui.statusbar.VibratorHelper;  import com.android.systemui.statusbar.policy.SplitShadeStateController;  import com.android.systemui.util.leak.RotationUtils; @@ -58,10 +58,11 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>                      Provider<Boolean> usingCollapsedLandscapeMediaProvider,              MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,              DumpManager dumpManager, SplitShadeStateController splitShadeStateController, -            VibratorHelper vibratorHelper +            Provider<QSLongPressEffect> longPressEffectProvider      ) {          super(view, qsHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger, -                uiEventLogger, qsLogger, dumpManager, splitShadeStateController, vibratorHelper); +                uiEventLogger, qsLogger, dumpManager, splitShadeStateController, +                longPressEffectProvider);          mUsingCollapsedLandscapeMediaProvider = usingCollapsedLandscapeMediaProvider;      } diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt index 267e2b7d0609..9c1b85799648 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddable.kt @@ -16,6 +16,7 @@  package com.android.systemui.qs.pipeline.domain.autoaddable +import android.view.accessibility.Flags  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.qs.ReduceBrightColorsController  import com.android.systemui.qs.dagger.QSFlagsModule.RBC_AVAILABLE @@ -58,7 +59,9 @@ constructor(      override val autoAddTracking          get() = -            if (available) { +            if (Flags.a11yQsShortcut()) { +                AutoAddTracking.Disabled +            } else if (available) {                  super.autoAddTracking              } else {                  AutoAddTracking.Disabled diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt index 30044856a7d4..ca71870845e0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt @@ -62,15 +62,15 @@ import com.android.systemui.plugins.qs.QSTileView  import com.android.systemui.qs.logging.QSLogger  import com.android.systemui.qs.tileimpl.QSIconViewImpl.QS_ANIM_LENGTH  import com.android.systemui.res.R -import com.android.systemui.statusbar.VibratorHelper  import com.android.systemui.util.children +import kotlinx.coroutines.DisposableHandle  import java.util.Objects  private const val TAG = "QSTileViewImpl"  open class QSTileViewImpl @JvmOverloads constructor(      context: Context,      private val collapsed: Boolean = false, -    private val vibratorHelper: VibratorHelper? = null, +    private val longPressEffect: QSLongPressEffect? = null,  ) : QSTileView(context), HeightOverrideable, LaunchableView {      companion object { @@ -180,15 +180,13 @@ open class QSTileViewImpl @JvmOverloads constructor(      private val locInScreen = IntArray(2)      /** Visuo-haptic long-press effects */ -    private var longPressEffect: QSLongPressEffect? = null -    private val longPressEffectViewBinder = QSLongPressEffectViewBinder()      private var initialLongPressProperties: QSLongPressProperties? = null      private var finalLongPressProperties: QSLongPressProperties? = null      private val colorEvaluator = ArgbEvaluator.getInstance() -    val hasLongPressEffect: Boolean -        get() = longPressEffect != null -    @VisibleForTesting val isLongPressEffectBound: Boolean -        get() = longPressEffectViewBinder.isBound +    val isLongPressEffectInitialized: Boolean +        get() = longPressEffect?.hasInitialized == true +    @VisibleForTesting +    var longPressEffectHandle: DisposableHandle? = null      init {          val typedValue = TypedValue() @@ -325,6 +323,13 @@ open class QSTileViewImpl @JvmOverloads constructor(      }      private fun updateHeight() { +        // TODO(b/332900989): Find a more robust way of resetting the tile if not reset by the +        //  launch animation. +        if (scaleX != 1f || scaleY != 1f) { +            // The launch animation of a long-press effect did not reset the long-press effect so +            // we must do it here +            resetLongPressEffectProperties() +        }          val actualHeight = if (heightOverride != HeightOverrideable.NO_OVERRIDE) {              heightOverride          } else { @@ -614,25 +619,26 @@ open class QSTileViewImpl @JvmOverloads constructor(          lastIconTint = icon.getColor(state)          // Long-press effects -        if (quickSettingsVisualHapticsLongpress()){ -            if (state.handlesLongClick && maybeCreateAndInitializeLongPressEffect()) { -                // set the valid long-press effect as the touch listener -                showRippleEffect = false +        if (state.handlesLongClick && +            longPressEffect?.initializeEffect(longPressEffectDuration) == true) { +            // set the valid long-press effect as the touch listener +            if (longPressEffectHandle == null) { +                longPressEffectHandle = +                    QSLongPressEffectViewBinder.bind(this, longPressEffect, state.spec)                  setOnTouchListener(longPressEffect) -                if (!longPressEffectViewBinder.isBound) { -                    longPressEffectViewBinder.bind(this, state.spec, longPressEffect) -                } -            } else { -                // Long-press effects might have been enabled before but the new state does not -                // handle a long-press. In this case, we go back to the behaviour of a regular tile -                // and clean-up the resources -                longPressEffectViewBinder.dispose() -                showRippleEffect = isClickable -                setOnTouchListener(null) -                longPressEffect = null -                initialLongPressProperties = null -                finalLongPressProperties = null              } +            showRippleEffect = false +            initializeLongPressProperties() +        } else { +            // Long-press effects might have been enabled before but the new state does not +            // handle a long-press. In this case, we go back to the behaviour of a regular tile +            // and clean-up the resources +            setOnTouchListener(null) +            longPressEffectHandle?.dispose() +            longPressEffectHandle = null +            showRippleEffect = isClickable +            initialLongPressProperties = null +            finalLongPressProperties = null          }      } @@ -824,7 +830,7 @@ open class QSTileViewImpl @JvmOverloads constructor(      private fun interpolateFloat(fraction: Float, start: Float, end: Float): Float =          start + fraction * (end - start) -    private fun resetLongPressEffectProperties() { +    fun resetLongPressEffectProperties() {          scaleY = 1f          scaleX = 1f          for (child in children) { @@ -842,27 +848,6 @@ open class QSTileViewImpl @JvmOverloads constructor(          icon.setTint(icon.mIcon as ImageView, lastIconTint)      } -    private fun maybeCreateAndInitializeLongPressEffect(): Boolean { -        // Don't setup the effect if the long-press duration is invalid -        val effectDuration = longPressEffectDuration -        if (effectDuration <= 0) { -            longPressEffect = null -            return false -        } - -        initializeLongPressProperties() -        if (longPressEffect == null) { -            longPressEffect = -                QSLongPressEffect( -                    vibratorHelper, -                    effectDuration, -                ) -        } else { -            longPressEffect?.resetWithDuration(effectDuration) -        } -        return true -    } -      private fun initializeLongPressProperties() {          initialLongPressProperties =              QSLongPressProperties( diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt index 4e0b5762b6cf..ab0b0b7b7c6c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt @@ -52,8 +52,6 @@ constructor(      val destinationScenes =          qsSceneAdapter.isCustomizing.flatMapLatest { customizing ->              if (customizing) { -                // TODO(b/332749288) Empty map so there are no back handlers and back can close -                // customizer                  flowOf(emptyMap())                  // TODO(b/330200163) Add an Up from Bottom to be able to collapse the shade                  // while customizing diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt index 32d72e0bac22..0e66c28d4b8d 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt @@ -47,6 +47,7 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor  import com.android.systemui.scene.shared.flag.SceneContainerFlags  import com.android.systemui.scene.shared.logger.SceneLogger  import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.shade.domain.interactor.ShadeInteractor  import com.android.systemui.statusbar.NotificationShadeWindowController  import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor  import com.android.systemui.statusbar.phone.CentralSurfaces @@ -61,6 +62,7 @@ import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.SharingStarted  import kotlinx.coroutines.flow.collectLatest  import kotlinx.coroutines.flow.combine  import kotlinx.coroutines.flow.distinctUntilChanged @@ -68,10 +70,12 @@ import kotlinx.coroutines.flow.distinctUntilChangedBy  import kotlinx.coroutines.flow.emptyFlow  import kotlinx.coroutines.flow.filter  import kotlinx.coroutines.flow.filterIsInstance +import kotlinx.coroutines.flow.filterNot  import kotlinx.coroutines.flow.flatMapLatest  import kotlinx.coroutines.flow.flowOf  import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.stateIn  import kotlinx.coroutines.launch  /** @@ -103,6 +107,7 @@ constructor(      private val headsUpInteractor: HeadsUpNotificationInteractor,      private val occlusionInteractor: SceneContainerOcclusionInteractor,      private val faceUnlockInteractor: DeviceEntryFaceAuthInteractor, +    private val shadeInteractor: ShadeInteractor,  ) : CoreStartable {      override fun start() { @@ -185,6 +190,14 @@ constructor(      /** Switches between scenes based on ever-changing application state. */      private fun automaticallySwitchScenes() { +        handleBouncerImeVisibility() +        handleSimUnlock() +        handleDeviceUnlockStatus() +        handlePowerState() +        handleShadeTouchability() +    } + +    private fun handleBouncerImeVisibility() {          applicationScope.launch {              // TODO (b/308001302): Move this to a bouncer specific interactor.              bouncerInteractor.onImeHiddenByUser.collectLatest { @@ -196,6 +209,9 @@ constructor(                  }              }          } +    } + +    private fun handleSimUnlock() {          applicationScope.launch {              simBouncerInteractor                  .get() @@ -229,7 +245,16 @@ constructor(                      }                  }          } +    } + +    private fun handleDeviceUnlockStatus() {          applicationScope.launch { +            // Track the previous scene (sans Bouncer), so that we know where to go when the device +            // is unlocked whilst on the bouncer. +            val previousScene = +                sceneInteractor.previousScene +                    .filterNot { it == Scenes.Bouncer } +                    .stateIn(this, SharingStarted.Eagerly, initialValue = null)              deviceUnlockedInteractor.deviceUnlockStatus                  .mapNotNull { deviceUnlockStatus ->                      val renderedScenes = @@ -257,8 +282,15 @@ constructor(                      when {                          isOnBouncer -> -                            // When the device becomes unlocked in Bouncer, go to Gone. -                            Scenes.Gone to "device was unlocked in Bouncer scene" +                            // When the device becomes unlocked in Bouncer, go to previous scene, +                            // or Gone. +                            if (previousScene.value == Scenes.Lockscreen) { +                                Scenes.Gone to "device was unlocked in Bouncer scene" +                            } else { +                                val prevScene = previousScene.value +                                (prevScene ?: Scenes.Gone) to +                                    "device was unlocked in Bouncer scene, from sceneKey=$prevScene" +                            }                          isOnLockscreen ->                              // The lockscreen should be dismissed automatically in 2 scenarios:                              // 1. When face auth bypass is enabled and authentication happens while @@ -288,7 +320,9 @@ constructor(                      )                  }          } +    } +    private fun handlePowerState() {          applicationScope.launch {              powerInteractor.isAsleep.collect { isAsleep ->                  if (isAsleep) { @@ -317,7 +351,7 @@ constructor(                      ) {                          switchToScene(                              targetSceneKey = Scenes.Bouncer, -                            loggingReason = "device is starting to wake up with a locked sim" +                            loggingReason = "device is starting to wake up with a locked sim",                          )                      }                  } @@ -325,6 +359,20 @@ constructor(          }      } +    private fun handleShadeTouchability() { +        applicationScope.launch { +            shadeInteractor.isShadeTouchable +                .distinctUntilChanged() +                .filter { !it } +                .collect { +                    switchToScene( +                        targetSceneKey = Scenes.Lockscreen, +                        loggingReason = "device became non-interactive", +                    ) +                } +        } +    } +      /** Keeps [SysUiState] up-to-date */      private fun hydrateSystemUiState() {          applicationScope.launch { diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt index c9291966bc15..cff11a753fe2 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt @@ -21,12 +21,14 @@ package com.android.systemui.scene.shared.flag  import com.android.systemui.Flags.FLAG_SCENE_CONTAINER  import com.android.systemui.Flags.sceneContainer  import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor  import com.android.systemui.flags.FlagToken  import com.android.systemui.flags.RefactorFlagUtils  import com.android.systemui.keyguard.KeyguardBottomAreaRefactor  import com.android.systemui.keyguard.KeyguardWmStateRefactor  import com.android.systemui.keyguard.MigrateClocksToBlueprint  import com.android.systemui.keyguard.shared.ComposeLockscreen +import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent  import com.android.systemui.media.controls.util.MediaInSceneContainerFlag  import com.android.systemui.statusbar.notification.shared.NotificationsHeadsUpRefactor  import com.android.systemui.statusbar.phone.PredictiveBackSysUiFlag @@ -48,7 +50,9 @@ object SceneContainerFlag {                  MediaInSceneContainerFlag.isEnabled &&                  MigrateClocksToBlueprint.isEnabled &&                  NotificationsHeadsUpRefactor.isEnabled && -                PredictiveBackSysUiFlag.isEnabled +                PredictiveBackSysUiFlag.isEnabled && +                DeviceEntryUdfpsRefactor.isEnabled && +                RefactorKeyguardDismissIntent.isEnabled      // NOTE: Changes should also be made in getSecondaryFlags and @EnableSceneContainer      /** The main aconfig flag. */ @@ -64,6 +68,8 @@ object SceneContainerFlag {              MigrateClocksToBlueprint.token,              NotificationsHeadsUpRefactor.token,              PredictiveBackSysUiFlag.token, +            DeviceEntryUdfpsRefactor.token, +            RefactorKeyguardDismissIntent.token,              // NOTE: Changes should also be made in isEnabled and @EnableSceneContainer          ) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/AssistContentRequester.java b/packages/SystemUI/src/com/android/systemui/screenshot/AssistContentRequester.java index ab8fc652c938..12bff499217e 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/AssistContentRequester.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/AssistContentRequester.java @@ -15,6 +15,7 @@   */  package com.android.systemui.screenshot; +import android.annotation.Nullable;  import android.app.ActivityTaskManager;  import android.app.IActivityTaskManager;  import android.app.IAssistDataReceiver; @@ -55,7 +56,7 @@ public class AssistContentRequester {           * Called when the {@link android.app.assist.AssistContent} of the requested task is           * available.           **/ -        void onAssistContentAvailable(AssistContent assistContent); +        void onAssistContentAvailable(@Nullable AssistContent assistContent);      }      private final IActivityTaskManager mActivityTaskManager; @@ -117,15 +118,9 @@ public class AssistContentRequester {          @Override          public void onHandleAssistData(Bundle data) { -            if (data == null) { -                return; -            } - -            final AssistContent content = data.getParcelable(ASSIST_KEY_CONTENT); -            if (content == null) { -                Log.e(TAG, "Received AssistData, but no AssistContent found"); -                return; -            } +            final AssistContent content = (data == null) ? null +                    : data.getParcelable( +                            ASSIST_KEY_CONTENT, AssistContent.class);              AssistContentRequester requester = mParentRef.get();              if (requester != null) { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ReferenceScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/ReferenceScreenshotModule.java index 6224e1bf2414..afb0280a3917 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ReferenceScreenshotModule.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ReferenceScreenshotModule.java @@ -16,6 +16,7 @@  package com.android.systemui.screenshot; +import dagger.Binds;  import dagger.Module;  import dagger.Provides; @@ -29,4 +30,9 @@ public interface ReferenceScreenshotModule {      static ScreenshotNotificationSmartActionsProvider providesScrnshtNotifSmartActionsProvider() {          return new ScreenshotNotificationSmartActionsProvider();      } + +    /** */ +    @Binds +    ScreenshotActionsProvider.Factory bindScreenshotActionsProviderFactory( +            DefaultScreenshotActionsProvider.Factory defaultScreenshotActionsProviderFactory);  } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt index 0ccb19cd9d31..07e143a34319 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt @@ -28,7 +28,6 @@ import com.android.systemui.screenshot.ActionIntentCreator.createShareWithSubjec  import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_EDIT_TAPPED  import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED  import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_SHARE_TAPPED -import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED  import com.android.systemui.screenshot.ui.viewmodel.ActionButtonAppearance  import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel  import dagger.assisted.Assisted @@ -43,7 +42,11 @@ interface ScreenshotActionsProvider {      fun onScrollChipReady(onClick: Runnable)      fun setCompletedScreenshot(result: ScreenshotSavedResult) -    fun onAssistContentAvailable(assistContent: AssistContent) {} +    /** +     * Provide the AssistContent for the focused task if available, null if the focused task isn't +     * known or didn't return data. +     */ +    fun onAssistContent(assistContent: AssistContent?) {}      interface Factory {          fun create( @@ -59,7 +62,6 @@ class DefaultScreenshotActionsProvider  constructor(      private val context: Context,      private val viewModel: ScreenshotViewModel, -    private val smartActionsProvider: SmartActionsProvider,      private val uiEventLogger: UiEventLogger,      @Assisted val request: ScreenshotData,      @Assisted val requestId: String, @@ -115,37 +117,6 @@ constructor(                  )              }          } - -        smartActionsProvider.requestQuickShare(request, requestId) { quickShare -> -            if (!quickShare.actionIntent.isImmutable) { -                viewModel.addAction( -                    ActionButtonAppearance( -                        quickShare.getIcon().loadDrawable(context), -                        quickShare.title, -                        quickShare.title -                    ) -                ) { -                    debugLog(LogConfig.DEBUG_ACTIONS) { "Quickshare tapped" } -                    onDeferrableActionTapped { result -> -                        uiEventLogger.log( -                            SCREENSHOT_SMART_ACTION_TAPPED, -                            0, -                            request.packageNameString -                        ) -                        val pendingIntentWithUri = -                            smartActionsProvider.wrapIntent( -                                quickShare, -                                result.uri, -                                result.subject, -                                requestId -                            ) -                        actionExecutor.sendPendingIntent(pendingIntentWithUri) -                    } -                } -            } else { -                Log.w(TAG, "Received immutable quick share pending intent; ignoring") -            } -        }      }      override fun onScrollChipReady(onClick: Runnable) { @@ -167,21 +138,6 @@ constructor(          }          this.result = result          pendingAction?.invoke(result) -        smartActionsProvider.requestSmartActions(request, requestId, result) { smartActions -> -            smartActions.forEach { -                smartActions.forEach { action -> -                    viewModel.addAction( -                        ActionButtonAppearance( -                            action.getIcon().loadDrawable(context), -                            action.title, -                            action.title, -                        ) -                    ) { -                        actionExecutor.sendPendingIntent(action.actionIntent) -                    } -                } -            } -        }      }      private fun onDeferrableActionTapped(onResult: (ScreenshotSavedResult) -> Unit) { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 13dd229d8f62..6871084aa938 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -176,11 +176,12 @@ public class ScreenshotController {      // These strings are used for communicating the action invoked to      // ScreenshotNotificationSmartActionsProvider. -    static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type"; -    static final String EXTRA_ID = "android:screenshot_id"; -    static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled"; -    static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent"; -    static final String EXTRA_ACTION_INTENT_FILLIN = "android:screenshot_action_intent_fillin"; +    public static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type"; +    public static final String EXTRA_ID = "android:screenshot_id"; +    public static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled"; +    public static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent"; +    public static final String EXTRA_ACTION_INTENT_FILLIN = +            "android:screenshot_action_intent_fillin";      // From WizardManagerHelper.java @@ -411,9 +412,9 @@ public class ScreenshotController {              if (screenshot.getTaskId() >= 0) {                  mAssistContentRequester.requestAssistContent(screenshot.getTaskId(), -                        assistContent -> { -                            mActionsProvider.onAssistContentAvailable(assistContent); -                        }); +                        assistContent -> mActionsProvider.onAssistContent(assistContent)); +            } else { +                mActionsProvider.onAssistContent(null);              }          } else {              saveScreenshotInWorkerThread(screenshot.getUserHandle(), finisher, diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java index 3eafbfbf37d7..23f05e0d8337 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java @@ -44,7 +44,7 @@ public class ScreenshotNotificationSmartActionsProvider {      public static final String DEFAULT_ACTION_TYPE = "Smart Action";      /* Define phases of screenshot execution. */ -    protected enum ScreenshotOp { +    public enum ScreenshotOp {          OP_UNKNOWN,          RETRIEVE_SMART_ACTIONS,          REQUEST_SMART_ACTIONS, @@ -52,7 +52,7 @@ public class ScreenshotNotificationSmartActionsProvider {      }      /* Enum to report success or failure for screenshot execution phases. */ -    protected enum ScreenshotOpStatus { +    public enum ScreenshotOpStatus {          OP_STATUS_UNKNOWN,          SUCCESS,          ERROR, diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt index 6b9332b39816..254c13367ce2 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt @@ -28,6 +28,7 @@ import android.view.ScrollCaptureResponse  import android.view.View  import android.view.ViewTreeObserver  import android.view.WindowInsets +import android.view.WindowManager  import android.window.OnBackInvokedCallback  import android.window.OnBackInvokedDispatcher  import com.android.internal.logging.UiEventLogger @@ -53,6 +54,7 @@ class ScreenshotShelfViewProxy  constructor(      private val logger: UiEventLogger,      private val viewModel: ScreenshotViewModel, +    private val windowManager: WindowManager,      @Assisted private val context: Context,      @Assisted private val displayId: Int  ) : ScreenshotViewProxy { @@ -79,6 +81,16 @@ constructor(          addPredictiveBackListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) }          setOnKeyListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) }          debugLog(DEBUG_WINDOW) { "adding OnComputeInternalInsetsListener" } +        view.viewTreeObserver.addOnComputeInternalInsetsListener { info -> +            val touchableRegion = +                view.getTouchRegion( +                    windowManager.currentWindowMetrics.windowInsets.getInsets( +                        WindowInsets.Type.systemGestures() +                    ) +                ) +            info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION) +            info.touchableRegion.set(touchableRegion) +        }          screenshotPreview = view.screenshotPreview      } @@ -194,6 +206,7 @@ constructor(              }          )      } +      private fun setOnKeyListener(onDismissRequested: (ScreenshotEvent) -> Unit) {          view.setOnKeyListener(              object : View.OnKeyListener { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsProvider.kt deleted file mode 100644 index a895b300b900..000000000000 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsProvider.kt +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.screenshot - -import android.app.Notification -import android.app.PendingIntent -import android.content.ClipData -import android.content.ClipDescription -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.graphics.Bitmap -import android.net.Uri -import android.os.Bundle -import android.os.Process -import android.os.SystemClock -import android.os.UserHandle -import android.provider.DeviceConfig -import android.util.Log -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags -import com.android.systemui.log.DebugLogger.debugLog -import com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS -import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.QUICK_SHARE_ACTION -import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType.REGULAR_SMART_ACTIONS -import java.util.concurrent.CompletableFuture -import java.util.concurrent.TimeUnit -import java.util.concurrent.TimeoutException -import javax.inject.Inject -import kotlin.random.Random - -/** - * Handle requesting smart/quickshare actions from the provider and executing an action when the - * action futures complete. - */ -class SmartActionsProvider -@Inject -constructor( -    private val context: Context, -    private val smartActions: ScreenshotNotificationSmartActionsProvider, -) { -    /** -     * Requests quick share action for a given screenshot. -     * -     * @param data the ScreenshotData request -     * @param id the request id for the screenshot -     * @param onAction callback to run when quick share action is returned -     */ -    fun requestQuickShare( -        data: ScreenshotData, -        id: String, -        onAction: (Notification.Action) -> Unit -    ) { -        val bitmap = data.bitmap ?: return -        val component = data.topComponent ?: ComponentName("", "") -        requestQuickShareAction(id, bitmap, component, data.getUserOrDefault()) { quickShare -> -            onAction(quickShare) -        } -    } - -    /** -     * Requests smart actions for a given screenshot. -     * -     * @param data the ScreenshotData request -     * @param id the request id for the screenshot -     * @param result the data for the saved image -     * @param onActions callback to run when actions are returned -     */ -    fun requestSmartActions( -        data: ScreenshotData, -        id: String, -        result: ScreenshotSavedResult, -        onActions: (List<Notification.Action>) -> Unit -    ) { -        val bitmap = data.bitmap ?: return -        val component = data.topComponent ?: ComponentName("", "") -        requestSmartActions( -            id, -            bitmap, -            component, -            data.getUserOrDefault(), -            result.uri, -            REGULAR_SMART_ACTIONS -        ) { actions -> -            onActions(actions) -        } -    } - -    /** -     * Wraps the given quick share action in a broadcast intent. -     * -     * @param quickShare the quick share action to wrap -     * @param uri the URI of the saved screenshot -     * @param subject the subject/title for the screenshot -     * @param id the request ID of the screenshot -     * @return the pending intent with correct URI -     */ -    fun wrapIntent( -        quickShare: Notification.Action, -        uri: Uri, -        subject: String, -        id: String -    ): PendingIntent { -        val wrappedIntent: Intent = -            Intent(context, SmartActionsReceiver::class.java) -                .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, quickShare.actionIntent) -                .putExtra( -                    ScreenshotController.EXTRA_ACTION_INTENT_FILLIN, -                    createFillInIntent(uri, subject) -                ) -                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND) -        val extras: Bundle = quickShare.extras -        val actionType = -            extras.getString( -                ScreenshotNotificationSmartActionsProvider.ACTION_TYPE, -                ScreenshotNotificationSmartActionsProvider.DEFAULT_ACTION_TYPE -            ) -        // We only query for quick share actions when smart actions are enabled, so we can assert -        // that it's true here. -        wrappedIntent -            .putExtra(ScreenshotController.EXTRA_ACTION_TYPE, actionType) -            .putExtra(ScreenshotController.EXTRA_ID, id) -            .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED, true) -        return PendingIntent.getBroadcast( -            context, -            Random.nextInt(), -            wrappedIntent, -            PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE -        ) -    } - -    private fun createFillInIntent(uri: Uri, subject: String): Intent { -        val fillIn = Intent() -        fillIn.setType("image/png") -        fillIn.putExtra(Intent.EXTRA_STREAM, uri) -        fillIn.putExtra(Intent.EXTRA_SUBJECT, subject) -        // Include URI in ClipData also, so that grantPermission picks it up. -        // We don't use setData here because some apps interpret this as "to:". -        val clipData = -            ClipData(ClipDescription("content", arrayOf("image/png")), ClipData.Item(uri)) -        fillIn.clipData = clipData -        fillIn.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) -        return fillIn -    } - -    private fun requestQuickShareAction( -        id: String, -        image: Bitmap, -        component: ComponentName, -        user: UserHandle, -        timeoutMs: Long = 500, -        onAction: (Notification.Action) -> Unit -    ) { -        requestSmartActions(id, image, component, user, null, QUICK_SHARE_ACTION, timeoutMs) { -            it.firstOrNull()?.let { action -> onAction(action) } -        } -    } - -    private fun requestSmartActions( -        id: String, -        image: Bitmap, -        component: ComponentName, -        user: UserHandle, -        uri: Uri?, -        actionType: ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType, -        timeoutMs: Long = 500, -        onActions: (List<Notification.Action>) -> Unit -    ) { -        val enabled = isSmartActionsEnabled(user) -        debugLog(DEBUG_ACTIONS) { -            ("getSmartActionsFuture id=$id, uri=$uri, provider=$smartActions, " + -                "actionType=$actionType, smartActionsEnabled=$enabled, userHandle=$user") -        } -        if (!enabled) { -            debugLog(DEBUG_ACTIONS) { "Screenshot Intelligence not enabled, returning empty list" } -            onActions(listOf()) -            return -        } -        if (image.config != Bitmap.Config.HARDWARE) { -            debugLog(DEBUG_ACTIONS) { -                "Bitmap expected: Hardware, Bitmap found: ${image.config}. Returning empty list." -            } -            onActions(listOf()) -            return -        } -        val smartActionsFuture: CompletableFuture<List<Notification.Action>> -        val startTimeMs = SystemClock.uptimeMillis() -        try { -            smartActionsFuture = -                smartActions.getActions(id, uri, image, component, actionType, user) -        } catch (e: Throwable) { -            val waitTimeMs = SystemClock.uptimeMillis() - startTimeMs -            debugLog(DEBUG_ACTIONS, error = e) { -                "Failed to get future for screenshot notification smart actions." -            } -            notifyScreenshotOp( -                id, -                ScreenshotNotificationSmartActionsProvider.ScreenshotOp.REQUEST_SMART_ACTIONS, -                ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.ERROR, -                waitTimeMs -            ) -            onActions(listOf()) -            return -        } -        try { -            val actions = smartActionsFuture.get(timeoutMs, TimeUnit.MILLISECONDS) -            val waitTimeMs = SystemClock.uptimeMillis() - startTimeMs -            debugLog(DEBUG_ACTIONS) { -                ("Got ${actions.size} smart actions. Wait time: $waitTimeMs ms, " + -                    "actionType=$actionType") -            } -            notifyScreenshotOp( -                id, -                ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS, -                ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.SUCCESS, -                waitTimeMs -            ) -            onActions(actions) -        } catch (e: Throwable) { -            val waitTimeMs = SystemClock.uptimeMillis() - startTimeMs -            debugLog(DEBUG_ACTIONS, error = e) { -                "Error getting smart actions. Wait time: $waitTimeMs ms, actionType=$actionType" -            } -            val status = -                if (e is TimeoutException) { -                    ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.TIMEOUT -                } else { -                    ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus.ERROR -                } -            notifyScreenshotOp( -                id, -                ScreenshotNotificationSmartActionsProvider.ScreenshotOp.WAIT_FOR_SMART_ACTIONS, -                status, -                waitTimeMs -            ) -            onActions(listOf()) -        } -    } - -    private fun notifyScreenshotOp( -        screenshotId: String, -        op: ScreenshotNotificationSmartActionsProvider.ScreenshotOp, -        status: ScreenshotNotificationSmartActionsProvider.ScreenshotOpStatus, -        durationMs: Long -    ) { -        debugLog(DEBUG_ACTIONS) { -            "$smartActions notifyOp: $op id=$screenshotId, status=$status, durationMs=$durationMs" -        } -        try { -            smartActions.notifyOp(screenshotId, op, status, durationMs) -        } catch (e: Throwable) { -            Log.e(TAG, "Error in notifyScreenshotOp: ", e) -        } -    } - -    private fun isSmartActionsEnabled(user: UserHandle): Boolean { -        // Smart actions don't yet work for cross-user saves. -        val savingToOtherUser = user !== Process.myUserHandle() -        val actionsEnabled = -            DeviceConfig.getBoolean( -                DeviceConfig.NAMESPACE_SYSTEMUI, -                SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, -                true -            ) -        return !savingToOtherUser && actionsEnabled -    } - -    companion object { -        private const val TAG = "SmartActionsProvider" -        private const val SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)" -    } -} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java index 6ff0fdaeab0f..ab23e5fdb7d9 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java @@ -22,11 +22,9 @@ import android.app.Service;  import android.view.accessibility.AccessibilityManager;  import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.screenshot.DefaultScreenshotActionsProvider;  import com.android.systemui.screenshot.ImageCapture;  import com.android.systemui.screenshot.ImageCaptureImpl;  import com.android.systemui.screenshot.LegacyScreenshotViewProxy; -import com.android.systemui.screenshot.ScreenshotActionsProvider;  import com.android.systemui.screenshot.ScreenshotPolicy;  import com.android.systemui.screenshot.ScreenshotPolicyImpl;  import com.android.systemui.screenshot.ScreenshotShelfViewProxy; @@ -90,10 +88,6 @@ public abstract class ScreenshotModule {      abstract ScreenshotSoundController bindScreenshotSoundController(              ScreenshotSoundControllerImpl screenshotSoundProviderImpl); -    @Binds -    abstract ScreenshotActionsProvider.Factory bindScreenshotActionsProviderFactory( -            DefaultScreenshotActionsProvider.Factory defaultScreenshotActionsProviderFactory); -      @Provides      @SysUISingleton      static ScreenshotViewModel providesScreenshotViewModel( diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/CapturePolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/CapturePolicy.kt index 4a88180d8f73..0fb536636f1c 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/CapturePolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/CapturePolicy.kt @@ -22,7 +22,28 @@ import com.android.systemui.screenshot.data.model.DisplayContentModel  fun interface CapturePolicy {      /**       * Test the policy against the current display task state. If the policy applies, Returns a -     * non-null [CaptureParameters] describing how the screenshot request should be augmented. +     * [PolicyResult.Matched] containing [CaptureParameters] used to alter the request.       */ -    suspend fun apply(content: DisplayContentModel): CaptureParameters? +    suspend fun check(content: DisplayContentModel): PolicyResult + +    /** The result of a screen capture policy check. */ +    sealed interface PolicyResult { +        /** The policy rules matched the given display content and will be applied. */ +        data class Matched( +            /** The name of the policy rule which matched. */ +            val policy: String, +            /** Why the policy matched. */ +            val reason: String, +            /** Details on how to modify the screen capture request. */ +            val parameters: CaptureParameters, +        ) : PolicyResult + +        /** The policy rules do not match the given display content and do not apply. */ +        data class NotMatched( +            /** The name of the policy rule which matched. */ +            val policy: String, +            /** Why the policy did not match. */ +            val reason: String +        ) : PolicyResult +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/CaptureType.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/CaptureType.kt index 6ca2e9d6d5e0..0ef5207cad37 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/CaptureType.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/CaptureType.kt @@ -21,10 +21,10 @@ import android.graphics.Rect  /** What to capture */  sealed interface CaptureType {      /** Capture the entire screen contents. */ -    class FullScreen(val displayId: Int) : CaptureType +    data class FullScreen(val displayId: Int) : CaptureType      /** Capture the contents of the task only. */ -    class IsolatedTask( +    data class IsolatedTask(          val taskId: Int,          val taskBounds: Rect?,      ) : CaptureType diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt index 2c0a0dbf8ea9..80aa0efb0a19 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PolicyRequestProcessor.kt @@ -16,9 +16,12 @@  package com.android.systemui.screenshot.policy +import android.app.ActivityTaskManager.RootTaskInfo +import android.app.WindowConfiguration  import android.content.ComponentName  import android.graphics.Bitmap  import android.graphics.Rect +import android.os.Process.myUserHandle  import android.os.UserHandle  import android.util.Log  import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN @@ -27,7 +30,10 @@ import com.android.systemui.dagger.qualifiers.Background  import com.android.systemui.screenshot.ImageCapture  import com.android.systemui.screenshot.ScreenshotData  import com.android.systemui.screenshot.ScreenshotRequestProcessor +import com.android.systemui.screenshot.data.model.DisplayContentModel  import com.android.systemui.screenshot.data.repository.DisplayContentRepository +import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.Matched +import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatched  import com.android.systemui.screenshot.policy.CaptureType.FullScreen  import com.android.systemui.screenshot.policy.CaptureType.IsolatedTask  import kotlinx.coroutines.CoroutineDispatcher @@ -39,8 +45,14 @@ private const val TAG = "PolicyRequestProcessor"  class PolicyRequestProcessor(      @Background private val background: CoroutineDispatcher,      private val capture: ImageCapture, +    /** Provides information about the tasks on a given display */      private val displayTasks: DisplayContentRepository, +    /** The list of policies to apply, in order of priority */      private val policies: List<CapturePolicy>, +    /** The owner to assign for screenshot when a focused task isn't visible */ +    private val defaultOwner: UserHandle = myUserHandle(), +    /** The assigned component when no application has focus, or not visible */ +    private val defaultComponent: ComponentName,  ) : ScreenshotRequestProcessor {      override suspend fun process(original: ScreenshotData): ScreenshotData {          if (original.type == TAKE_SCREENSHOT_PROVIDED_IMAGE) { @@ -48,29 +60,26 @@ class PolicyRequestProcessor(              Log.i(TAG, "Screenshot bitmap provided. No modifications applied.")              return original          } - -        val tasks = displayTasks.getDisplayContent(original.displayId) +        val displayContent = displayTasks.getDisplayContent(original.displayId)          // If policies yield explicit modifications, apply them and return the result          Log.i(TAG, "Applying policy checks....") -        policies -            .firstNotNullOfOrNull { policy -> policy.apply(tasks) } -            ?.let { -                Log.i(TAG, "Modifying screenshot: $it") -                return apply(it, original) +        policies.map { policy -> +            when (val result = policy.check(displayContent)) { +                is Matched -> { +                    Log.i(TAG, "$result") +                    return modify(original, result.parameters) +                } +                is NotMatched -> Log.i(TAG, "$result")              } +        }          // Otherwise capture normally, filling in additional information as needed. -        return replaceWithScreenshot( -            original = original, -            componentName = original.topComponent ?: tasks.rootTasks.firstOrNull()?.topActivity, -            owner = original.userHandle, -            displayId = original.displayId -        ) +        return captureScreenshot(original, displayContent)      }      /** Produce a new [ScreenshotData] using [CaptureParameters] */ -    suspend fun apply(updates: CaptureParameters, original: ScreenshotData): ScreenshotData { +    suspend fun modify(original: ScreenshotData, updates: CaptureParameters): ScreenshotData {          // Update and apply bitmap capture depending on the parameters.          val updated =              when (val type = updates.type) { @@ -93,6 +102,26 @@ class PolicyRequestProcessor(          return updated      } +    private suspend fun captureScreenshot( +        original: ScreenshotData, +        displayContent: DisplayContentModel, +    ): ScreenshotData { +        // The first root task on the display, excluding Picture-in-Picture +        val topMainRootTask = +            if (!displayContent.systemUiState.shadeExpanded) { +                displayContent.rootTasks.firstOrNull(::nonPipVisibleTask) +            } else { +                null // Otherwise attributed to SystemUI / current user +            } + +        return replaceWithScreenshot( +            original = original, +            componentName = topMainRootTask?.topActivity ?: defaultComponent, +            owner = topMainRootTask?.userId?.let { UserHandle.of(it) } ?: defaultOwner, +            displayId = original.displayId +        ) +    } +      suspend fun replaceWithTaskSnapshot(          original: ScreenshotData,          componentName: ComponentName?, @@ -100,6 +129,7 @@ class PolicyRequestProcessor(          taskId: Int,          taskBounds: Rect?,      ): ScreenshotData { +        Log.i(TAG, "Capturing task snapshot: $componentName / $owner")          val taskSnapshot = capture.captureTask(taskId)          return original.copy(              type = TAKE_SCREENSHOT_PROVIDED_IMAGE, @@ -117,6 +147,7 @@ class PolicyRequestProcessor(          owner: UserHandle?,          displayId: Int,      ): ScreenshotData { +        Log.i(TAG, "Capturing screenshot: $componentName / $owner")          val screenshot = captureDisplay(displayId)          return original.copy(              type = TAKE_SCREENSHOT_FULLSCREEN, @@ -127,6 +158,16 @@ class PolicyRequestProcessor(          )      } +    /** Filter for the task used to attribute a full screen capture to an owner */ +    private fun nonPipVisibleTask(info: RootTaskInfo): Boolean { +        return info.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED && +            info.isVisible && +            info.isRunning && +            info.numActivities > 0 && +            info.topActivity != null && +            info.childTaskIds.isNotEmpty() +    } +      /** TODO: Move to ImageCapture (existing function is non-suspending) */      private suspend fun captureDisplay(displayId: Int): Bitmap? {          return withContext(background) { capture.captureDisplay(displayId) } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PrivateProfilePolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PrivateProfilePolicy.kt index 221e64782894..d62ab8574799 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/PrivateProfilePolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/PrivateProfilePolicy.kt @@ -20,10 +20,11 @@ import android.os.UserHandle  import com.android.systemui.screenshot.data.model.DisplayContentModel  import com.android.systemui.screenshot.data.model.ProfileType  import com.android.systemui.screenshot.data.repository.ProfileTypeRepository +import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult +import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.Matched +import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatched  import com.android.systemui.screenshot.policy.CaptureType.FullScreen  import javax.inject.Inject -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.firstOrNull  /**   * Condition: When any visible task belongs to a private user. @@ -35,7 +36,12 @@ class PrivateProfilePolicy  constructor(      private val profileTypes: ProfileTypeRepository,  ) : CapturePolicy { -    override suspend fun apply(content: DisplayContentModel): CaptureParameters? { +    override suspend fun check(content: DisplayContentModel): PolicyResult { +        // The systemUI notification shade isn't a private profile app, skip. +        if (content.systemUiState.shadeExpanded) { +            return NotMatched(policy = NAME, reason = "Notification shade is expanded") +        } +          // Find the first visible rootTaskInfo with a child task owned by a private user          val (rootTask, childTask) =              content.rootTasks @@ -48,13 +54,20 @@ constructor(                          }                          ?.let { root to it }                  } -                ?: return null +                ?: return NotMatched(policy = NAME, reason = "No private profile tasks are visible")          // If matched, return parameters needed to modify the request. -        return CaptureParameters( -            type = FullScreen(content.displayId), -            component = childTask.componentName ?: rootTask.topActivity, -            owner = UserHandle.of(childTask.userId), +        return Matched( +            policy = NAME, +            reason = "At least one private profile task is visible", +            CaptureParameters( +                type = FullScreen(content.displayId), +                component = childTask.componentName ?: rootTask.topActivity, +                owner = UserHandle.of(childTask.userId), +            )          )      } +    companion object { +        const val NAME = "PrivateProfile" +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/RootTaskInfoExt.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/RootTaskInfoExt.kt index d2f4d9e039f6..3789371d7c33 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/RootTaskInfoExt.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/RootTaskInfoExt.kt @@ -18,12 +18,10 @@ package com.android.systemui.screenshot.policy  import android.app.ActivityTaskManager.RootTaskInfo  import com.android.systemui.screenshot.data.model.ChildTaskModel -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.asFlow -import kotlinx.coroutines.flow.map -internal fun RootTaskInfo.childTasksTopDown(): Flow<ChildTaskModel> { -    return ((numActivities - 1) downTo 0).asFlow().map { index -> +/** The child tasks of A RootTaskInfo as [ChildTaskModel] in top-down (z-index ascending) order. */ +internal fun RootTaskInfo.childTasksTopDown(): Sequence<ChildTaskModel> { +    return ((childTaskIds.size - 1) downTo 0).asSequence().map { index ->          ChildTaskModel(              childTaskIds[index],              childTaskNames[index], @@ -32,16 +30,3 @@ internal fun RootTaskInfo.childTasksTopDown(): Flow<ChildTaskModel> {          )      }  } - -internal suspend fun RootTaskInfo.firstChildTaskOrNull( -    filter: suspend (Int) -> Boolean -): Pair<RootTaskInfo, Int>? { -    // Child tasks are provided in bottom-up order -    // Filtering is done top-down, so iterate backwards here. -    for (index in numActivities - 1 downTo 0) { -        if (filter(index)) { -            return (this to index) -        } -    } -    return null -} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt index 63d15087d12c..44f767aa321e 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/ScreenshotPolicyModule.kt @@ -16,8 +16,13 @@  package com.android.systemui.screenshot.policy -import com.android.systemui.Flags.screenshotPrivateProfile +import android.content.ComponentName +import android.content.Context +import android.os.Process +import com.android.systemui.Flags.screenshotPrivateProfileBehaviorFix +import com.android.systemui.SystemUIService  import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.dagger.qualifiers.Background  import com.android.systemui.screenshot.ImageCapture  import com.android.systemui.screenshot.RequestProcessor @@ -60,18 +65,22 @@ interface ScreenshotPolicyModule {          @Provides          @SysUISingleton          fun bindScreenshotRequestProcessor( +            @Application context: Context,              @Background background: CoroutineDispatcher,              imageCapture: ImageCapture,              policyProvider: Provider<ScreenshotPolicy>,              displayContentRepoProvider: Provider<DisplayContentRepository>,              policyListProvider: Provider<List<CapturePolicy>>,          ): ScreenshotRequestProcessor { -            return if (screenshotPrivateProfile()) { +            return if (screenshotPrivateProfileBehaviorFix()) {                  PolicyRequestProcessor( -                    background, -                    imageCapture, -                    displayContentRepoProvider.get(), -                    policyListProvider.get() +                    background = background, +                    capture = imageCapture, +                    displayTasks = displayContentRepoProvider.get(), +                    policies = policyListProvider.get(), +                    defaultOwner = Process.myUserHandle(), +                    defaultComponent = +                        ComponentName(context.packageName, SystemUIService::class.java.toString())                  )              } else {                  RequestProcessor(imageCapture, policyProvider.get()) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt index d6b5d6dfda25..b781ae99a4de 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/policy/WorkProfilePolicy.kt @@ -21,6 +21,8 @@ import android.os.UserHandle  import com.android.systemui.screenshot.data.model.DisplayContentModel  import com.android.systemui.screenshot.data.model.ProfileType  import com.android.systemui.screenshot.data.repository.ProfileTypeRepository +import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult +import com.android.systemui.screenshot.policy.CapturePolicy.PolicyResult.NotMatched  import com.android.systemui.screenshot.policy.CaptureType.IsolatedTask  import javax.inject.Inject  import kotlinx.coroutines.flow.first @@ -35,7 +37,13 @@ class WorkProfilePolicy  constructor(      private val profileTypes: ProfileTypeRepository,  ) : CapturePolicy { -    override suspend fun apply(content: DisplayContentModel): CaptureParameters? { + +    override suspend fun check(content: DisplayContentModel): PolicyResult { +        // The systemUI notification shade isn't a work app, skip. +        if (content.systemUiState.shadeExpanded) { +            return NotMatched(policy = NAME, reason = "Notification shade is expanded") +        } +          // Find the first non PiP rootTask with a top child task owned by a work user          val (rootTask, childTask) =              content.rootTasks @@ -44,13 +52,24 @@ constructor(                  .firstOrNull { (_, child) ->                      profileTypes.getProfileType(child.userId) == ProfileType.WORK                  } -                ?: return null +                ?: return NotMatched( +                    policy = NAME, +                    reason = "The top-most non-PINNED task does not belong to a work profile user" +                )          // If matched, return parameters needed to modify the request. -        return CaptureParameters( -            type = IsolatedTask(taskId = childTask.id, taskBounds = childTask.bounds), -            component = childTask.componentName ?: rootTask.topActivity, -            owner = UserHandle.of(childTask.userId), +        return PolicyResult.Matched( +            policy = NAME, +            reason = "The top-most non-PINNED task ($childTask) belongs to a work profile user", +            CaptureParameters( +                type = IsolatedTask(taskId = childTask.id, taskBounds = childTask.bounds), +                component = childTask.componentName ?: rootTask.topActivity, +                owner = UserHandle.of(childTask.userId), +            )          )      } + +    companion object { +        val NAME = "WorkProfile" +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt index 747ad4f9e48c..b7a03ef42245 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt @@ -17,17 +17,70 @@  package com.android.systemui.screenshot.ui  import android.content.Context +import android.graphics.Insets +import android.graphics.Rect +import android.graphics.Region  import android.util.AttributeSet +import android.view.View  import android.widget.ImageView  import androidx.constraintlayout.widget.ConstraintLayout  import com.android.systemui.res.R +import com.android.systemui.screenshot.FloatingWindowUtil  class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) :      ConstraintLayout(context, attrs) {      lateinit var screenshotPreview: ImageView +    private val displayMetrics = context.resources.displayMetrics +    private val tmpRect = Rect() +    private lateinit var actionsContainerBackground: View +    private lateinit var dismissButton: View +      override fun onFinishInflate() {          super.onFinishInflate()          screenshotPreview = requireViewById(R.id.screenshot_preview) +        actionsContainerBackground = requireViewById(R.id.actions_container_background) +        dismissButton = requireViewById(R.id.screenshot_dismiss_button) +    } + +    fun getTouchRegion(gestureInsets: Insets): Region { +        val region = getSwipeRegion() + +        // Receive touches in gesture insets so they don't cause TOUCH_OUTSIDE +        // left edge gesture region +        val insetRect = Rect(0, 0, gestureInsets.left, displayMetrics.heightPixels) +        region.op(insetRect, Region.Op.UNION) +        // right edge gesture region +        insetRect.set( +            displayMetrics.widthPixels - gestureInsets.right, +            0, +            displayMetrics.widthPixels, +            displayMetrics.heightPixels +        ) +        region.op(insetRect, Region.Op.UNION) + +        return region +    } + +    private fun getSwipeRegion(): Region { +        val swipeRegion = Region() +        val padding = FloatingWindowUtil.dpToPx(displayMetrics, -1 * TOUCH_PADDING_DP).toInt() +        swipeRegion.addInsetView(screenshotPreview, padding) +        swipeRegion.addInsetView(actionsContainerBackground, padding) +        swipeRegion.addInsetView(dismissButton, padding) +        findViewById<View>(R.id.screenshot_message_container)?.let { +            swipeRegion.addInsetView(it, padding) +        } +        return swipeRegion +    } + +    private fun Region.addInsetView(view: View, padding: Int = 0) { +        view.getBoundsOnScreen(tmpRect) +        tmpRect.inset(padding, padding) +        this.op(tmpRect, Region.Op.UNION) +    } + +    companion object { +        private const val TOUCH_PADDING_DP = 12f      }  } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt index 32e9296107a3..5f835b3697a1 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt @@ -65,7 +65,9 @@ object ScreenshotShelfViewBinder {                      }                      launch {                          viewModel.actions.collect { actions -> -                            if (actions.isNotEmpty()) { +                            val visibleActions = actions.filter { it.visible } + +                            if (visibleActions.isNotEmpty()) {                                  view                                      .requireViewById<View>(R.id.actions_container_background)                                      .visibility = View.VISIBLE @@ -75,7 +77,7 @@ object ScreenshotShelfViewBinder {                              // any new actions and update any that are already there.                              // This assumes that actions can never change order and that each action                              // ID is unique. -                            val newIds = actions.map { it.id } +                            val newIds = visibleActions.map { it.id }                              for (view in actionsContainer.children.toList()) {                                  if (view.tag !in newIds) { @@ -83,7 +85,7 @@ object ScreenshotShelfViewBinder {                                  }                              } -                            for ((index, action) in actions.withIndex()) { +                            for ((index, action) in visibleActions.withIndex()) {                                  val currentView: View? = actionsContainer.getChildAt(index)                                  if (action.id == currentView?.tag) {                                      // Same ID, update the display @@ -93,7 +95,7 @@ object ScreenshotShelfViewBinder {                                      // mean that the new action must be inserted here.                                      val actionButton =                                          layoutInflater.inflate( -                                            R.layout.overlay_action_chip, +                                            R.layout.shelf_action_chip,                                              actionsContainer,                                              false                                          ) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt index 64b0105a98a0..c5fa8db953fa 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt @@ -19,6 +19,7 @@ package com.android.systemui.screenshot.ui.viewmodel  data class ActionButtonViewModel(      val appearance: ActionButtonAppearance,      val id: Int, +    val visible: Boolean,      val onClicked: (() -> Unit)?,  ) {      companion object { @@ -29,6 +30,6 @@ data class ActionButtonViewModel(          fun withNextId(              appearance: ActionButtonAppearance,              onClicked: (() -> Unit)? -        ): ActionButtonViewModel = ActionButtonViewModel(appearance, getId(), onClicked) +        ): ActionButtonViewModel = ActionButtonViewModel(appearance, getId(), true, onClicked)      }  } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt index fa3480343ea0..f67ad402a738 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt @@ -48,12 +48,34 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager          return action.id      } +    fun setActionVisibility(actionId: Int, visible: Boolean) { +        val actionList = _actions.value.toMutableList() +        val index = actionList.indexOfFirst { it.id == actionId } +        if (index >= 0) { +            actionList[index] = +                ActionButtonViewModel( +                    actionList[index].appearance, +                    actionId, +                    visible, +                    actionList[index].onClicked +                ) +            _actions.value = actionList +        } else { +            Log.w(TAG, "Attempted to update unknown action id $actionId") +        } +    } +      fun updateActionAppearance(actionId: Int, appearance: ActionButtonAppearance) {          val actionList = _actions.value.toMutableList()          val index = actionList.indexOfFirst { it.id == actionId }          if (index >= 0) {              actionList[index] = -                ActionButtonViewModel(appearance, actionId, actionList[index].onClicked) +                ActionButtonViewModel( +                    appearance, +                    actionId, +                    actionList[index].visible, +                    actionList[index].onClicked +                )              _actions.value = actionList          } else {              Log.w(TAG, "Attempted to update unknown action id $actionId") diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index f6b1bcc0ceea..f418e7e0278f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -23,7 +23,13 @@ import android.view.GestureDetector  import android.view.MotionEvent  import android.view.View  import android.view.ViewGroup +import androidx.activity.OnBackPressedDispatcher +import androidx.activity.OnBackPressedDispatcherOwner +import androidx.activity.setViewTreeOnBackPressedDispatcherOwner  import androidx.compose.ui.platform.ComposeView +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle  import com.android.compose.theme.PlatformTheme  import com.android.internal.annotations.VisibleForTesting  import com.android.systemui.communal.dagger.Communal @@ -33,6 +39,7 @@ import com.android.systemui.communal.ui.viewmodel.CommunalViewModel  import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor  import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.lifecycle.repeatWhenAttached  import com.android.systemui.res.R  import com.android.systemui.scene.shared.model.SceneDataSourceDelegator  import com.android.systemui.shade.domain.interactor.ShadeInteractor @@ -40,6 +47,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialogFactory  import com.android.systemui.util.kotlin.collectFlow  import javax.inject.Inject  import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.launch  /**   * Controller that's responsible for the glanceable hub container view and its touch handling. @@ -139,13 +147,33 @@ constructor(      ): View {          return initView(              ComposeView(context).apply { -                setContent { -                    PlatformTheme { -                        CommunalContainer( -                            viewModel = communalViewModel, -                            dataSourceDelegator = dataSourceDelegator, -                            dialogFactory = dialogFactory, -                        ) +                repeatWhenAttached { +                    lifecycleScope.launch { +                        repeatOnLifecycle(Lifecycle.State.CREATED) { +                            setViewTreeOnBackPressedDispatcherOwner( +                                object : OnBackPressedDispatcherOwner { +                                    override val onBackPressedDispatcher = +                                        OnBackPressedDispatcher().apply { +                                            setOnBackInvokedDispatcher( +                                                viewRootImpl.onBackInvokedDispatcher +                                            ) +                                        } + +                                    override val lifecycle: Lifecycle = +                                        this@repeatWhenAttached.lifecycle +                                } +                            ) + +                            setContent { +                                PlatformTheme { +                                    CommunalContainer( +                                        viewModel = communalViewModel, +                                        dataSourceDelegator = dataSourceDelegator, +                                        dialogFactory = dialogFactory, +                                    ) +                                } +                            } +                        }                      }                  }              } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 4660831b77af..b8512f2de0a6 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -30,6 +30,11 @@ import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;  import static com.android.systemui.classifier.Classifier.GENERIC;  import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;  import static com.android.systemui.classifier.Classifier.UNLOCK; +import static com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING; +import static com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING_LOCKSCREEN_HOSTED; +import static com.android.systemui.keyguard.shared.model.KeyguardState.GONE; +import static com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN; +import static com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED;  import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadScroll;  import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadThreeFingerSwipe;  import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED; @@ -1119,7 +1124,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump                  controller.setup(mNotificationContainerParent));          // Dreaming->Lockscreen -        collectFlow(mView, mKeyguardTransitionInteractor.getDreamingToLockscreenTransition(), +        collectFlow(mView, mKeyguardTransitionInteractor.transition(DREAMING, LOCKSCREEN),                  mDreamingToLockscreenTransition, mMainDispatcher);          collectFlow(mView, mDreamingToLockscreenTransitionViewModel.getLockscreenAlpha(),                  setDreamLockscreenTransitionAlpha(mNotificationStackScrollLayoutController), @@ -1130,7 +1135,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump          // Gone -> Dreaming hosted in lockscreen          collectFlow(mView, mKeyguardTransitionInteractor -                        .getGoneToDreamingLockscreenHostedTransition(), +                        .transition(GONE, DREAMING_LOCKSCREEN_HOSTED),                  mGoneToDreamingLockscreenHostedTransition, mMainDispatcher);          collectFlow(mView, mGoneToDreamingLockscreenHostedTransitionViewModel.getLockscreenAlpha(),                  setTransitionAlpha(mNotificationStackScrollLayoutController), @@ -1138,16 +1143,16 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump          // Lockscreen -> Dreaming hosted in lockscreen          collectFlow(mView, mKeyguardTransitionInteractor -                        .getLockscreenToDreamingLockscreenHostedTransition(), +                        .transition(LOCKSCREEN, DREAMING_LOCKSCREEN_HOSTED),                  mLockscreenToDreamingLockscreenHostedTransition, mMainDispatcher);          // Dreaming hosted in lockscreen -> Lockscreen          collectFlow(mView, mKeyguardTransitionInteractor -                        .getDreamingLockscreenHostedToLockscreenTransition(), +                        .transition(DREAMING_LOCKSCREEN_HOSTED, LOCKSCREEN),                  mDreamingLockscreenHostedToLockscreenTransition, mMainDispatcher);          // Occluded->Lockscreen -        collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(), +        collectFlow(mView, mKeyguardTransitionInteractor.transition(OCCLUDED, LOCKSCREEN),                  mOccludedToLockscreenTransition, mMainDispatcher);          if (!MigrateClocksToBlueprint.isEnabled()) {              collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(), @@ -1158,7 +1163,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump          }          // Lockscreen->Dreaming -        collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToDreamingTransition(), +        collectFlow(mView, mKeyguardTransitionInteractor.transition(LOCKSCREEN, DREAMING),                  mLockscreenToDreamingTransition, mMainDispatcher);          if (!MigrateClocksToBlueprint.isEnabled()) {              collectFlow(mView, mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha(), @@ -1170,7 +1175,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump                  setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);          // Gone->Dreaming -        collectFlow(mView, mKeyguardTransitionInteractor.getGoneToDreamingTransition(), +        collectFlow(mView, mKeyguardTransitionInteractor.transition(GONE, DREAMING),                  mGoneToDreamingTransition, mMainDispatcher);          if (!MigrateClocksToBlueprint.isEnabled()) {              collectFlow(mView, mGoneToDreamingTransitionViewModel.getLockscreenAlpha(), @@ -1181,7 +1186,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump                  setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);          // Lockscreen->Occluded -        collectFlow(mView, mKeyguardTransitionInteractor.getLockscreenToOccludedTransition(), +        collectFlow(mView, mKeyguardTransitionInteractor.transition(LOCKSCREEN, OCCLUDED),                  mLockscreenToOccludedTransition, mMainDispatcher);          if (!MigrateClocksToBlueprint.isEnabled()) {              collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(), @@ -1201,6 +1206,16 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump                                  "mPrimaryBouncerToGoneTransitionViewModel.getNotificationAlpha()");                      }, mMainDispatcher);          } + +        // Ensures that flags are updated when an activity launches +        collectFlow(mView, +                mShadeAnimationInteractor.isLaunchingActivity(), +                isLaunchingActivity -> { +                    if (isLaunchingActivity) { +                        updateSystemUiStateFlags(); +                    } +                }, +                mMainDispatcher);      }      @VisibleForTesting @@ -3632,7 +3647,8 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump                      + isFullyExpanded() + " inQs=" + mQsController.getExpanded());          }          mSysUiState -                .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE, isPanelExpanded()) +                .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE, +                        isPanelExpanded() && !isCollapsing())                  .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,                          isFullyExpanded() && !mQsController.getExpanded())                  .setFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED, diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 6ac81d226eee..00bc752c1b83 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -18,6 +18,8 @@ package com.android.systemui.shade;  import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;  import static com.android.systemui.flags.Flags.TRACKPAD_GESTURE_COMMON; +import static com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING; +import static com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN;  import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;  import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; @@ -221,7 +223,7 @@ public class NotificationShadeWindowViewController implements Dumpable {          mDisableSubpixelTextTransitionListener = new DisableSubpixelTextTransitionListener(mView);          bouncerViewBinder.bind(mView.findViewById(R.id.keyguard_bouncer_container)); -        collectFlow(mView, keyguardTransitionInteractor.getLockscreenToDreamingTransition(), +        collectFlow(mView, keyguardTransitionInteractor.transition(LOCKSCREEN, DREAMING),                  mLockscreenToDreamingTransition);          collectFlow(                  mView, @@ -382,12 +384,15 @@ public class NotificationShadeWindowViewController implements Dumpable {                      float x = ev.getRawX();                      float y = ev.getRawY();                      if (mStatusBarViewController.touchIsWithinView(x, y)) { -                        if (mStatusBarWindowStateController.windowIsShowing()) { -                            mIsTrackingBarGesture = true; -                            return logDownDispatch(ev, "sending touch to status bar", -                                    mStatusBarViewController.sendTouchToView(ev)); -                        } else { -                            return logDownDispatch(ev, "hidden or hiding", true); +                        if (!(MigrateClocksToBlueprint.isEnabled() +                                && mPrimaryBouncerInteractor.isBouncerShowing())) { +                            if (mStatusBarWindowStateController.windowIsShowing()) { +                                mIsTrackingBarGesture = true; +                                return logDownDispatch(ev, "sending touch to status bar", +                                        mStatusBarViewController.sendTouchToView(ev)); +                            } else { +                                return logDownDispatch(ev, "hidden or hiding", true); +                            }                          }                      }                  } else if (mIsTrackingBarGesture) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt index ebebbe65d54b..8c15817898a8 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt @@ -124,7 +124,6 @@ constructor(              // release focus immediately to kick off focus change transition              notificationShadeWindowController.setNotificationShadeFocusable(false)              notificationStackScrollLayout.cancelExpandHelper() -            sceneInteractor.changeScene(Scenes.Shade, "ShadeController.animateExpandShade")              if (delayed) {                  scope.launch {                      delay(125) diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt index d68e28c930f4..0b45c0834245 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt @@ -82,7 +82,7 @@ constructor(      override val isShadeTouchable: Flow<Boolean> =          combine(              powerInteractor.isAsleep, -            keyguardTransitionInteractor.isInTransitionToStateWhere { it == KeyguardState.AOD }, +            keyguardTransitionInteractor.isInTransitionToState(KeyguardState.AOD),              keyguardRepository.dozeTransitionModel.map { it.to == DozeStateModel.DOZE_PULSING },          ) { isAsleep, goingToSleep, isPulsing ->              when { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index e7b159a2d057..d955349ffede 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -50,6 +50,7 @@ import android.os.Message;  import android.os.ParcelFileDescriptor;  import android.os.Process;  import android.os.RemoteException; +import android.os.UserHandle;  import android.util.Pair;  import android.util.SparseArray;  import android.view.KeyEvent; @@ -516,7 +517,7 @@ public class CommandQueue extends IStatusBar.Stub implements          /**           * @see IStatusBar#showMediaOutputSwitcher           */ -        default void showMediaOutputSwitcher(String packageName) {} +        default void showMediaOutputSwitcher(String packageName, UserHandle userHandle) {}          /**           * @see IStatusBar#confirmImmersivePrompt @@ -1361,7 +1362,7 @@ public class CommandQueue extends IStatusBar.Stub implements          }      }      @Override -    public void showMediaOutputSwitcher(String packageName) { +    public void showMediaOutputSwitcher(String packageName, UserHandle userHandle) {          int callingUid = Binder.getCallingUid();          if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {              throw new SecurityException("Call only allowed from system server."); @@ -1369,6 +1370,7 @@ public class CommandQueue extends IStatusBar.Stub implements          synchronized (mLock) {              SomeArgs args = SomeArgs.obtain();              args.arg1 = packageName; +            args.arg2 = userHandle;              mHandler.obtainMessage(MSG_SHOW_MEDIA_OUTPUT_SWITCHER, args).sendToTarget();          }      } @@ -1939,8 +1941,10 @@ public class CommandQueue extends IStatusBar.Stub implements                  case MSG_SHOW_MEDIA_OUTPUT_SWITCHER:                      args = (SomeArgs) msg.obj;                      String clientPackageName = (String) args.arg1; +                    UserHandle clientUserHandle = (UserHandle) args.arg2;                      for (int i = 0; i < mCallbacks.size(); i++) { -                        mCallbacks.get(i).showMediaOutputSwitcher(clientPackageName); +                        mCallbacks.get(i).showMediaOutputSwitcher(clientPackageName, +                                clientUserHandle);                      }                      break;                  case MSG_CONFIRM_IMMERSIVE_PROMPT: diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 815236e0820c..09985f842185 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -195,20 +195,20 @@ public class KeyguardIndicationController {      private boolean mOrganizationOwnedDevice;      // these all assume the device is plugged in (wired/wireless/docked) AND chargingOrFull: -    private boolean mPowerPluggedIn; -    private boolean mPowerPluggedInWired; -    private boolean mPowerPluggedInWireless; -    private boolean mPowerPluggedInDock; +    protected boolean mPowerPluggedIn; +    protected boolean mPowerPluggedInWired; +    protected boolean mPowerPluggedInWireless; +    protected boolean mPowerPluggedInDock;      private boolean mPowerCharged;      private boolean mBatteryDefender;      private boolean mEnableBatteryDefender;      private boolean mIncompatibleCharger; -    private int mChargingSpeed; +    protected int mChargingSpeed;      private int mChargingWattage;      private int mBatteryLevel;      private boolean mBatteryPresent = true; -    private long mChargingTimeRemaining; +    protected long mChargingTimeRemaining;      private Pair<String, BiometricSourceType> mBiometricErrorMessageToShowOnScreenOn;      private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;      private final FaceHelpMessageDeferral mFaceAcquiredMessageDeferral; @@ -1053,20 +1053,24 @@ public class KeyguardIndicationController {       * Assumption: device is charging       */      protected String computePowerIndication() { -        int chargingId;          if (mBatteryDefender) { -            chargingId = R.string.keyguard_plugged_in_charging_limited;              String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); -            return mContext.getResources().getString(chargingId, percentage); +            return mContext.getResources().getString( +                    R.string.keyguard_plugged_in_charging_limited, percentage);          } else if (mPowerPluggedIn && mIncompatibleCharger) { -            chargingId = R.string.keyguard_plugged_in_incompatible_charger;              String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); -            return mContext.getResources().getString(chargingId, percentage); +            return mContext.getResources().getString( +                    R.string.keyguard_plugged_in_incompatible_charger, percentage);          } else if (mPowerCharged) {              return mContext.getResources().getString(R.string.keyguard_charged);          } +        return computePowerChargingStringIndication(); +    } + +    protected String computePowerChargingStringIndication() {          final boolean hasChargingTime = mChargingTimeRemaining > 0; +        int chargingId;          if (mPowerPluggedInWired) {              switch (mChargingSpeed) {                  case BatteryStatus.CHARGING_FAST: diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index bb6ee24b0ffe..f8193a4a1b93 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -57,6 +57,7 @@ import com.android.app.animation.Interpolators;  import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.statusbar.StatusBarIcon;  import com.android.internal.util.ContrastColorUtil; +import com.android.systemui.Flags;  import com.android.systemui.res.R;  import com.android.systemui.statusbar.notification.NotificationContentDescription;  import com.android.systemui.statusbar.notification.NotificationDozeHelper; @@ -208,6 +209,10 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi          initializeDecorColor();          reloadDimens();          maybeUpdateIconScaleDimens(); + +        if (Flags.statusBarMonochromeIconsFix()) { +            setCropToPadding(true); +        }      }      /** Should always be preceded by {@link #reloadDimens()} */ 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 9ce38db1aebe..8b673c951b94 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 @@ -49,7 +49,6 @@ import android.os.SystemClock;  import android.service.notification.NotificationListenerService.Ranking;  import android.service.notification.SnoozeCriterion;  import android.service.notification.StatusBarNotification; -import android.util.ArraySet;  import android.view.ContentInfo;  import androidx.annotation.NonNull; @@ -150,10 +149,8 @@ public final class NotificationEntry extends ListEntry {      private int mCachedContrastColor = COLOR_INVALID;      private int mCachedContrastColorIsFor = COLOR_INVALID;      private InflationTask mRunningTask = null; -    private Throwable mDebugThrowable;      public CharSequence remoteInputTextWhenReset;      public long lastRemoteInputSent = NOT_LAUNCHED_YET; -    public final ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);      private final MutableStateFlow<CharSequence> mHeadsUpStatusBarText =              StateFlowKt.MutableStateFlow(null); @@ -190,11 +187,6 @@ public final class NotificationEntry extends ListEntry {      private boolean mBlockable;      /** -     * The {@link SystemClock#elapsedRealtime()} when this notification entry was created. -     */ -    public long mCreationElapsedRealTime; - -    /**       * Whether this notification has ever been a non-sticky HUN.       */      private boolean mIsDemoted = false; @@ -264,13 +256,8 @@ public final class NotificationEntry extends ListEntry {          mKey = sbn.getKey();          setSbn(sbn);          setRanking(ranking); -        mCreationElapsedRealTime = SystemClock.elapsedRealtime();      } -    @VisibleForTesting -    public void setCreationElapsedRealTime(long time) { -        mCreationElapsedRealTime = time; -    }      @Override      public NotificationEntry getRepresentativeEntry() {          return this; @@ -581,19 +568,6 @@ public final class NotificationEntry extends ListEntry {          return mRunningTask;      } -    /** -     * Set a throwable that is used for debugging -     * -     * @param debugThrowable the throwable to save -     */ -    public void setDebugThrowable(Throwable debugThrowable) { -        mDebugThrowable = debugThrowable; -    } - -    public Throwable getDebugThrowable() { -        return mDebugThrowable; -    } -      public void onRemoteInputInserted() {          lastRemoteInputSent = NOT_LAUNCHED_YET;          remoteInputTextWhenReset = null; @@ -749,12 +723,6 @@ public final class NotificationEntry extends ListEntry {          return row != null && row.areChildrenExpanded();      } - -    //TODO: probably less confusing to say "is group fully visible" -    public boolean isGroupNotFullyVisible() { -        return row == null || row.isGroupNotFullyVisible(); -    } -      public NotificationGuts getGuts() {          if (row != null) return row.getGuts();          return null; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRepository.kt index ed8c05688a66..77660eb7d864 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/HeadsUpRepository.kt @@ -29,9 +29,9 @@ interface HeadsUpRepository {      /**       * True if we are exiting the headsUp pinned mode, and some notifications might still be -     * animating out. This is used to keep the touchable regions in a reasonable state. +     * animating out. This is used to keep their view container visible.       */ -    val headsUpAnimatingAway: Flow<Boolean> +    val isHeadsUpAnimatingAway: Flow<Boolean>      /** The heads up row that should be displayed on top. */      val topHeadsUpRow: Flow<HeadsUpRowRepository?> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt index d1dd7b55c11f..7f94da3c8c6a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt @@ -60,7 +60,7 @@ class HeadsUpNotificationInteractor @Inject constructor(repository: HeadsUpRepos          }      val isHeadsUpOrAnimatingAway: Flow<Boolean> = -        combine(hasPinnedRows, repository.headsUpAnimatingAway) { hasPinnedRows, animatingAway -> +        combine(hasPinnedRows, repository.isHeadsUpAnimatingAway) { hasPinnedRows, animatingAway ->              hasPinnedRows || animatingAway          } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt index c4d9ab7a47c2..9619acaed441 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt @@ -27,6 +27,7 @@ import android.database.ContentObserver  import android.hardware.display.AmbientDisplayConfiguration  import android.os.Handler  import android.os.PowerManager +import android.provider.Settings  import android.provider.Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED  import android.provider.Settings.Global.HEADS_UP_OFF  import com.android.systemui.dagger.qualifiers.Main @@ -42,6 +43,7 @@ import com.android.systemui.statusbar.notification.interruption.VisualInterrupti  import com.android.systemui.statusbar.policy.BatteryController  import com.android.systemui.statusbar.policy.HeadsUpManager  import com.android.systemui.util.settings.GlobalSettings +import com.android.systemui.util.settings.SystemSettings  import com.android.systemui.util.time.SystemClock  class PeekDisabledSuppressor( @@ -231,6 +233,7 @@ class AlertKeyguardVisibilitySuppressor(  class AvalancheSuppressor(      private val avalancheProvider: AvalancheProvider,      private val systemClock: SystemClock, +    private val systemSettings: SystemSettings,  ) :      VisualInterruptionFilter(          types = setOf(PEEK, PULSE), @@ -253,12 +256,23 @@ class AvalancheSuppressor(      }      override fun shouldSuppress(entry: NotificationEntry): Boolean { -        val timeSinceAvalanche = systemClock.currentTimeMillis() - avalancheProvider.startTime -        val isActive = timeSinceAvalanche < avalancheProvider.timeoutMs +        if (!isCooldownEnabled()) { +            reason = "FALSE avalanche cooldown setting DISABLED" +            return false +        } +        val timeSinceAvalancheMs = systemClock.currentTimeMillis() - avalancheProvider.startTime +        val timedOut = timeSinceAvalancheMs >= avalancheProvider.timeoutMs +        if (timedOut) { +            reason = "FALSE avalanche event TIMED OUT. " + +                    "${timeSinceAvalancheMs/1000} seconds since last avalanche" +            return false +        }          val state = calculateState(entry) -        val suppress = isActive && state == State.SUPPRESS -        reason = "avalanche suppress=$suppress isActive=$isActive state=$state" -        return suppress +        if (state != State.SUPPRESS) { +            reason = "FALSE avalanche IN ALLOWLIST: $state" +            return false +        } +        return true      }      private fun calculateState(entry: NotificationEntry): State { @@ -294,4 +308,11 @@ class AvalancheSuppressor(          }          return State.SUPPRESS      } + +    private fun isCooldownEnabled(): Boolean { +        return systemSettings.getInt( +            Settings.System.NOTIFICATION_COOLDOWN_ENABLED, +            /* def */ 1 +        ) == 1 +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt index 375b6e5cb6a3..e6d97c211dc5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt @@ -40,6 +40,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager  import com.android.systemui.statusbar.policy.KeyguardStateController  import com.android.systemui.util.EventLog  import com.android.systemui.util.settings.GlobalSettings +import com.android.systemui.util.settings.SystemSettings  import com.android.systemui.util.time.SystemClock  import javax.inject.Inject @@ -61,7 +62,8 @@ constructor(      private val systemClock: SystemClock,      private val uiEventLogger: UiEventLogger,      private val userTracker: UserTracker, -    private val avalancheProvider: AvalancheProvider +    private val avalancheProvider: AvalancheProvider, +    private val systemSettings: SystemSettings  ) : VisualInterruptionDecisionProvider {      init { @@ -170,7 +172,7 @@ constructor(          addFilter(AlertKeyguardVisibilitySuppressor(keyguardNotificationVisibilityProvider))          if (NotificationAvalancheSuppression.isEnabled) { -            addFilter(AvalancheSuppressor(avalancheProvider, systemClock)) +            addFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings))              avalancheProvider.register()          }          started = true diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt index d6118a0b3865..d3c874ce04d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt @@ -16,6 +16,7 @@  package com.android.systemui.statusbar.notification.row +import android.app.Flags  import android.app.Notification  import android.app.Notification.MessagingStyle  import android.app.Person @@ -131,7 +132,7 @@ internal object SingleLineViewInflater {          val senderName =              systemUiContext.resources.getString(                  R.string.conversation_single_line_name_display, -                name +                if (Flags.cleanUpSpansAndNewLines()) name?.toString() else name              )          // We need to find back-up values for those texts if they are needed and empty diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 5eaccd924344..e980794d23dd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -594,7 +594,11 @@ public class StackScrollAlgorithm {          );          if (view instanceof FooterView) {              if (FooterViewRefactor.isEnabled()) { -                if (((FooterView) view).shouldBeHidden()) { +                // TODO(b/333445519): shouldBeHidden should reflect whether the shade is closed +                //  already, so we shouldn't need to use ambientState here. However, currently it +                //  doesn't get updated quickly enough and can cause the footer to flash when +                //  closing the shade. As such, we temporarily also check the ambientState directly. +                if (((FooterView) view).shouldBeHidden() || !ambientState.isShadeExpanded()) {                      viewState.hidden = true;                  } else {                      final float footerEnd = algorithmState.mCurrentExpandedYPosition diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt index 0486ef5bca51..50996821a156 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt @@ -57,6 +57,7 @@ import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGoneTransitionView  import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.LockscreenToPrimaryBouncerTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.OccludedToAodTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.OccludedToGoneTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToLockscreenTransitionViewModel @@ -121,6 +122,7 @@ constructor(          LockscreenToPrimaryBouncerTransitionViewModel,      private val lockscreenToOccludedTransitionViewModel: LockscreenToOccludedTransitionViewModel,      private val occludedToAodTransitionViewModel: OccludedToAodTransitionViewModel, +    private val occludedToGoneTransitionViewModel: OccludedToGoneTransitionViewModel,      private val occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,      private val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,      private val primaryBouncerToLockscreenTransitionViewModel: @@ -207,9 +209,7 @@ constructor(                  keyguardTransitionInteractor.finishedKeyguardState.map {                      statesForConstrainedNotifications.contains(it)                  }, -                keyguardTransitionInteractor -                    .isInTransitionWhere { from, to -> from == LOCKSCREEN || to == LOCKSCREEN } -                    .onStart { emit(false) } +                keyguardTransitionInteractor.transitionValue(LOCKSCREEN).map { it > 0f },              ) { constrainedNotificationState, transitioningToOrFromLockscreen ->                  constrainedNotificationState || transitioningToOrFromLockscreen              } @@ -241,11 +241,10 @@ constructor(                  keyguardTransitionInteractor.finishedKeyguardState.map { state ->                      state == GLANCEABLE_HUB                  }, -                keyguardTransitionInteractor -                    .isInTransitionWhere { from, to -> -                        from == GLANCEABLE_HUB || to == GLANCEABLE_HUB -                    } -                    .onStart { emit(false) } +                or( +                    keyguardTransitionInteractor.isInTransitionToState(GLANCEABLE_HUB), +                    keyguardTransitionInteractor.isInTransitionFromState(GLANCEABLE_HUB), +                ),              ) { isOnGlanceableHub, transitioningToOrFromHub ->                  isOnGlanceableHub || transitioningToOrFromHub              } @@ -290,12 +289,10 @@ constructor(          var aodTransitionIsComplete = true          return combine(                  isOnLockscreenWithoutShade, -                keyguardTransitionInteractor -                    .isInTransitionWhere( -                        fromStatePredicate = { it == LOCKSCREEN }, -                        toStatePredicate = { it == AOD } -                    ) -                    .onStart { emit(false) }, +                keyguardTransitionInteractor.isInTransition( +                    from = LOCKSCREEN, +                    to = AOD, +                ),                  ::Pair              )              .transformWhile { (isOnLockscreenWithoutShade, aodTransitionIsRunning) -> @@ -350,7 +347,8 @@ constructor(       *       * When the shade is expanding, the position is controlled by... the shade.       */ -    val bounds: StateFlow<NotificationContainerBounds> = +    val bounds: StateFlow<NotificationContainerBounds> by lazy { +        SceneContainerFlag.assertInLegacyMode()          combine(                  isOnLockscreenWithoutShade,                  keyguardInteractor.notificationContainerBounds, @@ -380,6 +378,7 @@ constructor(                  initialValue = NotificationContainerBounds(),              )              .dumpValue("bounds") +    }      /**       * Ensure view is visible when the shade/qs are expanded. Also, as QS is expanding, fade out @@ -475,6 +474,7 @@ constructor(                  lockscreenToOccludedTransitionViewModel.lockscreenAlpha,                  lockscreenToPrimaryBouncerTransitionViewModel.lockscreenAlpha,                  occludedToAodTransitionViewModel.lockscreenAlpha, +                occludedToGoneTransitionViewModel.notificationAlpha(viewState),                  occludedToLockscreenTransitionViewModel.lockscreenAlpha,                  primaryBouncerToGoneTransitionViewModel.notificationAlpha,                  primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt index 37646aea86e2..9268d1658b80 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt @@ -14,51 +14,20 @@  package com.android.systemui.statusbar.phone -import android.app.ActivityManager -import android.app.ActivityOptions -import android.app.ActivityTaskManager  import android.app.PendingIntent -import android.app.TaskStackBuilder -import android.content.Context  import android.content.Intent  import android.os.Bundle -import android.os.RemoteException  import android.os.UserHandle -import android.provider.Settings -import android.util.Log -import android.view.RemoteAnimationAdapter  import android.view.View -import android.view.WindowManager -import com.android.keyguard.KeyguardUpdateMonitor -import com.android.systemui.ActivityIntentHelper  import com.android.systemui.animation.ActivityTransitionAnimator -import com.android.systemui.animation.ActivityTransitionAnimator.PendingIntentStarter -import com.android.systemui.animation.DelegateTransitionAnimatorController -import com.android.systemui.assist.AssistManager -import com.android.systemui.camera.CameraIntents.Companion.isInsecureCameraIntent  import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.DisplayId  import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.keyguard.KeyguardViewMediator -import com.android.systemui.keyguard.WakefulnessLifecycle  import com.android.systemui.plugins.ActivityStarter  import com.android.systemui.plugins.ActivityStarter.OnDismissAction -import com.android.systemui.res.R -import com.android.systemui.settings.UserTracker -import com.android.systemui.shade.ShadeController -import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor -import com.android.systemui.statusbar.CommandQueue -import com.android.systemui.statusbar.NotificationLockscreenUserManager -import com.android.systemui.statusbar.NotificationShadeWindowController +import com.android.systemui.scene.shared.flag.SceneContainerFlag  import com.android.systemui.statusbar.SysuiStatusBarStateController -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow -import com.android.systemui.statusbar.policy.DeviceProvisionedController -import com.android.systemui.statusbar.policy.KeyguardStateController -import com.android.systemui.statusbar.window.StatusBarWindowController  import com.android.systemui.util.concurrency.DelayableExecutor -import com.android.systemui.util.kotlin.getOrNull  import dagger.Lazy -import java.util.Optional  import javax.inject.Inject  /** Handles start activity logic in SystemUI. */ @@ -66,38 +35,18 @@ import javax.inject.Inject  class ActivityStarterImpl  @Inject  constructor( -    private val centralSurfacesOptLazy: Lazy<Optional<CentralSurfaces>>, -    private val assistManagerLazy: Lazy<AssistManager>, -    private val dozeServiceHostLazy: Lazy<DozeServiceHost>, -    private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>, -    private val keyguardViewMediatorLazy: Lazy<KeyguardViewMediator>, -    private val shadeControllerLazy: Lazy<ShadeController>, -    private val commandQueue: CommandQueue, -    private val shadeAnimationInteractor: ShadeAnimationInteractor, -    private val statusBarKeyguardViewManagerLazy: Lazy<StatusBarKeyguardViewManager>, -    private val notifShadeWindowControllerLazy: Lazy<NotificationShadeWindowController>, -    private val activityTransitionAnimator: ActivityTransitionAnimator, -    private val context: Context, -    @DisplayId private val displayId: Int, -    private val lockScreenUserManager: NotificationLockscreenUserManager, -    private val statusBarWindowController: StatusBarWindowController, -    private val wakefulnessLifecycle: WakefulnessLifecycle, -    private val keyguardStateController: KeyguardStateController,      private val statusBarStateController: SysuiStatusBarStateController, -    private val keyguardUpdateMonitor: KeyguardUpdateMonitor, -    private val deviceProvisionedController: DeviceProvisionedController, -    private val userTracker: UserTracker, -    private val activityIntentHelper: ActivityIntentHelper,      @Main private val mainExecutor: DelayableExecutor, +    legacyActivityStarter: Lazy<LegacyActivityStarterInternalImpl>, +    activityStarterInternal: Lazy<ActivityStarterInternalImpl>,  ) : ActivityStarter { -    companion object { -        const val TAG = "ActivityStarterImpl" -    } - -    private val centralSurfaces: CentralSurfaces? -        get() = centralSurfacesOptLazy.get().getOrNull() -    private val activityStarterInternal = ActivityStarterInternal() +    private val activityStarterInternal: ActivityStarterInternal = +        if (SceneContainerFlag.isEnabled) { +            activityStarterInternal.get() +        } else { +            legacyActivityStarter.get() +        }      override fun startPendingIntentDismissingKeyguard(intent: PendingIntent) {          activityStarterInternal.startPendingIntentDismissingKeyguard(intent = intent) @@ -401,575 +350,11 @@ constructor(          }      } -    private fun postOnUiThread(delay: Int = 0, runnable: Runnable) { -        mainExecutor.executeDelayed(runnable, delay.toLong()) -    } - -    /** -     * Whether we should animate an activity launch. -     * -     * Note: This method must be called *before* dismissing the keyguard. -     */ -    private fun shouldAnimateLaunch( -        isActivityIntent: Boolean, -        showOverLockscreen: Boolean, -    ): Boolean { -        // TODO(b/294418322): Support launch animations when occluded. -        if (keyguardStateController.isOccluded) { -            return false -        } - -        // Always animate if we are not showing the keyguard or if we animate over the lockscreen -        // (without unlocking it). -        if (showOverLockscreen || !keyguardStateController.isShowing) { -            return true -        } - -        // We don't animate non-activity launches as they can break the animation. -        // TODO(b/184121838): Support non activity launches on the lockscreen. -        return isActivityIntent -    } -      override fun shouldAnimateLaunch(isActivityIntent: Boolean): Boolean { -        return shouldAnimateLaunch(isActivityIntent, false) +        return activityStarterInternal.shouldAnimateLaunch(isActivityIntent)      } -    /** -     * Encapsulates the activity logic for activity starter. -     * -     * Logic is duplicated in {@link CentralSurfacesImpl} -     */ -    private inner class ActivityStarterInternal { -        /** Starts an activity after dismissing keyguard. */ -        fun startActivityDismissingKeyguard( -            intent: Intent, -            onlyProvisioned: Boolean = false, -            dismissShade: Boolean = false, -            disallowEnterPictureInPictureWhileLaunching: Boolean = false, -            callback: ActivityStarter.Callback? = null, -            flags: Int = 0, -            animationController: ActivityTransitionAnimator.Controller? = null, -            userHandle: UserHandle? = null, -            customMessage: String? = null, -        ) { -            val userHandle: UserHandle = userHandle ?: getActivityUserHandle(intent) - -            if (onlyProvisioned && !deviceProvisionedController.isDeviceProvisioned) return - -            val willLaunchResolverActivity: Boolean = -                activityIntentHelper.wouldLaunchResolverActivity( -                    intent, -                    lockScreenUserManager.currentUserId -                ) - -            val animate = -                animationController != null && -                    !willLaunchResolverActivity && -                    shouldAnimateLaunch(isActivityIntent = true) -            val animController = -                wrapAnimationControllerForShadeOrStatusBar( -                    animationController = animationController, -                    dismissShade = dismissShade, -                    isLaunchForActivity = true, -                ) - -            // If we animate, we will dismiss the shade only once the animation is done. This is -            // taken care of by the StatusBarLaunchAnimationController. -            val dismissShadeDirectly = dismissShade && animController == null - -            val runnable = Runnable { -                assistManagerLazy.get().hideAssist() -                intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP -                intent.addFlags(flags) -                val result = intArrayOf(ActivityManager.START_CANCELED) -                activityTransitionAnimator.startIntentWithAnimation( -                    animController, -                    animate, -                    intent.getPackage() -                ) { adapter: RemoteAnimationAdapter? -> -                    val options = -                        ActivityOptions(CentralSurfaces.getActivityOptions(displayId, adapter)) - -                    // We know that the intent of the caller is to dismiss the keyguard and -                    // this runnable is called right after the keyguard is solved, so we tell -                    // WM that we should dismiss it to avoid flickers when opening an activity -                    // that can also be shown over the keyguard. -                    options.setDismissKeyguardIfInsecure() -                    options.setDisallowEnterPictureInPictureWhileLaunching( -                        disallowEnterPictureInPictureWhileLaunching -                    ) -                    if (isInsecureCameraIntent(intent)) { -                        // Normally an activity will set it's requested rotation -                        // animation on its window. However when launching an activity -                        // causes the orientation to change this is too late. In these cases -                        // the default animation is used. This doesn't look good for -                        // the camera (as it rotates the camera contents out of sync -                        // with physical reality). So, we ask the WindowManager to -                        // force the cross fade animation if an orientation change -                        // happens to occur during the launch. -                        options.rotationAnimationHint = -                            WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS -                    } -                    if (Settings.Panel.ACTION_VOLUME == intent.action) { -                        // Settings Panel is implemented as activity(not a dialog), so -                        // underlying app is paused and may enter picture-in-picture mode -                        // as a result. -                        // So we need to disable picture-in-picture mode here -                        // if it is volume panel. -                        options.setDisallowEnterPictureInPictureWhileLaunching(true) -                    } -                    try { -                        result[0] = -                            ActivityTaskManager.getService() -                                .startActivityAsUser( -                                    null, -                                    context.basePackageName, -                                    context.attributionTag, -                                    intent, -                                    intent.resolveTypeIfNeeded(context.contentResolver), -                                    null, -                                    null, -                                    0, -                                    Intent.FLAG_ACTIVITY_NEW_TASK, -                                    null, -                                    options.toBundle(), -                                    userHandle.identifier, -                                ) -                    } catch (e: RemoteException) { -                        Log.w(TAG, "Unable to start activity", e) -                    } -                    result[0] -                } -                callback?.onActivityStarted(result[0]) -            } -            val cancelRunnable = Runnable { -                callback?.onActivityStarted(ActivityManager.START_CANCELED) -            } -            // Do not deferKeyguard when occluded because, when keyguard is occluded, -            // we do not launch the activity until keyguard is done. -            val occluded = (keyguardStateController.isShowing && keyguardStateController.isOccluded) -            val deferred = !occluded -            executeRunnableDismissingKeyguard( -                runnable, -                cancelRunnable, -                dismissShadeDirectly, -                willLaunchResolverActivity, -                deferred, -                animate, -                customMessage, -            ) -        } - -        /** -         * Starts a pending intent after dismissing keyguard. -         * -         * This can be called in a background thread (to prevent calls in [ActivityIntentHelper] in -         * the main thread). -         */ -        fun startPendingIntentDismissingKeyguard( -            intent: PendingIntent, -            intentSentUiThreadCallback: Runnable? = null, -            associatedView: View? = null, -            animationController: ActivityTransitionAnimator.Controller? = null, -            showOverLockscreen: Boolean = false, -            fillInIntent: Intent? = null, -            extraOptions: Bundle? = null, -        ) { -            val animationController = -                if (associatedView is ExpandableNotificationRow) { -                    centralSurfaces?.getAnimatorControllerFromNotification(associatedView) -                } else animationController - -            val willLaunchResolverActivity = -                (intent.isActivity && -                    activityIntentHelper.wouldPendingLaunchResolverActivity( -                        intent, -                        lockScreenUserManager.currentUserId, -                    )) - -            val actuallyShowOverLockscreen = -                showOverLockscreen && -                    intent.isActivity && -                    activityIntentHelper.wouldPendingShowOverLockscreen( -                        intent, -                        lockScreenUserManager.currentUserId -                    ) - -            val animate = -                !willLaunchResolverActivity && -                    animationController != null && -                    shouldAnimateLaunch(intent.isActivity, actuallyShowOverLockscreen) - -            // We wrap animationCallback with a StatusBarLaunchAnimatorController so -            // that the shade is collapsed after the animation (or when it is cancelled, -            // aborted, etc). -            val statusBarController = -                wrapAnimationControllerForShadeOrStatusBar( -                    animationController = animationController, -                    dismissShade = true, -                    isLaunchForActivity = intent.isActivity, -                ) -            val controller = -                if (actuallyShowOverLockscreen) { -                    wrapAnimationControllerForLockscreen(statusBarController) -                } else { -                    statusBarController -                } - -            // If we animate, don't collapse the shade and defer the keyguard dismiss (in case we -            // run the animation on the keyguard). The animation will take care of (instantly) -            // collapsing the shade and hiding the keyguard once it is done. -            val collapse = !animate -            val runnable = Runnable { -                try { -                    activityTransitionAnimator.startPendingIntentWithAnimation( -                        controller, -                        animate, -                        intent.creatorPackage, -                        actuallyShowOverLockscreen, -                        object : PendingIntentStarter { -                            override fun startPendingIntent( -                                animationAdapter: RemoteAnimationAdapter? -                            ): Int { -                                val options = -                                    ActivityOptions( -                                        CentralSurfaces.getActivityOptions( -                                                displayId, -                                                animationAdapter -                                            ) -                                            .apply { extraOptions?.let { putAll(it) } } -                                    ) -                                // TODO b/221255671: restrict this to only be set for -                                // notifications -                                options.isEligibleForLegacyPermissionPrompt = true -                                options.setPendingIntentBackgroundActivityStartMode( -                                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED -                                ) -                                return intent.sendAndReturnResult( -                                    context, -                                    0, -                                    fillInIntent, -                                    null, -                                    null, -                                    null, -                                    options.toBundle() -                                ) -                            } -                        }, -                    ) -                } catch (e: PendingIntent.CanceledException) { -                    // the stack trace isn't very helpful here. -                    // Just log the exception message. -                    Log.w(TAG, "Sending intent failed: $e") -                    if (!collapse) { -                        // executeRunnableDismissingKeyguard did not collapse for us already. -                        shadeControllerLazy.get().collapseOnMainThread() -                    } -                    // TODO: Dismiss Keyguard. -                } -                if (intent.isActivity) { -                    assistManagerLazy.get().hideAssist() -                    // This activity could have started while the device is dreaming, in which case -                    // the dream would occlude the activity. In order to show the newly started -                    // activity, we wake from the dream. -                    keyguardUpdateMonitor.awakenFromDream() -                } -                intentSentUiThreadCallback?.let { postOnUiThread(runnable = it) } -            } - -            if (!actuallyShowOverLockscreen) { -                postOnUiThread(delay = 0) { -                    executeRunnableDismissingKeyguard( -                        runnable = runnable, -                        afterKeyguardGone = willLaunchResolverActivity, -                        dismissShade = collapse, -                        willAnimateOnKeyguard = animate, -                    ) -                } -            } else { -                postOnUiThread(delay = 0, runnable) -            } -        } - -        /** Starts an Activity. */ -        fun startActivity( -            intent: Intent, -            dismissShade: Boolean = false, -            animationController: ActivityTransitionAnimator.Controller? = null, -            showOverLockscreenWhenLocked: Boolean = false, -            userHandle: UserHandle? = null, -        ) { -            val userHandle = userHandle ?: getActivityUserHandle(intent) -            // Make sure that we dismiss the keyguard if it is directly dismissible or when we don't -            // want to show the activity above it. -            if (keyguardStateController.isUnlocked || !showOverLockscreenWhenLocked) { -                startActivityDismissingKeyguard( -                    intent = intent, -                    onlyProvisioned = false, -                    dismissShade = dismissShade, -                    disallowEnterPictureInPictureWhileLaunching = false, -                    callback = null, -                    flags = 0, -                    animationController = animationController, -                    userHandle = userHandle, -                ) -                return -            } - -            val animate = -                animationController != null && -                    shouldAnimateLaunch( -                        /* isActivityIntent= */ true, -                        showOverLockscreenWhenLocked -                    ) == true - -            var controller: ActivityTransitionAnimator.Controller? = null -            if (animate) { -                // Wrap the animation controller to dismiss the shade and set -                // mIsLaunchingActivityOverLockscreen during the animation. -                val delegate = -                    wrapAnimationControllerForShadeOrStatusBar( -                        animationController = animationController, -                        dismissShade = dismissShade, -                        isLaunchForActivity = true, -                    ) -                controller = wrapAnimationControllerForLockscreen(delegate) -            } else if (dismissShade) { -                // The animation will take care of dismissing the shade at the end of the animation. -                // If we don't animate, collapse it directly. -                shadeControllerLazy.get().cancelExpansionAndCollapseShade() -            } - -            // We should exit the dream to prevent the activity from starting below the -            // dream. -            if (keyguardUpdateMonitor.isDreaming) { -                centralSurfaces?.awakenDreams() -            } - -            activityTransitionAnimator.startIntentWithAnimation( -                controller, -                animate, -                intent.getPackage(), -                showOverLockscreenWhenLocked -            ) { adapter: RemoteAnimationAdapter? -> -                TaskStackBuilder.create(context) -                    .addNextIntent(intent) -                    .startActivities( -                        CentralSurfaces.getActivityOptions(displayId, adapter), -                        userHandle -                    ) -            } -        } - -        /** Executes an action after dismissing keyguard. */ -        fun dismissKeyguardThenExecute( -            action: OnDismissAction, -            cancel: Runnable? = null, -            afterKeyguardGone: Boolean = false, -            customMessage: String? = null, -        ) { -            if ( -                !action.willRunAnimationOnKeyguard() && -                    wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_ASLEEP && -                    keyguardStateController.canDismissLockScreen() && -                    !statusBarStateController.leaveOpenOnKeyguardHide() && -                    dozeServiceHostLazy.get().isPulsing -            ) { -                // Reuse the biometric wake-and-unlock transition if we dismiss keyguard from a -                // pulse. -                // TODO: Factor this transition out of BiometricUnlockController. -                biometricUnlockControllerLazy -                    .get() -                    .startWakeAndUnlock(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) -            } -            if (keyguardStateController.isShowing) { -                statusBarKeyguardViewManagerLazy -                    .get() -                    .dismissWithAction(action, cancel, afterKeyguardGone, customMessage) -            } else { -                // If the keyguard isn't showing but the device is dreaming, we should exit the -                // dream. -                if (keyguardUpdateMonitor.isDreaming) { -                    centralSurfaces?.awakenDreams() -                } -                action.onDismiss() -            } -        } - -        /** Executes an action after dismissing keyguard. */ -        fun executeRunnableDismissingKeyguard( -            runnable: Runnable? = null, -            cancelAction: Runnable? = null, -            dismissShade: Boolean = false, -            afterKeyguardGone: Boolean = false, -            deferred: Boolean = false, -            willAnimateOnKeyguard: Boolean = false, -            customMessage: String? = null, -        ) { -            val onDismissAction: OnDismissAction = -                object : OnDismissAction { -                    override fun onDismiss(): Boolean { -                        if (runnable != null) { -                            if ( -                                keyguardStateController.isShowing && -                                    keyguardStateController.isOccluded -                            ) { -                                statusBarKeyguardViewManagerLazy -                                    .get() -                                    .addAfterKeyguardGoneRunnable(runnable) -                            } else { -                                mainExecutor.execute(runnable) -                            } -                        } -                        if (dismissShade) { -                            shadeControllerLazy.get().collapseShadeForActivityStart() -                        } -                        return deferred -                    } - -                    override fun willRunAnimationOnKeyguard(): Boolean { -                        return willAnimateOnKeyguard -                    } -                } -            dismissKeyguardThenExecute( -                onDismissAction, -                cancelAction, -                afterKeyguardGone, -                customMessage, -            ) -        } - -        /** -         * Return a [ActivityTransitionAnimator.Controller] wrapping `animationController` so that: -         * - if it launches in the notification shade window and `dismissShade` is true, then the -         *   shade will be instantly dismissed at the end of the animation. -         * - if it launches in status bar window, it will make the status bar window match the -         *   device size during the animation (that way, the animation won't be clipped by the -         *   status bar size). -         * -         * @param animationController the controller that is wrapped and will drive the main -         *   animation. -         * @param dismissShade whether the notification shade will be dismissed at the end of the -         *   animation. This is ignored if `animationController` is not animating in the shade -         *   window. -         * @param isLaunchForActivity whether the launch is for an activity. -         */ -        private fun wrapAnimationControllerForShadeOrStatusBar( -            animationController: ActivityTransitionAnimator.Controller?, -            dismissShade: Boolean, -            isLaunchForActivity: Boolean, -        ): ActivityTransitionAnimator.Controller? { -            if (animationController == null) { -                return null -            } -            val rootView = animationController.transitionContainer.rootView -            val controllerFromStatusBar: Optional<ActivityTransitionAnimator.Controller> = -                statusBarWindowController.wrapAnimationControllerIfInStatusBar( -                    rootView, -                    animationController -                ) -            if (controllerFromStatusBar.isPresent) { -                return controllerFromStatusBar.get() -            } - -            centralSurfaces?.let { -                // If the view is not in the status bar, then we are animating a view in the shade. -                // We have to make sure that we collapse it when the animation ends or is cancelled. -                if (dismissShade) { -                    return StatusBarTransitionAnimatorController( -                        animationController, -                        shadeAnimationInteractor, -                        shadeControllerLazy.get(), -                        notifShadeWindowControllerLazy.get(), -                        commandQueue, -                        displayId, -                        isLaunchForActivity -                    ) -                } -            } - -            return animationController -        } - -        /** -         * Wraps an animation controller so that if an activity would be launched on top of the -         * lockscreen, the correct flags are set for it to be occluded. -         */ -        private fun wrapAnimationControllerForLockscreen( -            animationController: ActivityTransitionAnimator.Controller? -        ): ActivityTransitionAnimator.Controller? { -            return animationController?.let { -                object : DelegateTransitionAnimatorController(it) { -                    override fun onIntentStarted(willAnimate: Boolean) { -                        delegate.onIntentStarted(willAnimate) -                        if (willAnimate) { -                            centralSurfaces?.setIsLaunchingActivityOverLockscreen(true) -                        } -                    } - -                    override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) { -                        super.onTransitionAnimationStart(isExpandingFullyAbove) - -                        // Double check that the keyguard is still showing and not going -                        // away, but if so set the keyguard occluded. Typically, WM will let -                        // KeyguardViewMediator know directly, but we're overriding that to -                        // play the custom launch animation, so we need to take care of that -                        // here. The unocclude animation is not overridden, so WM will call -                        // KeyguardViewMediator's unocclude animation runner when the -                        // activity is exited. -                        if ( -                            keyguardStateController.isShowing && -                                !keyguardStateController.isKeyguardGoingAway -                        ) { -                            Log.d(TAG, "Setting occluded = true in #startActivity.") -                            keyguardViewMediatorLazy -                                .get() -                                .setOccluded(true /* isOccluded */, true /* animate */) -                        } -                    } - -                    override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) { -                        // Set mIsLaunchingActivityOverLockscreen to false before actually -                        // finishing the animation so that we can assume that -                        // mIsLaunchingActivityOverLockscreen being true means that we will -                        // collapse the shade (or at least run the post collapse runnables) -                        // later on. -                        centralSurfaces?.setIsLaunchingActivityOverLockscreen(false) -                        delegate.onTransitionAnimationEnd(isExpandingFullyAbove) -                    } - -                    override fun onTransitionAnimationCancelled( -                        newKeyguardOccludedState: Boolean? -                    ) { -                        if (newKeyguardOccludedState != null) { -                            keyguardViewMediatorLazy -                                .get() -                                .setOccluded(newKeyguardOccludedState, false /* animate */) -                        } - -                        // Set mIsLaunchingActivityOverLockscreen to false before actually -                        // finishing the animation so that we can assume that -                        // mIsLaunchingActivityOverLockscreen being true means that we will -                        // collapse the shade (or at least run the // post collapse -                        // runnables) later on. -                        centralSurfaces?.setIsLaunchingActivityOverLockscreen(false) -                        delegate.onTransitionAnimationCancelled(newKeyguardOccludedState) -                    } -                } -            } -        } - -        /** Retrieves the current user handle to start the Activity. */ -        private fun getActivityUserHandle(intent: Intent): UserHandle { -            val packages: Array<String> = -                context.resources.getStringArray(R.array.system_ui_packages) -            for (pkg in packages) { -                val componentName = intent.component ?: break -                if (pkg == componentName.packageName) { -                    return UserHandle(UserHandle.myUserId()) -                } -            } -            return userTracker.userHandle -        } +    private fun postOnUiThread(delay: Int = 0, runnable: Runnable) { +        mainExecutor.executeDelayed(runnable, delay.toLong())      }  } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt new file mode 100644 index 000000000000..e8443982d560 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternal.kt @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone + +import android.app.PendingIntent +import android.content.Intent +import android.os.Bundle +import android.os.UserHandle +import android.view.View +import com.android.systemui.ActivityIntentHelper +import com.android.systemui.animation.ActivityTransitionAnimator +import com.android.systemui.plugins.ActivityStarter + +interface ActivityStarterInternal { +    /** +     * Starts a pending intent after dismissing keyguard. +     * +     * This can be called in a background thread (to prevent calls in [ActivityIntentHelper] in the +     * main thread). +     */ +    fun startPendingIntentDismissingKeyguard( +        intent: PendingIntent, +        intentSentUiThreadCallback: Runnable? = null, +        associatedView: View? = null, +        animationController: ActivityTransitionAnimator.Controller? = null, +        showOverLockscreen: Boolean = false, +        fillInIntent: Intent? = null, +        extraOptions: Bundle? = null, +    ) + +    /** Starts an activity after dismissing keyguard. */ +    fun startActivityDismissingKeyguard( +        intent: Intent, +        dismissShade: Boolean, +        onlyProvisioned: Boolean = false, +        callback: ActivityStarter.Callback? = null, +        flags: Int = 0, +        animationController: ActivityTransitionAnimator.Controller? = null, +        customMessage: String? = null, +        disallowEnterPictureInPictureWhileLaunching: Boolean = false, +        userHandle: UserHandle? = null, +    ) + +    /** Starts an Activity. */ +    fun startActivity( +        intent: Intent, +        dismissShade: Boolean, +        animationController: ActivityTransitionAnimator.Controller?, +        showOverLockscreenWhenLocked: Boolean, +        userHandle: UserHandle? = null, +    ) + +    /** Executes an action after dismissing keyguard. */ +    fun dismissKeyguardThenExecute( +        action: ActivityStarter.OnDismissAction, +        cancel: Runnable?, +        afterKeyguardGone: Boolean, +        customMessage: String? = null, +    ) + +    /** Executes an action after dismissing keyguard. */ +    fun executeRunnableDismissingKeyguard( +        runnable: Runnable?, +        cancelAction: Runnable? = null, +        dismissShade: Boolean = false, +        afterKeyguardGone: Boolean = false, +        deferred: Boolean = false, +        willAnimateOnKeyguard: Boolean = false, +        customMessage: String? = null, +    ) + +    /** Whether we should animate an activity launch. */ +    fun shouldAnimateLaunch(isActivityIntent: Boolean): Boolean +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt new file mode 100644 index 000000000000..c101755bcf38 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone + +import android.app.PendingIntent +import android.content.Intent +import android.os.Bundle +import android.os.UserHandle +import android.view.View +import com.android.systemui.animation.ActivityTransitionAnimator +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.plugins.ActivityStarter +import javax.inject.Inject + +/** + * Encapsulates the activity logic for activity starter when flexiglass is enabled. + * + * TODO: b/308819693 + */ +@SysUISingleton +class ActivityStarterInternalImpl @Inject constructor() : ActivityStarterInternal { +    override fun startPendingIntentDismissingKeyguard( +        intent: PendingIntent, +        intentSentUiThreadCallback: Runnable?, +        associatedView: View?, +        animationController: ActivityTransitionAnimator.Controller?, +        showOverLockscreen: Boolean, +        fillInIntent: Intent?, +        extraOptions: Bundle? +    ) { +        TODO("Not yet implemented b/308819693") +    } + +    override fun startActivityDismissingKeyguard( +        intent: Intent, +        dismissShade: Boolean, +        onlyProvisioned: Boolean, +        callback: ActivityStarter.Callback?, +        flags: Int, +        animationController: ActivityTransitionAnimator.Controller?, +        customMessage: String?, +        disallowEnterPictureInPictureWhileLaunching: Boolean, +        userHandle: UserHandle? +    ) { +        TODO("Not yet implemented b/308819693") +    } + +    override fun startActivity( +        intent: Intent, +        dismissShade: Boolean, +        animationController: ActivityTransitionAnimator.Controller?, +        showOverLockscreenWhenLocked: Boolean, +        userHandle: UserHandle? +    ) { +        TODO("Not yet implemented b/308819693") +    } + +    override fun dismissKeyguardThenExecute( +        action: ActivityStarter.OnDismissAction, +        cancel: Runnable?, +        afterKeyguardGone: Boolean, +        customMessage: String? +    ) { +        TODO("Not yet implemented b/308819693") +    } + +    override fun executeRunnableDismissingKeyguard( +        runnable: Runnable?, +        cancelAction: Runnable?, +        dismissShade: Boolean, +        afterKeyguardGone: Boolean, +        deferred: Boolean, +        willAnimateOnKeyguard: Boolean, +        customMessage: String? +    ) { +        TODO("Not yet implemented b/308819693") +    } + +    override fun shouldAnimateLaunch(isActivityIntent: Boolean): Boolean { +        TODO("Not yet implemented b/308819693") +    } +} 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 8b7b348ede76..79e6a0aa9c8c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -67,6 +67,8 @@ import com.android.systemui.util.time.SystemClock;  import dagger.Lazy; +import kotlinx.coroutines.ExperimentalCoroutinesApi; +  import java.io.PrintWriter;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy; @@ -77,8 +79,6 @@ import java.util.Set;  import javax.inject.Inject; -import kotlinx.coroutines.ExperimentalCoroutinesApi; -  /**   * Controller which coordinates all the biometric unlocking actions with the UI.   */ @@ -183,6 +183,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp      private final SystemClock mSystemClock;      private final boolean mOrderUnlockAndWake;      private final Lazy<SelectedUserInteractor> mSelectedUserInteractor; +    private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;      private long mLastFpFailureUptimeMillis;      private int mNumConsecutiveFpFailures; @@ -323,6 +324,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp          mOrderUnlockAndWake = resources.getBoolean(                  com.android.internal.R.bool.config_orderUnlockAndWake);          mSelectedUserInteractor = selectedUserInteractor; +        mKeyguardTransitionInteractor = keyguardTransitionInteractor;          javaAdapter.alwaysCollectFlow(                  keyguardTransitionInteractor.getStartedKeyguardTransitionStep(),                  this::consumeTransitionStepOnStartedKeyguardState); @@ -665,7 +667,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp          }          if (isKeyguardShowing) {              if ((mKeyguardViewController.primaryBouncerIsOrWillBeShowing() -                    || mKeyguardBypassController.getAltBouncerShowing()) && unlockingAllowed) { +                    || mKeyguardTransitionInteractor.getCurrentState() +                    == KeyguardState.ALTERNATE_BOUNCER) && unlockingAllowed) {                  return MODE_DISMISS_BOUNCER;              } else if (unlockingAllowed && bypass) {                  return MODE_UNLOCK_COLLAPSING; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index 3f200d578261..0ddf37db6078 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -91,7 +91,8 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements              StateFlowKt.MutableStateFlow(null);      private final MutableStateFlow<Set<HeadsUpRowRepository>> mHeadsUpNotificationRows =              StateFlowKt.MutableStateFlow(new HashSet<>()); -    private final MutableStateFlow<Boolean> mHeadsUpGoingAway = StateFlowKt.MutableStateFlow(false); +    private final MutableStateFlow<Boolean> mHeadsUpAnimatingAway = +            StateFlowKt.MutableStateFlow(false);      private boolean mReleaseOnExpandFinish;      private boolean mTrackingHeadsUp;      private final HashSet<String> mSwipedOutKeys = new HashSet<>(); @@ -184,7 +185,7 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements      //  Public methods:      /** -     * Add a listener to receive callbacks onHeadsUpGoingAway +     * Add a listener to receive callbacks {@link #setHeadsUpAnimatingAway(boolean)}       */      @Override      public void addHeadsUpPhoneListener(OnHeadsUpPhoneListenerChange listener) { @@ -264,7 +265,7 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements          if (isExpanded != mIsExpanded) {              mIsExpanded = isExpanded;              if (isExpanded) { -                mHeadsUpGoingAway.setValue(false); +                mHeadsUpAnimatingAway.setValue(false);              }          }      } @@ -274,20 +275,15 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements       * animating out. This is used to keep the touchable regions in a reasonable state.       */      @Override -    public void setHeadsUpGoingAway(boolean headsUpGoingAway) { -        if (headsUpGoingAway != mHeadsUpGoingAway.getValue()) { +    public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { +        if (headsUpAnimatingAway != mHeadsUpAnimatingAway.getValue()) {              for (OnHeadsUpPhoneListenerChange listener : mHeadsUpPhoneListeners) { -                listener.onHeadsUpGoingAwayStateChanged(headsUpGoingAway); +                listener.onHeadsUpAnimatingAwayStateChanged(headsUpAnimatingAway);              } -            mHeadsUpGoingAway.setValue(headsUpGoingAway); +            mHeadsUpAnimatingAway.setValue(headsUpAnimatingAway);          }      } -    @Override -    public boolean isHeadsUpGoingAway() { -        return mHeadsUpGoingAway.getValue(); -    } -      /**       * Notifies that a remote input textbox in notification gets active or inactive.       * @@ -504,8 +500,13 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements      @Override      @NonNull -    public Flow<Boolean> getHeadsUpAnimatingAway() { -        return mHeadsUpGoingAway; +    public Flow<Boolean> isHeadsUpAnimatingAway() { +        return mHeadsUpAnimatingAway; +    } + +    @Override +    public boolean isHeadsUpAnimatingAwayValue() { +        return mHeadsUpAnimatingAway.getValue();      }      /////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt new file mode 100644 index 000000000000..ebaeb39efe31 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone + +import android.app.ActivityManager +import android.app.ActivityOptions +import android.app.ActivityTaskManager +import android.app.PendingIntent +import android.app.TaskStackBuilder +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.os.RemoteException +import android.os.UserHandle +import android.provider.Settings +import android.util.Log +import android.view.RemoteAnimationAdapter +import android.view.View +import android.view.WindowManager +import com.android.keyguard.KeyguardUpdateMonitor +import com.android.systemui.ActivityIntentHelper +import com.android.systemui.animation.ActivityTransitionAnimator +import com.android.systemui.animation.DelegateTransitionAnimatorController +import com.android.systemui.assist.AssistManager +import com.android.systemui.camera.CameraIntents +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.DisplayId +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.keyguard.KeyguardViewMediator +import com.android.systemui.keyguard.WakefulnessLifecycle +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.res.R +import com.android.systemui.settings.UserTracker +import com.android.systemui.shade.ShadeController +import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor +import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.statusbar.NotificationLockscreenUserManager +import com.android.systemui.statusbar.NotificationShadeWindowController +import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.policy.DeviceProvisionedController +import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.statusbar.window.StatusBarWindowController +import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.kotlin.getOrNull +import dagger.Lazy +import java.util.Optional +import javax.inject.Inject + +/** Encapsulates the activity logic for activity starter. */ +@SysUISingleton +class LegacyActivityStarterInternalImpl +@Inject +constructor( +    private val centralSurfacesOptLazy: Lazy<Optional<CentralSurfaces>>, +    private val keyguardStateController: KeyguardStateController, +    private val statusBarStateController: SysuiStatusBarStateController, +    private val assistManagerLazy: Lazy<AssistManager>, +    private val dozeServiceHostLazy: Lazy<DozeServiceHost>, +    private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>, +    private val keyguardViewMediatorLazy: Lazy<KeyguardViewMediator>, +    private val shadeControllerLazy: Lazy<ShadeController>, +    private val commandQueue: CommandQueue, +    private val shadeAnimationInteractor: ShadeAnimationInteractor, +    private val statusBarKeyguardViewManagerLazy: Lazy<StatusBarKeyguardViewManager>, +    private val notifShadeWindowControllerLazy: Lazy<NotificationShadeWindowController>, +    private val activityTransitionAnimator: ActivityTransitionAnimator, +    private val context: Context, +    @DisplayId private val displayId: Int, +    private val lockScreenUserManager: NotificationLockscreenUserManager, +    private val statusBarWindowController: StatusBarWindowController, +    private val wakefulnessLifecycle: WakefulnessLifecycle, +    private val keyguardUpdateMonitor: KeyguardUpdateMonitor, +    private val deviceProvisionedController: DeviceProvisionedController, +    private val userTracker: UserTracker, +    private val activityIntentHelper: ActivityIntentHelper, +    @Main private val mainExecutor: DelayableExecutor, +) : ActivityStarterInternal { +    private val centralSurfaces: CentralSurfaces? +        get() = centralSurfacesOptLazy.get().getOrNull() + +    override fun startActivityDismissingKeyguard( +        intent: Intent, +        dismissShade: Boolean, +        onlyProvisioned: Boolean, +        callback: ActivityStarter.Callback?, +        flags: Int, +        animationController: ActivityTransitionAnimator.Controller?, +        customMessage: String?, +        disallowEnterPictureInPictureWhileLaunching: Boolean, +        userHandle: UserHandle?, +    ) { +        val userHandle: UserHandle = userHandle ?: getActivityUserHandle(intent) + +        if (onlyProvisioned && !deviceProvisionedController.isDeviceProvisioned) return + +        val willLaunchResolverActivity: Boolean = +            activityIntentHelper.wouldLaunchResolverActivity( +                intent, +                lockScreenUserManager.currentUserId +            ) + +        val animate = +            animationController != null && +                !willLaunchResolverActivity && +                shouldAnimateLaunch(isActivityIntent = true) +        val animController = +            wrapAnimationControllerForShadeOrStatusBar( +                animationController = animationController, +                dismissShade = dismissShade, +                isLaunchForActivity = true, +            ) + +        // If we animate, we will dismiss the shade only once the animation is done. This is +        // taken care of by the StatusBarLaunchAnimationController. +        val dismissShadeDirectly = dismissShade && animController == null + +        val runnable = Runnable { +            assistManagerLazy.get().hideAssist() +            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK +            intent.addFlags(flags) +            val result = intArrayOf(ActivityManager.START_CANCELED) +            activityTransitionAnimator.startIntentWithAnimation( +                animController, +                animate, +                intent.getPackage() +            ) { adapter: RemoteAnimationAdapter? -> +                val options = +                    ActivityOptions(CentralSurfaces.getActivityOptions(displayId, adapter)) + +                // We know that the intent of the caller is to dismiss the keyguard and +                // this runnable is called right after the keyguard is solved, so we tell +                // WM that we should dismiss it to avoid flickers when opening an activity +                // that can also be shown over the keyguard. +                options.setDismissKeyguardIfInsecure() +                options.setDisallowEnterPictureInPictureWhileLaunching( +                    disallowEnterPictureInPictureWhileLaunching +                ) +                if (CameraIntents.isInsecureCameraIntent(intent)) { +                    // Normally an activity will set it's requested rotation +                    // animation on its window. However when launching an activity +                    // causes the orientation to change this is too late. In these cases +                    // the default animation is used. This doesn't look good for +                    // the camera (as it rotates the camera contents out of sync +                    // with physical reality). So, we ask the WindowManager to +                    // force the cross fade animation if an orientation change +                    // happens to occur during the launch. +                    options.rotationAnimationHint = +                        WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS +                } +                if (Settings.Panel.ACTION_VOLUME == intent.action) { +                    // Settings Panel is implemented as activity(not a dialog), so +                    // underlying app is paused and may enter picture-in-picture mode +                    // as a result. +                    // So we need to disable picture-in-picture mode here +                    // if it is volume panel. +                    options.setDisallowEnterPictureInPictureWhileLaunching(true) +                } +                try { +                    result[0] = +                        ActivityTaskManager.getService() +                            .startActivityAsUser( +                                null, +                                context.basePackageName, +                                context.attributionTag, +                                intent, +                                intent.resolveTypeIfNeeded(context.contentResolver), +                                null, +                                null, +                                0, +                                Intent.FLAG_ACTIVITY_NEW_TASK, +                                null, +                                options.toBundle(), +                                userHandle.identifier, +                            ) +                } catch (e: RemoteException) { +                    Log.w(TAG, "Unable to start activity", e) +                } +                result[0] +            } +            callback?.onActivityStarted(result[0]) +        } +        val cancelRunnable = Runnable { +            callback?.onActivityStarted(ActivityManager.START_CANCELED) +        } +        // Do not deferKeyguard when occluded because, when keyguard is occluded, +        // we do not launch the activity until keyguard is done. +        val occluded = (keyguardStateController.isShowing && keyguardStateController.isOccluded) +        val deferred = !occluded +        executeRunnableDismissingKeyguard( +            runnable, +            cancelRunnable, +            dismissShadeDirectly, +            willLaunchResolverActivity, +            deferred, +            animate, +            customMessage, +        ) +    } + +    override fun startPendingIntentDismissingKeyguard( +        intent: PendingIntent, +        intentSentUiThreadCallback: Runnable?, +        associatedView: View?, +        animationController: ActivityTransitionAnimator.Controller?, +        showOverLockscreen: Boolean, +        fillInIntent: Intent?, +        extraOptions: Bundle?, +    ) { +        val animationController = +            if (associatedView is ExpandableNotificationRow) { +                centralSurfaces?.getAnimatorControllerFromNotification(associatedView) +            } else animationController + +        val willLaunchResolverActivity = +            (intent.isActivity && +                activityIntentHelper.wouldPendingLaunchResolverActivity( +                    intent, +                    lockScreenUserManager.currentUserId, +                )) + +        val actuallyShowOverLockscreen = +            showOverLockscreen && +                intent.isActivity && +                activityIntentHelper.wouldPendingShowOverLockscreen( +                    intent, +                    lockScreenUserManager.currentUserId +                ) + +        val animate = +            !willLaunchResolverActivity && +                animationController != null && +                shouldAnimateLaunch(intent.isActivity, actuallyShowOverLockscreen) + +        // We wrap animationCallback with a StatusBarLaunchAnimatorController so +        // that the shade is collapsed after the animation (or when it is cancelled, +        // aborted, etc). +        val statusBarController = +            wrapAnimationControllerForShadeOrStatusBar( +                animationController = animationController, +                dismissShade = true, +                isLaunchForActivity = intent.isActivity, +            ) +        val controller = +            if (actuallyShowOverLockscreen) { +                wrapAnimationControllerForLockscreen(statusBarController) +            } else { +                statusBarController +            } + +        // If we animate, don't collapse the shade and defer the keyguard dismiss (in case we +        // run the animation on the keyguard). The animation will take care of (instantly) +        // collapsing the shade and hiding the keyguard once it is done. +        val collapse = !animate +        val runnable = Runnable { +            try { +                activityTransitionAnimator.startPendingIntentWithAnimation( +                    controller, +                    animate, +                    intent.creatorPackage, +                    actuallyShowOverLockscreen, +                    object : ActivityTransitionAnimator.PendingIntentStarter { +                        override fun startPendingIntent( +                            animationAdapter: RemoteAnimationAdapter? +                        ): Int { +                            val options = +                                ActivityOptions( +                                    CentralSurfaces.getActivityOptions(displayId, animationAdapter) +                                        .apply { extraOptions?.let { putAll(it) } } +                                ) +                            // TODO b/221255671: restrict this to only be set for +                            // notifications +                            options.isEligibleForLegacyPermissionPrompt = true +                            options.setPendingIntentBackgroundActivityStartMode( +                                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED +                            ) +                            return intent.sendAndReturnResult( +                                context, +                                0, +                                fillInIntent, +                                null, +                                null, +                                null, +                                options.toBundle() +                            ) +                        } +                    }, +                ) +            } catch (e: PendingIntent.CanceledException) { +                // the stack trace isn't very helpful here. +                // Just log the exception message. +                Log.w(TAG, "Sending intent failed: $e") +                if (!collapse) { +                    // executeRunnableDismissingKeyguard did not collapse for us already. +                    shadeControllerLazy.get().collapseOnMainThread() +                } +                // TODO: Dismiss Keyguard. +            } +            if (intent.isActivity) { +                assistManagerLazy.get().hideAssist() +                // This activity could have started while the device is dreaming, in which case +                // the dream would occlude the activity. In order to show the newly started +                // activity, we wake from the dream. +                keyguardUpdateMonitor.awakenFromDream() +            } +            intentSentUiThreadCallback?.let { postOnUiThread(runnable = it) } +        } + +        if (!actuallyShowOverLockscreen) { +            postOnUiThread(delay = 0) { +                executeRunnableDismissingKeyguard( +                    runnable = runnable, +                    afterKeyguardGone = willLaunchResolverActivity, +                    dismissShade = collapse, +                    willAnimateOnKeyguard = animate, +                ) +            } +        } else { +            postOnUiThread(delay = 0, runnable) +        } +    } + +    override fun startActivity( +        intent: Intent, +        dismissShade: Boolean, +        animationController: ActivityTransitionAnimator.Controller?, +        showOverLockscreenWhenLocked: Boolean, +        userHandle: UserHandle?, +    ) { +        val userHandle = userHandle ?: getActivityUserHandle(intent) +        // Make sure that we dismiss the keyguard if it is directly dismissible or when we don't +        // want to show the activity above it. +        if (keyguardStateController.isUnlocked || !showOverLockscreenWhenLocked) { +            startActivityDismissingKeyguard( +                intent = intent, +                onlyProvisioned = false, +                dismissShade = dismissShade, +                disallowEnterPictureInPictureWhileLaunching = false, +                callback = null, +                flags = 0, +                animationController = animationController, +                userHandle = userHandle, +            ) +            return +        } + +        val animate = +            animationController != null && +                shouldAnimateLaunch(/* isActivityIntent= */ true, showOverLockscreenWhenLocked) + +        var controller: ActivityTransitionAnimator.Controller? = null +        if (animate) { +            // Wrap the animation controller to dismiss the shade and set +            // mIsLaunchingActivityOverLockscreen during the animation. +            val delegate = +                wrapAnimationControllerForShadeOrStatusBar( +                    animationController = animationController, +                    dismissShade = dismissShade, +                    isLaunchForActivity = true, +                ) +            controller = wrapAnimationControllerForLockscreen(delegate) +        } else if (dismissShade) { +            // The animation will take care of dismissing the shade at the end of the animation. +            // If we don't animate, collapse it directly. +            shadeControllerLazy.get().cancelExpansionAndCollapseShade() +        } + +        // We should exit the dream to prevent the activity from starting below the +        // dream. +        if (keyguardUpdateMonitor.isDreaming) { +            centralSurfaces?.awakenDreams() +        } + +        activityTransitionAnimator.startIntentWithAnimation( +            controller, +            animate, +            intent.getPackage(), +            showOverLockscreenWhenLocked +        ) { adapter: RemoteAnimationAdapter? -> +            TaskStackBuilder.create(context) +                .addNextIntent(intent) +                .startActivities(CentralSurfaces.getActivityOptions(displayId, adapter), userHandle) +        } +    } + +    override fun dismissKeyguardThenExecute( +        action: ActivityStarter.OnDismissAction, +        cancel: Runnable?, +        afterKeyguardGone: Boolean, +        customMessage: String?, +    ) { +        if ( +            !action.willRunAnimationOnKeyguard() && +                wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_ASLEEP && +                keyguardStateController.canDismissLockScreen() && +                !statusBarStateController.leaveOpenOnKeyguardHide() && +                dozeServiceHostLazy.get().isPulsing +        ) { +            // Reuse the biometric wake-and-unlock transition if we dismiss keyguard from a +            // pulse. +            // TODO: Factor this transition out of BiometricUnlockController. +            biometricUnlockControllerLazy +                .get() +                .startWakeAndUnlock(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) +        } +        if (keyguardStateController.isShowing) { +            statusBarKeyguardViewManagerLazy +                .get() +                .dismissWithAction(action, cancel, afterKeyguardGone, customMessage) +        } else { +            // If the keyguard isn't showing but the device is dreaming, we should exit the +            // dream. +            if (keyguardUpdateMonitor.isDreaming) { +                centralSurfaces?.awakenDreams() +            } +            action.onDismiss() +        } +    } + +    override fun executeRunnableDismissingKeyguard( +        runnable: Runnable?, +        cancelAction: Runnable?, +        dismissShade: Boolean, +        afterKeyguardGone: Boolean, +        deferred: Boolean, +        willAnimateOnKeyguard: Boolean, +        customMessage: String?, +    ) { +        val onDismissAction: ActivityStarter.OnDismissAction = +            object : ActivityStarter.OnDismissAction { +                override fun onDismiss(): Boolean { +                    if (runnable != null) { +                        if ( +                            keyguardStateController.isShowing && keyguardStateController.isOccluded +                        ) { +                            statusBarKeyguardViewManagerLazy +                                .get() +                                .addAfterKeyguardGoneRunnable(runnable) +                        } else { +                            mainExecutor.execute(runnable) +                        } +                    } +                    if (dismissShade) { +                        shadeControllerLazy.get().collapseShadeForActivityStart() +                    } +                    return deferred +                } + +                override fun willRunAnimationOnKeyguard(): Boolean { +                    return willAnimateOnKeyguard +                } +            } +        dismissKeyguardThenExecute( +            onDismissAction, +            cancelAction, +            afterKeyguardGone, +            customMessage, +        ) +    } + +    /** +     * Return a [ActivityTransitionAnimator.Controller] wrapping `animationController` so that: +     * - if it launches in the notification shade window and `dismissShade` is true, then the shade +     *   will be instantly dismissed at the end of the animation. +     * - if it launches in status bar window, it will make the status bar window match the device +     *   size during the animation (that way, the animation won't be clipped by the status bar +     *   size). +     * +     * @param animationController the controller that is wrapped and will drive the main animation. +     * @param dismissShade whether the notification shade will be dismissed at the end of the +     *   animation. This is ignored if `animationController` is not animating in the shade window. +     * @param isLaunchForActivity whether the launch is for an activity. +     */ +    private fun wrapAnimationControllerForShadeOrStatusBar( +        animationController: ActivityTransitionAnimator.Controller?, +        dismissShade: Boolean, +        isLaunchForActivity: Boolean, +    ): ActivityTransitionAnimator.Controller? { +        if (animationController == null) { +            return null +        } +        val rootView = animationController.transitionContainer.rootView +        val controllerFromStatusBar: Optional<ActivityTransitionAnimator.Controller> = +            statusBarWindowController.wrapAnimationControllerIfInStatusBar( +                rootView, +                animationController +            ) +        if (controllerFromStatusBar.isPresent) { +            return controllerFromStatusBar.get() +        } + +        centralSurfaces?.let { +            // If the view is not in the status bar, then we are animating a view in the shade. +            // We have to make sure that we collapse it when the animation ends or is cancelled. +            if (dismissShade) { +                return StatusBarTransitionAnimatorController( +                    animationController, +                    shadeAnimationInteractor, +                    shadeControllerLazy.get(), +                    notifShadeWindowControllerLazy.get(), +                    commandQueue, +                    displayId, +                    isLaunchForActivity +                ) +            } +        } + +        return animationController +    } + +    /** +     * Wraps an animation controller so that if an activity would be launched on top of the +     * lockscreen, the correct flags are set for it to be occluded. +     */ +    private fun wrapAnimationControllerForLockscreen( +        animationController: ActivityTransitionAnimator.Controller? +    ): ActivityTransitionAnimator.Controller? { +        return animationController?.let { +            object : DelegateTransitionAnimatorController(it) { +                override fun onIntentStarted(willAnimate: Boolean) { +                    delegate.onIntentStarted(willAnimate) +                    if (willAnimate) { +                        centralSurfaces?.setIsLaunchingActivityOverLockscreen(true) +                    } +                } + +                override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) { +                    super.onTransitionAnimationStart(isExpandingFullyAbove) + +                    // Double check that the keyguard is still showing and not going +                    // away, but if so set the keyguard occluded. Typically, WM will let +                    // KeyguardViewMediator know directly, but we're overriding that to +                    // play the custom launch animation, so we need to take care of that +                    // here. The unocclude animation is not overridden, so WM will call +                    // KeyguardViewMediator's unocclude animation runner when the +                    // activity is exited. +                    if ( +                        keyguardStateController.isShowing && +                            !keyguardStateController.isKeyguardGoingAway +                    ) { +                        Log.d(TAG, "Setting occluded = true in #startActivity.") +                        keyguardViewMediatorLazy +                            .get() +                            .setOccluded(true /* isOccluded */, true /* animate */) +                    } +                } + +                override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) { +                    // Set mIsLaunchingActivityOverLockscreen to false before actually +                    // finishing the animation so that we can assume that +                    // mIsLaunchingActivityOverLockscreen being true means that we will +                    // collapse the shade (or at least run the post collapse runnables) +                    // later on. +                    centralSurfaces?.setIsLaunchingActivityOverLockscreen(false) +                    delegate.onTransitionAnimationEnd(isExpandingFullyAbove) +                } + +                override fun onTransitionAnimationCancelled(newKeyguardOccludedState: Boolean?) { +                    if (newKeyguardOccludedState != null) { +                        keyguardViewMediatorLazy +                            .get() +                            .setOccluded(newKeyguardOccludedState, false /* animate */) +                    } + +                    // Set mIsLaunchingActivityOverLockscreen to false before actually +                    // finishing the animation so that we can assume that +                    // mIsLaunchingActivityOverLockscreen being true means that we will +                    // collapse the shade (or at least run the // post collapse +                    // runnables) later on. +                    centralSurfaces?.setIsLaunchingActivityOverLockscreen(false) +                    delegate.onTransitionAnimationCancelled(newKeyguardOccludedState) +                } +            } +        } +    } + +    /** Retrieves the current user handle to start the Activity. */ +    private fun getActivityUserHandle(intent: Intent): UserHandle { +        val packages: Array<String> = context.resources.getStringArray(R.array.system_ui_packages) +        for (pkg in packages) { +            val componentName = intent.component ?: break +            if (pkg == componentName.packageName) { +                return UserHandle(UserHandle.myUserId()) +            } +        } +        return userTracker.userHandle +    } + +    /** +     * Whether we should animate an activity launch. +     * +     * Note: This method must be called *before* dismissing the keyguard. +     */ +    private fun shouldAnimateLaunch( +        isActivityIntent: Boolean, +        showOverLockscreen: Boolean, +    ): Boolean { +        // TODO(b/294418322): Support launch animations when occluded. +        if (keyguardStateController.isOccluded) { +            return false +        } + +        // Always animate if we are not showing the keyguard or if we animate over the lockscreen +        // (without unlocking it). +        if (showOverLockscreen || !keyguardStateController.isShowing) { +            return true +        } + +        // We don't animate non-activity launches as they can break the animation. +        // TODO(b/184121838): Support non activity launches on the lockscreen. +        return isActivityIntent +    } + +    override fun shouldAnimateLaunch(isActivityIntent: Boolean): Boolean { +        return shouldAnimateLaunch(isActivityIntent, false) +    } + +    private fun postOnUiThread(delay: Int = 0, runnable: Runnable) { +        mainExecutor.executeDelayed(runnable, delay.toLong()) +    } + +    companion object { +        private const val TAG = "LegacyActivityStarterInternalImpl" +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java index ed1f6ff7e513..87139ac0cada 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java @@ -98,11 +98,11 @@ public class StatusBarHeadsUpChangeListener implements OnHeadsUpChangedListener,                  // we need to keep the panel open artificially, let's wait until the                  //animation                  // is finished. -                mHeadsUpManager.setHeadsUpGoingAway(true); +                mHeadsUpManager.setHeadsUpAnimatingAway(true);                  mNsslController.runAfterAnimationFinished(() -> {                      if (!mHeadsUpManager.hasPinnedHeadsUp()) {                          mNotificationShadeWindowController.setHeadsUpShowing(false); -                        mHeadsUpManager.setHeadsUpGoingAway(false); +                        mHeadsUpManager.setHeadsUpAnimatingAway(false);                      }                      mNotificationRemoteInputManager.onPanelCollapsed();                  }); 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 5f26702ad867..dd7d282e67c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -67,12 +67,12 @@ import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;  import com.android.systemui.dock.DockManager;  import com.android.systemui.dreams.DreamOverlayStateController;  import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags;  import com.android.systemui.keyguard.KeyguardWmStateRefactor;  import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor;  import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor;  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;  import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor; +import com.android.systemui.keyguard.shared.RefactorKeyguardDismissIntent;  import com.android.systemui.keyguard.shared.model.DismissAction;  import com.android.systemui.keyguard.shared.model.KeyguardDone;  import com.android.systemui.keyguard.shared.model.KeyguardState; @@ -381,7 +381,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb              Lazy<ShadeController> shadeController,              LatencyTracker latencyTracker,              KeyguardSecurityModel keyguardSecurityModel, -            FeatureFlags featureFlags,              PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor,              PrimaryBouncerInteractor primaryBouncerInteractor,              BouncerView primaryBouncerView, @@ -413,7 +412,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb          mShadeController = shadeController;          mLatencyTracker = latencyTracker;          mKeyguardSecurityModel = keyguardSecurityModel; -        mFlags = featureFlags;          mPrimaryBouncerCallbackInteractor = primaryBouncerCallbackInteractor;          mPrimaryBouncerInteractor = primaryBouncerInteractor;          mPrimaryBouncerView = primaryBouncerView; @@ -805,7 +803,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb      public void dismissWithAction(OnDismissAction r, Runnable cancelAction,              boolean afterKeyguardGone, String message) { -        if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +        if (RefactorKeyguardDismissIntent.isEnabled()) {              if (r == null) {                  return;              } @@ -857,7 +855,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb                      return;                  } -                if (!mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +                if (!RefactorKeyguardDismissIntent.isEnabled()) {                      mAfterKeyguardGoneAction = r;                      mKeyguardGoneCancelAction = cancelAction;                      mDismissActionWillAnimateOnKeyguard = r != null @@ -925,7 +923,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb       * Adds a {@param runnable} to be executed after Keyguard is gone.       */      public void addAfterKeyguardGoneRunnable(Runnable runnable) { -        if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +        if (RefactorKeyguardDismissIntent.isEnabled()) {              if (runnable != null) {                  mKeyguardDismissActionInteractor.get().runAfterKeyguardGone(runnable);              } @@ -1118,7 +1116,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb              // We update the state (which will show the keyguard) only if an animation will run on              // the keyguard. If there is no animation, we wait before updating the state so that we              // go directly from bouncer to launcher/app. -            if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +            if (RefactorKeyguardDismissIntent.isEnabled()) {                  if (mKeyguardDismissActionInteractor.get().runDismissAnimationOnKeyguard()) {                      updateStates();                  } @@ -1245,7 +1243,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb      }      private void executeAfterKeyguardGoneAction() { -        if (mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { +        if (RefactorKeyguardDismissIntent.isEnabled()) {              return;          }          if (mAfterKeyguardGoneAction != null) { @@ -1298,9 +1296,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb              return;          } +        boolean hideBouncerOverDream = isBouncerShowing() +                && mDreamOverlayStateController.isOverlayActive();          mCentralSurfaces.endAffordanceLaunch();          // The second condition is for SIM card locked bouncer -        if (primaryBouncerIsScrimmed() && !needsFullscreenBouncer()) { +        if (hideBouncerOverDream || (primaryBouncerIsScrimmed() && !needsFullscreenBouncer())) {              hideBouncer(false);              updateStates();          } else { @@ -1634,7 +1634,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb          pw.println("  bouncerIsOrWillBeShowing(): " + primaryBouncerIsOrWillBeShowing());          pw.println("  Registered KeyguardViewManagerCallbacks:");          pw.println(" refactorKeyguardDismissIntent enabled:" -                + mFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)); +                + RefactorKeyguardDismissIntent.isEnabled());          for (KeyguardViewManagerCallback callback : mCallbacks) {              pw.println("      " + callback);          } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java index c615887d5c25..8e8de46957ed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java @@ -121,7 +121,7 @@ public final class StatusBarTouchableRegionManager implements Dumpable {                          updateTouchableRegion();                      }                  }); -        mHeadsUpManager.addHeadsUpPhoneListener(this::onHeadsUpGoingAwayStateChanged); +        mHeadsUpManager.addHeadsUpPhoneListener(this::onHeadsUpAnimatingAwayStateChanged);          mNotificationShadeWindowController = notificationShadeWindowController;          mNotificationShadeWindowController.setForcePluginOpenListener((forceOpen) -> { @@ -214,7 +214,7 @@ public final class StatusBarTouchableRegionManager implements Dumpable {                  && (mNotificationShadeWindowView.getRootWindowInsets() != null)                  && (mNotificationShadeWindowView.getRootWindowInsets().getDisplayCutout() != null);          boolean shouldObserve = mHeadsUpManager.hasPinnedHeadsUp() -                        || mHeadsUpManager.isHeadsUpGoingAway() +                        || mHeadsUpManager.isHeadsUpAnimatingAwayValue()                          || mForceCollapsedUntilLayout                          || hasCutoutInset                          || mNotificationShadeWindowController.getForcePluginOpen(); @@ -288,8 +288,8 @@ public final class StatusBarTouchableRegionManager implements Dumpable {                  || mUnlockedScreenOffAnimationController.isAnimationPlaying();      } -    private void onHeadsUpGoingAwayStateChanged(boolean headsUpGoingAway) { -        if (!headsUpGoingAway) { +    private void onHeadsUpAnimatingAwayStateChanged(boolean headsUpAnimatingAway) { +        if (!headsUpAnimatingAway) {              updateTouchableRegionAfterLayout();          } else {              updateTouchableRegion(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt index 3b2930f78d19..f4e3eab8593d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.pipeline.mobile.data.model  import android.os.PersistableBundle  import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL -import android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT  import android.telephony.CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL  import androidx.annotation.VisibleForTesting  import kotlinx.coroutines.flow.MutableStateFlow @@ -43,11 +42,10 @@ import kotlinx.coroutines.flow.asStateFlow   * using the default config for logging purposes.   *   * NOTE to add new keys to be tracked: - * 1. Define a new `private val` wrapping the key using [BooleanCarrierConfig] or [IntCarrierConfig] - * 2. Define a public `val` exposing the wrapped flow using [BooleanCarrierConfig.config] or - *    [IntCarrierConfig.config] - * 3. Add the new wrapped public flow to the list of tracked configs, so they are properly updated - *    when a new carrier config comes down + * 1. Define a new `private val` wrapping the key using [BooleanCarrierConfig] + * 2. Define a public `val` exposing the wrapped flow using [BooleanCarrierConfig.config] + * 3. Add the new [BooleanCarrierConfig] to the list of tracked configs, so they are properly + *    updated when a new carrier config comes down   */  class SystemUiCarrierConfig  internal constructor( @@ -68,16 +66,10 @@ internal constructor(      /** Flow tracking the [KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL] config */      val showOperatorNameInStatusBar: StateFlow<Boolean> = showOperatorName.config -    private val satelliteHysteresisSeconds = -        IntCarrierConfig(KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT, defaultConfig) -    /** Flow tracking the [KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT] config */ -    val satelliteConnectionHysteresisSeconds: StateFlow<Int> = satelliteHysteresisSeconds.config -      private val trackedConfigs =          listOf(              inflateSignalStrength,              showOperatorName, -            satelliteHysteresisSeconds,          )      /** Ingest a new carrier config, and switch all of the tracked keys over to the new values */ @@ -98,19 +90,15 @@ internal constructor(      override fun toString(): String = trackedConfigs.joinToString { it.toString() }  } -interface CarrierConfig { -    fun update(config: PersistableBundle) -} -  /** Extracts [key] from the carrier config, and stores it in a flow */  private class BooleanCarrierConfig(      val key: String,      defaultConfig: PersistableBundle, -) : CarrierConfig { +) {      private val _configValue = MutableStateFlow(defaultConfig.getBoolean(key))      val config = _configValue.asStateFlow() -    override fun update(config: PersistableBundle) { +    fun update(config: PersistableBundle) {          _configValue.value = config.getBoolean(key)      } @@ -118,20 +106,3 @@ private class BooleanCarrierConfig(          return "$key=${config.value}"      }  } - -/** Extracts [key] from the carrier config, and stores it in a flow */ -private class IntCarrierConfig( -    val key: String, -    defaultConfig: PersistableBundle, -) : CarrierConfig { -    private val _configValue = MutableStateFlow(defaultConfig.getInt(key)) -    val config = _configValue.asStateFlow() - -    override fun update(config: PersistableBundle) { -        _configValue.value = config.getInt(key) -    } - -    override fun toString(): String { -        return "$key=${config.value}" -    } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt index 8f00b43e79f8..22785979f3ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt @@ -44,6 +44,9 @@ interface MobileConnectionRepository {      /** The carrierId for this connection. See [TelephonyManager.getSimCarrierId] */      val carrierId: StateFlow<Int> +    /** Reflects the value from the carrier config INFLATE_SIGNAL_STRENGTH for this connection */ +    val inflateSignalStrength: StateFlow<Boolean> +      /**       * The table log buffer created for this connection. Will have the name "MobileConnectionLog       * [subId]" @@ -141,9 +144,6 @@ interface MobileConnectionRepository {       */      val hasPrioritizedNetworkCapabilities: StateFlow<Boolean> -    /** Duration in seconds of the hysteresis to use when losing satellite connection. */ -    val satelliteConnectionHysteresisSeconds: StateFlow<Int> -      /**       * True if this connection is in emergency callback mode.       * diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt index af34a57c7242..83d5f2b5d325 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt @@ -43,6 +43,7 @@ import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.F  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.stateIn  /** @@ -67,6 +68,17 @@ class DemoMobileConnectionRepository(              )              .stateIn(scope, SharingStarted.WhileSubscribed(), _carrierId.value) +    private val _inflateSignalStrength: MutableStateFlow<Boolean> = MutableStateFlow(false) +    override val inflateSignalStrength = +        _inflateSignalStrength +            .logDiffsForTable( +                tableLogBuffer, +                columnPrefix = "", +                columnName = "inflate", +                _inflateSignalStrength.value +            ) +            .stateIn(scope, SharingStarted.WhileSubscribed(), _inflateSignalStrength.value) +      private val _isEmergencyOnly = MutableStateFlow(false)      override val isEmergencyOnly =          _isEmergencyOnly @@ -191,7 +203,16 @@ class DemoMobileConnectionRepository(              .logDiffsForTable(tableLogBuffer, columnPrefix = "", _resolvedNetworkType.value)              .stateIn(scope, SharingStarted.WhileSubscribed(), _resolvedNetworkType.value) -    override val numberOfLevels = MutableStateFlow(MobileConnectionRepository.DEFAULT_NUM_LEVELS) +    override val numberOfLevels = +        _inflateSignalStrength +            .map { shouldInflate -> +                if (shouldInflate) { +                    DEFAULT_NUM_LEVELS + 1 +                } else { +                    DEFAULT_NUM_LEVELS +                } +            } +            .stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)      override val dataEnabled = MutableStateFlow(true) @@ -206,8 +227,6 @@ class DemoMobileConnectionRepository(      override val hasPrioritizedNetworkCapabilities = MutableStateFlow(false) -    override val satelliteConnectionHysteresisSeconds = MutableStateFlow(0) -      override suspend fun isInEcmMode(): Boolean = false      /** @@ -226,8 +245,7 @@ class DemoMobileConnectionRepository(          _carrierId.value = event.carrierId ?: INVALID_SUBSCRIPTION_ID -        numberOfLevels.value = -            if (event.inflateStrength) DEFAULT_NUM_LEVELS + 1 else DEFAULT_NUM_LEVELS +        _inflateSignalStrength.value = event.inflateStrength          cdmaRoaming.value = event.roaming          _isRoaming.value = event.roaming @@ -258,7 +276,6 @@ class DemoMobileConnectionRepository(          carrierName.value = NetworkNameModel.SubscriptionDerived(CARRIER_MERGED_NAME)          // TODO(b/276943904): is carrierId a thing with carrier merged networks?          _carrierId.value = INVALID_SUBSCRIPTION_ID -        numberOfLevels.value = event.numberOfLevels          cdmaRoaming.value = false          _primaryLevel.value = event.level          _cdmaLevel.value = event.level diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt index 2bc3bcbc8bf5..a532e6227451 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt @@ -165,6 +165,7 @@ class CarrierMergedConnectionRepository(      override val isRoaming = MutableStateFlow(false).asStateFlow()      override val carrierId = MutableStateFlow(INVALID_SUBSCRIPTION_ID).asStateFlow() +    override val inflateSignalStrength = MutableStateFlow(false).asStateFlow()      override val isEmergencyOnly = MutableStateFlow(false).asStateFlow()      override val operatorAlphaShort = MutableStateFlow(null).asStateFlow()      override val isInService = MutableStateFlow(true).asStateFlow() @@ -186,9 +187,6 @@ class CarrierMergedConnectionRepository(       */      override val hasPrioritizedNetworkCapabilities = MutableStateFlow(false).asStateFlow() -    /** Non-applicable to carrier merged connections. */ -    override val satelliteConnectionHysteresisSeconds = MutableStateFlow(0).asStateFlow() -      override val dataEnabled: StateFlow<Boolean> = wifiRepository.isWifiEnabled      override suspend fun isInEcmMode(): Boolean = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt index b085d8046b12..41559b2c1455 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt @@ -16,6 +16,7 @@  package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod +import android.util.IndentingPrintWriter  import androidx.annotation.VisibleForTesting  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.log.table.TableLogBuffer @@ -24,6 +25,7 @@ import com.android.systemui.log.table.logDiffsForTable  import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel  import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel  import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository +import java.io.PrintWriter  import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -291,6 +293,21 @@ class FullMobileConnectionRepository(              )              .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.dataEnabled.value) +    override val inflateSignalStrength = +        activeRepo +            .flatMapLatest { it.inflateSignalStrength } +            .logDiffsForTable( +                tableLogBuffer, +                columnPrefix = "", +                columnName = "inflate", +                initialValue = activeRepo.value.inflateSignalStrength.value, +            ) +            .stateIn( +                scope, +                SharingStarted.WhileSubscribed(), +                activeRepo.value.inflateSignalStrength.value +            ) +      override val numberOfLevels =          activeRepo              .flatMapLatest { it.numberOfLevels } @@ -334,17 +351,29 @@ class FullMobileConnectionRepository(                  activeRepo.value.hasPrioritizedNetworkCapabilities.value,              ) -    override val satelliteConnectionHysteresisSeconds = -        activeRepo -            .flatMapLatest { it.satelliteConnectionHysteresisSeconds } -            .stateIn( -                scope, -                SharingStarted.WhileSubscribed(), -                activeRepo.value.satelliteConnectionHysteresisSeconds.value -            ) -      override suspend fun isInEcmMode(): Boolean = activeRepo.value.isInEcmMode() +    fun dump(pw: PrintWriter) { +        val ipw = IndentingPrintWriter(pw, "  ") + +        ipw.println("MobileConnectionRepository[$subId]") +        ipw.increaseIndent() + +        ipw.println("carrierMerged=${_isCarrierMerged.value}") + +        ipw.print("Type (cellular or carrier merged): ") +        when (activeRepo.value) { +            is CarrierMergedConnectionRepository -> ipw.println("Carrier merged") +            is MobileConnectionRepositoryImpl -> ipw.println("Cellular") +        } + +        ipw.increaseIndent() +        ipw.println("Provider: ${activeRepo.value}") +        ipw.decreaseIndent() + +        ipw.decreaseIndent() +    } +      class Factory      @Inject      constructor( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt index 5ab2ae899370..b3885d247949 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt @@ -302,8 +302,10 @@ class MobileConnectionRepositoryImpl(              }              .stateIn(scope, SharingStarted.WhileSubscribed(), UnknownNetworkType) +    override val inflateSignalStrength = systemUiCarrierConfig.shouldInflateSignalStrength +      override val numberOfLevels = -        systemUiCarrierConfig.shouldInflateSignalStrength +        inflateSignalStrength              .map { shouldInflate ->                  if (shouldInflate) {                      DEFAULT_NUM_LEVELS + 1 @@ -448,9 +450,6 @@ class MobileConnectionRepositoryImpl(              .flowOn(bgDispatcher)              .stateIn(scope, SharingStarted.WhileSubscribed(), false) -    override val satelliteConnectionHysteresisSeconds: StateFlow<Int> = -        systemUiCarrierConfig.satelliteConnectionHysteresisSeconds -      class Factory      @Inject      constructor( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt index a455db2e67ce..5d91ef323ead 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt @@ -26,17 +26,20 @@ import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID  import android.telephony.TelephonyCallback  import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener  import android.telephony.TelephonyManager +import android.util.IndentingPrintWriter  import androidx.annotation.VisibleForTesting  import com.android.internal.telephony.PhoneConstants  import com.android.keyguard.KeyguardUpdateMonitor  import com.android.keyguard.KeyguardUpdateMonitorCallback  import com.android.settingslib.SignalIcon.MobileIconGroup  import com.android.settingslib.mobile.MobileMappings.Config +import com.android.systemui.Dumpable  import com.android.systemui.broadcast.BroadcastDispatcher  import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dump.DumpManager  import com.android.systemui.log.table.TableLogBuffer  import com.android.systemui.log.table.logDiffsForTable  import com.android.systemui.res.R @@ -52,6 +55,8 @@ import com.android.systemui.statusbar.pipeline.shared.data.repository.Connectivi  import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository  import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel  import com.android.systemui.util.kotlin.pairwise +import java.io.PrintWriter +import java.lang.ref.WeakReference  import javax.inject.Inject  import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.CoroutineScope @@ -97,8 +102,12 @@ constructor(      wifiRepository: WifiRepository,      private val fullMobileRepoFactory: FullMobileConnectionRepository.Factory,      private val keyguardUpdateMonitor: KeyguardUpdateMonitor, -) : MobileConnectionsRepository { -    private var subIdRepositoryCache: MutableMap<Int, FullMobileConnectionRepository> = +    private val dumpManager: DumpManager, +) : MobileConnectionsRepository, Dumpable { + +    // TODO(b/333912012): for now, we are never invalidating the cache. We can do better though +    private var subIdRepositoryCache: +        MutableMap<Int, WeakReference<FullMobileConnectionRepository>> =          mutableMapOf()      private val defaultNetworkName = @@ -109,6 +118,10 @@ constructor(      private val networkNameSeparator: String =          context.getString(R.string.status_bar_network_name_separator) +    init { +        dumpManager.registerNormalDumpable("MobileConnectionsRepository", this) +    } +      private val carrierMergedSubId: StateFlow<Int?> =          combine(                  wifiRepository.wifiNetwork, @@ -283,8 +296,10 @@ constructor(          getOrCreateRepoForSubId(subId)      private fun getOrCreateRepoForSubId(subId: Int) = -        subIdRepositoryCache[subId] -            ?: createRepositoryForSubId(subId).also { subIdRepositoryCache[subId] = it } +        subIdRepositoryCache[subId]?.get() +            ?: createRepositoryForSubId(subId).also { +                subIdRepositoryCache[subId] = WeakReference(it) +            }      override val mobileIsDefault: StateFlow<Boolean> =          connectivityRepository.defaultConnections @@ -374,9 +389,8 @@ constructor(      }      private fun updateRepos(newInfos: List<SubscriptionModel>) { -        dropUnusedReposFromCache(newInfos)          subIdRepositoryCache.forEach { (subId, repo) -> -            repo.setIsCarrierMerged(isCarrierMerged(subId)) +            repo.get()?.setIsCarrierMerged(isCarrierMerged(subId))          }      } @@ -384,13 +398,6 @@ constructor(          return subId == carrierMergedSubId.value      } -    private fun dropUnusedReposFromCache(newInfos: List<SubscriptionModel>) { -        // Remove any connection repository from the cache that isn't in the new set of IDs. They -        // will get garbage collected once their subscribers go away -        subIdRepositoryCache = -            subIdRepositoryCache.filter { checkSub(it.key, newInfos) }.toMutableMap() -    } -      /**       * True if the checked subId is in the list of current subs or the active mobile data subId       * @@ -422,6 +429,22 @@ constructor(              profileClass = profileClass,          ) +    override fun dump(pw: PrintWriter, args: Array<String>) { +        val ipw = IndentingPrintWriter(pw, " ") +        ipw.println("Connection cache:") + +        ipw.increaseIndent() +        subIdRepositoryCache.entries.forEach { (subId, repo) -> +            ipw.println("$subId: ${repo.get()}") +        } +        ipw.decreaseIndent() + +        ipw.println("Connections (${subIdRepositoryCache.size} total):") +        ipw.increaseIndent() +        subIdRepositoryCache.values.forEach { it.get()?.dump(ipw) } +        ipw.decreaseIndent() +    } +      companion object {          private const val LOGGING_PREFIX = "Repo"      } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index 9d194cfca350..ed9e4056535f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt @@ -35,25 +35,18 @@ import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIc  import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel  import com.android.systemui.statusbar.pipeline.satellite.ui.model.SatelliteIconModel  import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel -import com.android.systemui.util.kotlin.pairwiseBy -import kotlin.time.DurationUnit -import kotlin.time.toDuration  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.delay  import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.flow.SharingStarted  import kotlinx.coroutines.flow.StateFlow  import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.collectLatest  import kotlinx.coroutines.flow.combine  import kotlinx.coroutines.flow.distinctUntilChanged  import kotlinx.coroutines.flow.flatMapLatest  import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch  interface MobileIconInteractor {      /** The table log created for this connection */ @@ -269,43 +262,6 @@ class MobileIconInteractorImpl(              MutableStateFlow(false).asStateFlow()          } -    private val hysteresisActive = MutableStateFlow(false) - -    private val isNonTerrestrialWithHysteresis: StateFlow<Boolean> = -        combine(isNonTerrestrial, hysteresisActive) { isNonTerrestrial, hysteresisActive -> -                if (hysteresisActive) { -                    true -                } else { -                    isNonTerrestrial -                } -            } -            .logDiffsForTable( -                tableLogBuffer = tableLogBuffer, -                columnName = "isNonTerrestrialWithHysteresis", -                columnPrefix = "", -                initialValue = Flags.carrierEnabledSatelliteFlag(), -            ) -            .stateIn(scope, SharingStarted.Eagerly, Flags.carrierEnabledSatelliteFlag()) - -    private val lostSatelliteConnection = -        isNonTerrestrial.pairwiseBy { old, new -> hysteresisActive.value = old && !new } - -    init { -        scope.launch { lostSatelliteConnection.collect() } -        scope.launch { -            hysteresisActive.collectLatest { -                if (it) { -                    delay( -                        connectionRepository.satelliteConnectionHysteresisSeconds.value.toDuration( -                            DurationUnit.SECONDS -                        ) -                    ) -                    hysteresisActive.value = false -                } -            } -        } -    } -      override val isRoaming: StateFlow<Boolean> =          combine(                  connectionRepository.carrierNetworkChangeActive, @@ -367,8 +323,11 @@ class MobileIconInteractorImpl(          combine(                  level,                  isInService, -            ) { level, isInService -> -                if (isInService) level else 0 +                connectionRepository.inflateSignalStrength, +            ) { level, isInService, inflate -> +                if (isInService) { +                    if (inflate) level + 1 else level +                } else 0              }              .stateIn(scope, SharingStarted.WhileSubscribed(), 0) @@ -404,7 +363,7 @@ class MobileIconInteractorImpl(                  showExclamationMark.value,                  carrierNetworkChangeActive.value,              ) -        isNonTerrestrialWithHysteresis +        isNonTerrestrial              .flatMapLatest { ntn ->                  if (ntn) {                      satelliteIcon diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt index eda5c44b5c2f..103b0e3a6f27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt @@ -16,7 +16,7 @@  package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel -import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH +import com.android.settingslib.AccessibilityContentDescriptions  import com.android.systemui.Flags.statusBarStaticInoutIndicators  import com.android.systemui.common.shared.model.ContentDescription  import com.android.systemui.common.shared.model.Icon @@ -50,7 +50,7 @@ interface MobileIconViewModelCommon {      /** True if this view should be visible at all. */      val isVisible: StateFlow<Boolean>      val icon: Flow<SignalIconModel> -    val contentDescription: Flow<ContentDescription> +    val contentDescription: Flow<ContentDescription?>      val roaming: Flow<Boolean>      /** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */      val networkTypeIcon: Flow<Icon.Resource?> @@ -123,7 +123,7 @@ class MobileIconViewModel(      override val icon: Flow<SignalIconModel> = vmProvider.flatMapLatest { it.icon } -    override val contentDescription: Flow<ContentDescription> = +    override val contentDescription: Flow<ContentDescription?> =          vmProvider.flatMapLatest { it.contentDescription }      override val roaming: Flow<Boolean> = vmProvider.flatMapLatest { it.roaming } @@ -206,12 +206,26 @@ private class CellularIconViewModel(      override val icon: Flow<SignalIconModel> = iconInteractor.signalLevelIcon -    override val contentDescription: Flow<ContentDescription> = run { -        val initial = ContentDescription.Resource(PHONE_SIGNAL_STRENGTH[0]) +    override val contentDescription: Flow<ContentDescription?> =          iconInteractor.signalLevelIcon -            .map { ContentDescription.Resource(PHONE_SIGNAL_STRENGTH[it.level]) } -            .stateIn(scope, SharingStarted.WhileSubscribed(), initial) -    } +            .map { +                // We expect the signal icon to be cellular here since this is the cellular vm +                if (it !is SignalIconModel.Cellular) { +                    null +                } else { +                    val resId = +                        AccessibilityContentDescriptions.getDescriptionForLevel( +                            it.level, +                            it.numberOfLevels +                        ) +                    if (resId != 0) { +                        ContentDescription.Resource(resId) +                    } else { +                        null +                    } +                } +            } +            .stateIn(scope, SharingStarted.WhileSubscribed(), null)      private val showNetworkTypeIcon: Flow<Boolean> =          combine( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt index 52a6d8cf0952..cc87e8a45d13 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt @@ -19,6 +19,9 @@ package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel  import com.android.systemui.dagger.SysUISingleton  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING +import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN +import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED  import com.android.systemui.keyguard.shared.model.TransitionState  import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor  import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor @@ -77,15 +80,13 @@ constructor(      @Application coroutineScope: CoroutineScope,  ) : CollapsedStatusBarViewModel {      override val isTransitioningFromLockscreenToOccluded: StateFlow<Boolean> = -        keyguardTransitionInteractor.lockscreenToOccludedTransition -            .map { -                it.transitionState == TransitionState.STARTED || -                    it.transitionState == TransitionState.RUNNING -            } +        keyguardTransitionInteractor +            .isInTransition(LOCKSCREEN, OCCLUDED)              .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), initialValue = false)      override val transitionFromLockscreenToDreamStartedEvent: Flow<Unit> = -        keyguardTransitionInteractor.lockscreenToDreamingTransition +        keyguardTransitionInteractor +            .transition(LOCKSCREEN, DREAMING)              .filter { it.transitionState == TransitionState.STARTED }              .map {} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt index 9cdecef3f6e8..1b56702f3907 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt @@ -115,13 +115,16 @@ class AvalancheController @Inject constructor(       * Run or ignore Runnable for given HeadsUpEntry. If entry was never shown, ignore and delete       * all Runnables associated with that entry.       */ -    fun delete(entry: HeadsUpEntry, runnable: Runnable, label: String) { +    fun delete(entry: HeadsUpEntry?, runnable: Runnable, label: String) {          if (!NotificationThrottleHun.isEnabled) {              runnable.run()              return          }          val fn = "[$label] => AvalancheController.delete " + getKey(entry) - +        if (entry == null) { +            log { "$fn => cannot remove NULL entry" } +            return +        }          if (entry in nextMap) {              log { "$fn => [remove from next]" }              if (entry in nextMap) nextMap.remove(entry) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java index d99af2ddb95d..b8318a7dfb61 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BaseHeadsUpManager.java @@ -256,10 +256,15 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {          // A copy is necessary here as we are changing the underlying map.  This would cause          // undefined behavior if we iterated over the key set directly.          ArraySet<String> keysToRemove = new ArraySet<>(mHeadsUpEntryMap.keySet()); + +        // Must get waiting keys before calling removeEntry, which clears waiting entries in +        // AvalancheController +        List<String> waitingKeysToRemove = mAvalancheController.getWaitingKeys(); +          for (String key : keysToRemove) {              removeEntry(key);          } -        for (String key : mAvalancheController.getWaitingKeys()) { +        for (String key : waitingKeysToRemove) {              removeEntry(key);          }      } @@ -903,8 +908,12 @@ public abstract class BaseHeadsUpManager implements HeadsUpManager {                      mLogger.logAutoRemoveCanceled(mEntry, reason);                  }              }; -            mAvalancheController.update(this, runnable, -                    reason + " removeAutoRemovalCallbacks"); +            if (isHeadsUpEntry(this.mEntry.getKey())) { +                mAvalancheController.update(this, runnable, reason + " cancelAutoRemovalCallbacks"); +            } else { +                // Just removed +                runnable.run(); +            }          }          public void scheduleAutoRemovalCallback(FinishTimeUpdater finishTimeCalculator, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt index 52a2e9ccc163..28a2a1f49bf6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.kt @@ -73,7 +73,8 @@ interface HeadsUpManager : Dumpable {      /** Returns whether or not the given notification is managed by this manager. */      fun isHeadsUpEntry(key: String): Boolean -    fun isHeadsUpGoingAway(): Boolean +    /** @see setHeadsUpAnimatingAway */ +    fun isHeadsUpAnimatingAwayValue(): Boolean      /** Returns if the given notification is snoozed or not. */      fun isSnoozed(packageName: String): Boolean @@ -130,7 +131,7 @@ interface HeadsUpManager : Dumpable {       * Set that we are exiting the headsUp pinned mode, but some notifications might still be       * animating out. This is used to keep the touchable regions in a reasonable state.       */ -    fun setHeadsUpGoingAway(headsUpGoingAway: Boolean) +    fun setHeadsUpAnimatingAway(headsUpAnimatingAway: Boolean)      /**       * Notifies that a remote input textbox in notification gets active or inactive. @@ -194,10 +195,10 @@ interface AnimationStateHandler {  interface OnHeadsUpPhoneListenerChange {      /**       * Called when a heads up notification is 'going away' or no longer 'going away'. See -     * [HeadsUpManager.setHeadsUpGoingAway]. +     * [HeadsUpManager.setHeadsUpAnimatingAway].       */      // TODO(b/325936094) delete this callback, and listen to the flow instead -    fun onHeadsUpGoingAwayStateChanged(headsUpGoingAway: Boolean) +    fun onHeadsUpAnimatingAwayStateChanged(headsUpAnimatingAway: Boolean)  }  /* No op impl of HeadsUpManager. */ @@ -215,7 +216,7 @@ class HeadsUpManagerEmptyImpl @Inject constructor() : HeadsUpManager {      override fun getTopEntry() = null      override fun hasPinnedHeadsUp() = false      override fun isHeadsUpEntry(key: String) = false -    override fun isHeadsUpGoingAway() = false +    override fun isHeadsUpAnimatingAwayValue() = false      override fun isSnoozed(packageName: String) = false      override fun isSticky(key: String?) = false      override fun isTrackingHeadsUp() = false @@ -228,7 +229,7 @@ class HeadsUpManagerEmptyImpl @Inject constructor() : HeadsUpManager {      override fun setAnimationStateHandler(handler: AnimationStateHandler) {}      override fun setExpanded(entry: NotificationEntry, expanded: Boolean) {}      override fun setGutsShown(entry: NotificationEntry, gutsShown: Boolean) {} -    override fun setHeadsUpGoingAway(headsUpGoingAway: Boolean) {} +    override fun setHeadsUpAnimatingAway(headsUpAnimatingAway: Boolean) {}      override fun setRemoteInputActive(entry: NotificationEntry, remoteInputActive: Boolean) {}      override fun setTrackingHeadsUp(tracking: Boolean) {}      override fun setUser(user: Int) {} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt index a30660645990..11cbc9c66923 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt @@ -176,7 +176,7 @@ class HeadsUpManagerLogger @Inject constructor(              bool1 = alert              bool2 = hasEntry          }, { -            "request: update notification $str1 alert: $bool1 hasEntry: $bool2 reason: $str2" +            "request: update notification $str1 alert: $bool1 hasEntry: $bool2"          })      } @@ -186,7 +186,7 @@ class HeadsUpManagerLogger @Inject constructor(              bool1 = alert              bool2 = hasEntry          }, { -            "update notification $str1 alert: $bool1 hasEntry: $bool2 reason: $str2" +            "update notification $str1 alert: $bool1 hasEntry: $bool2"          })      } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 27a708a00cb7..1688b0b51b41 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -1129,7 +1129,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,          }          updateSelectedRingerContainerDescription(true); - +        mSelectedRingerContainer.setImportantForAccessibility( +                View.IMPORTANT_FOR_ACCESSIBILITY_NO); +        mSelectedRingerContainer.clearFocus();          mIsRingerDrawerOpen = true;      } @@ -1175,7 +1177,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,                  .start();          updateSelectedRingerContainerDescription(false); - +        mSelectedRingerContainer.setImportantForAccessibility( +                View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);          mIsRingerDrawerOpen = false;      } @@ -1746,7 +1749,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,              boolean isZenMuted = mState.zenMode == Global.ZEN_MODE_ALARMS                      || mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS                      || (mState.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS -                        && mState.disallowRinger); +                    && mState.disallowRinger);              enableRingerViewsH(!isZenMuted);              switch (mState.ringerModeInternal) {                  case AudioManager.RINGER_MODE_VIBRATE: @@ -1796,7 +1799,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable,              public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {                  super.onInitializeAccessibilityNodeInfo(host, info);                  info.addAction(new AccessibilityNodeInfo.AccessibilityAction( -                                AccessibilityNodeInfo.ACTION_CLICK, hintLabel)); +                        AccessibilityNodeInfo.ACTION_CLICK, hintLabel));              }          });      } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/UiEventLoggerStartableModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/UiEventLoggerStartableModule.kt new file mode 100644 index 000000000000..9b84090d72cd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/UiEventLoggerStartableModule.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + *  Licensed under the Apache License, Version 2.0 (the "License"); + *  you may not use this file except in compliance with the License. + *  You may obtain a copy of the License at + * + *       http://www.apache.org/licenses/LICENSE-2.0 + * + *  Unless required by applicable law or agreed to in writing, software + *  distributed under the License is distributed on an "AS IS" BASIS, + *  WITHOUT 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.volume.dagger + +import com.android.systemui.volume.domain.startable.AudioModeLoggerStartable +import com.android.systemui.volume.panel.domain.VolumePanelStartable +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoSet + +@Module +interface UiEventLoggerStartableModule { + +    @Binds +    @IntoSet +    fun bindAudioModeLoggerStartable( +        audioModeLoggerStartable: AudioModeLoggerStartable, +    ): VolumePanelStartable +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/domain/startable/AudioModeLoggerStartable.kt b/packages/SystemUI/src/com/android/systemui/volume/domain/startable/AudioModeLoggerStartable.kt new file mode 100644 index 000000000000..12447577e945 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/domain/startable/AudioModeLoggerStartable.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.volume.domain.startable + +import com.android.internal.logging.UiEventLogger +import com.android.settingslib.volume.domain.interactor.AudioModeInteractor +import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope +import com.android.systemui.volume.panel.domain.VolumePanelStartable +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.launch + +/** Logger for audio mode */ +@VolumePanelScope +class AudioModeLoggerStartable +@Inject +constructor( +    @VolumePanelScope private val scope: CoroutineScope, +    private val uiEventLogger: UiEventLogger, +    private val audioModeInteractor: AudioModeInteractor, +) : VolumePanelStartable { + +    override fun start() { +        scope.launch { +            audioModeInteractor.isOngoingCall.distinctUntilChanged().collect { ongoingCall -> +                uiEventLogger.log( +                    if (ongoingCall) VolumePanelUiEvent.VOLUME_PANEL_AUDIO_MODE_CHANGE_TO_CALLING +                    else VolumePanelUiEvent.VOLUME_PANEL_AUDIO_MODE_CHANGE_TO_NORMAL +                ) +            } +        } +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt index 8f18aa8021ae..8ce3b1fa1e73 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt @@ -41,12 +41,14 @@ import kotlinx.coroutines.flow.map  interface AncSliceRepository {      /** -     * ANC slice with a given width. Emits null when there is no ANC slice available. This can mean -     * that: +     * ANC slice with a given width. [isCollapsed] slice shows a single button, and expanded shows a +     * row buttons. +     * +     * Emits null when there is no ANC slice available. This can mean that:       * - there is no supported device connected;       * - there is no slice provider for the uri;       */ -    fun ancSlice(width: Int): Flow<Slice?> +    fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?>  }  @OptIn(ExperimentalCoroutinesApi::class) @@ -60,9 +62,14 @@ constructor(      private val localMediaRepository = mediaRepositoryFactory.create(null) -    override fun ancSlice(width: Int): Flow<Slice?> { +    override fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> {          return localMediaRepository.currentConnectedDevice -            .map { (it as? BluetoothMediaDevice)?.cachedDevice?.device?.getExtraControlUri(width) } +            .map { +                (it as? BluetoothMediaDevice) +                    ?.cachedDevice +                    ?.device +                    ?.getExtraControlUri(width, isCollapsed, hideLabel) +            }              .distinctUntilChanged()              .flatMapLatest { sliceUri ->                  sliceUri ?: return@flatMapLatest flowOf(null) @@ -71,7 +78,11 @@ constructor(              .flowOn(backgroundCoroutineContext)      } -    private fun BluetoothDevice.getExtraControlUri(width: Int): Uri? { +    private fun BluetoothDevice.getExtraControlUri( +        width: Int, +        isCollapsed: Boolean, +        hideLabel: Boolean +    ): Uri? {          val uri: String? = BluetoothUtils.getControlUriMetaData(this)          uri ?: return null @@ -81,7 +92,8 @@ constructor(              Uri.parse(                  "$uri$width" +                      "&version=${SliceParameters.VERSION}" + -                    "&is_collapsed=${SliceParameters.IS_COLLAPSED}" +                    "&is_collapsed=$isCollapsed" + +                    "&hide_label=$hideLabel"              )          }      } @@ -98,11 +110,5 @@ constructor(           * 2) new slice           */          const val VERSION = 2 - -        /** -         * Collapsed slice shows a single button, and expanded shows a row buttons. Supported since -         * [VERSION]==2. -         */ -        const val IS_COLLAPSED = false      }  } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteria.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteria.kt index 89b927480783..dc4be2696204 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteria.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteria.kt @@ -17,6 +17,7 @@  package com.android.systemui.volume.panel.component.anc.domain  import com.android.systemui.volume.panel.component.anc.domain.interactor.AncSliceInteractor +import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices  import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope  import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria  import javax.inject.Inject @@ -31,5 +32,6 @@ constructor(      private val ancSliceInteractor: AncSliceInteractor,  ) : ComponentAvailabilityCriteria { -    override fun isAvailable(): Flow<Boolean> = ancSliceInteractor.ancSlice.map { it != null } +    override fun isAvailable(): Flow<Boolean> = +        ancSliceInteractor.ancSlices.map { it is AncSlices.Ready }  } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt index 91af622074a0..cefa26907710 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt @@ -20,16 +20,19 @@ import android.app.slice.Slice.HINT_ERROR  import android.app.slice.SliceItem.FORMAT_SLICE  import androidx.slice.Slice  import com.android.systemui.volume.panel.component.anc.data.repository.AncSliceRepository +import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices  import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope  import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharedFlow  import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filter  import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.shareIn +import kotlinx.coroutines.flow.stateIn  /** Provides a valid slice from [AncSliceRepository]. */  @OptIn(ExperimentalCoroutinesApi::class) @@ -41,25 +44,35 @@ constructor(      scope: CoroutineScope,  ) { -    // Start with a positive width to check is the Slice is available. -    private val width = MutableStateFlow(1) +    // Any positive width to check if the Slice is available. +    private val buttonSliceWidth = MutableStateFlow(1) +    private val popupSliceWidth = MutableStateFlow(1) -    /** Provides a valid ANC slice. */ -    val ancSlice: SharedFlow<Slice?> = -        width -            .flatMapLatest { width -> ancSliceRepository.ancSlice(width) } -            .map { slice -> -                if (slice?.isValidSlice() == true) { -                    slice +    val ancSlices: StateFlow<AncSlices> = +        combine( +                buttonSliceWidth.flatMapLatest { +                    ancSlice(width = it, isCollapsed = true, hideLabel = true) +                }, +                popupSliceWidth.flatMapLatest { +                    ancSlice(width = it, isCollapsed = false, hideLabel = false) +                } +            ) { buttonSlice, popupSlice -> +                if (buttonSlice != null && popupSlice != null) { +                    AncSlices.Ready(buttonSlice = buttonSlice, popupSlice = popupSlice)                  } else { -                    null +                    AncSlices.Unavailable                  }              } -            .shareIn(scope, SharingStarted.Eagerly, replay = 1) +            .stateIn(scope, SharingStarted.Eagerly, AncSlices.Unavailable) -    /** Updates the width of the [ancSlice] */ -    fun changeWidth(newWidth: Int) { -        width.value = newWidth +    /** +     * Provides a valid [isCollapsed] ANC slice for a given [width]. Use [hideLabel] == true to +     * remove the labels from the [Slice]. +     */ +    private fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> { +        return ancSliceRepository +            .ancSlice(width = width, isCollapsed = isCollapsed, hideLabel = hideLabel) +            .filter { it?.isValidSlice() != false }      }      private fun Slice.isValidSlice(): Boolean { @@ -73,4 +86,20 @@ constructor(          }          return false      } + +    /** +     * Call this to update [AncSlices.Ready.popupSlice] width in a reaction to container size +     * change. +     */ +    fun onPopupSliceWidthChanged(width: Int) { +        popupSliceWidth.tryEmit(width) +    } + +    /** +     * Call this to update [AncSlices.Ready.buttonSlice] width in a reaction to container size +     * change. +     */ +    fun onButtonSliceWidthChanged(width: Int) { +        buttonSliceWidth.tryEmit(width) +    }  } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/model/AncSlices.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/model/AncSlices.kt new file mode 100644 index 000000000000..3cd4e672ce56 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/model/AncSlices.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.volume.panel.component.anc.domain.model + +import androidx.slice.Slice + +/** Modes current ANC slices state */ +sealed interface AncSlices { + +    data class Ready( +        val popupSlice: Slice, +        val buttonSlice: Slice, +    ) : AncSlices + +    /** Couldn't one or both slices. */ +    data object Unavailable : AncSlices +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt index eb96f6cad8f2..bee79bb68141 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/ui/viewmodel/AncViewModel.kt @@ -16,52 +16,56 @@  package com.android.systemui.volume.panel.component.anc.ui.viewmodel -import android.content.Context  import androidx.slice.Slice -import com.android.systemui.common.shared.model.Icon -import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.res.R +import com.android.systemui.volume.panel.component.anc.domain.AncAvailabilityCriteria  import com.android.systemui.volume.panel.component.anc.domain.interactor.AncSliceInteractor -import com.android.systemui.volume.panel.component.button.ui.viewmodel.ButtonViewModel +import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices  import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope  import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.SharingStarted  import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.filterIsInstance  import kotlinx.coroutines.flow.map  import kotlinx.coroutines.flow.stateIn  /** Volume Panel ANC component view model. */ +@OptIn(ExperimentalCoroutinesApi::class)  @VolumePanelScope  class AncViewModel  @Inject  constructor( -    @Application private val context: Context,      @VolumePanelScope private val coroutineScope: CoroutineScope,      private val interactor: AncSliceInteractor, +    private val availabilityCriteria: AncAvailabilityCriteria,  ) { +    val isAvailable: Flow<Boolean> +        get() = availabilityCriteria.isAvailable() +      /** ANC [Slice]. Null when there is no slice available for ANC. */ -    val slice: StateFlow<Slice?> = -        interactor.ancSlice.stateIn(coroutineScope, SharingStarted.Eagerly, null) +    val popupSlice: StateFlow<Slice?> = +        interactor.ancSlices +            .filterIsInstance<AncSlices.Ready>() +            .map { it.popupSlice } +            .stateIn(coroutineScope, SharingStarted.Eagerly, null) -    /** -     * ButtonViewModel to be shown in the VolumePanel. Null when there is no ANC Slice available. -     */ -    val button: StateFlow<ButtonViewModel?> = -        interactor.ancSlice -            .map { slice -> -                slice?.let { -                    ButtonViewModel( -                        Icon.Resource(R.drawable.ic_noise_aware, null), -                        context.getString(R.string.volume_panel_noise_control_title) -                    ) -                } -            } +    /** Button [Slice] to be shown in the VolumePanel. Null when there is no ANC Slice available. */ +    val buttonSlice: StateFlow<Slice?> = +        interactor.ancSlices +            .filterIsInstance<AncSlices.Ready>() +            .map { it.buttonSlice }              .stateIn(coroutineScope, SharingStarted.Eagerly, null) -    /** Call this to update [slice] width in a reaction to container size change. */ -    fun changeSliceWidth(width: Int) { -        interactor.changeWidth(width) +    /** Call this to update [popupSlice] width in a reaction to container size change. */ +    fun onPopupSliceWidthChanged(width: Int) { +        interactor.onPopupSliceWidthChanged(width) +    } + +    /** Call this to update [buttonSlice] width in a reaction to container size change. */ +    fun onButtonSliceWidthChanged(width: Int) { +        interactor.onButtonSliceWidthChanged(width)      }  } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt index 04d7b1fa6532..3ca9cdfe285c 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt @@ -18,8 +18,10 @@ package com.android.systemui.volume.panel.component.bottombar.ui.viewmodel  import android.content.Intent  import android.provider.Settings +import com.android.internal.logging.UiEventLogger  import com.android.systemui.plugins.ActivityStarter  import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent  import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel  import javax.inject.Inject @@ -29,6 +31,7 @@ class BottomBarViewModel  constructor(      private val activityStarter: ActivityStarter,      private val volumePanelViewModel: VolumePanelViewModel, +    private val uiEventLogger: UiEventLogger,  ) {      fun onDoneClicked() { @@ -36,6 +39,7 @@ constructor(      }      fun onSettingsClicked() { +        uiEventLogger.log(VolumePanelUiEvent.VOLUME_PANEL_SOUND_SETTINGS_CLICKED)          activityStarter.startActivityDismissingKeyguard(              /* intent = */ Intent(Settings.ACTION_SOUND_SETTINGS),              /* onlyProvisioned = */ false, diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/domain/CaptioningAvailabilityCriteria.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/domain/CaptioningAvailabilityCriteria.kt index aab825fb9f5e..85da1d0efe3a 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/domain/CaptioningAvailabilityCriteria.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/domain/CaptioningAvailabilityCriteria.kt @@ -16,18 +16,36 @@  package com.android.systemui.volume.panel.component.captioning.domain +import com.android.internal.logging.UiEventLogger  import com.android.settingslib.view.accessibility.domain.interactor.CaptioningInteractor  import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope  import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent  import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.shareIn  @VolumePanelScope  class CaptioningAvailabilityCriteria  @Inject -constructor(private val captioningInteractor: CaptioningInteractor) : -    ComponentAvailabilityCriteria { +constructor( +    captioningInteractor: CaptioningInteractor, +    @VolumePanelScope private val scope: CoroutineScope, +    private val uiEventLogger: UiEventLogger, +) : ComponentAvailabilityCriteria { -    override fun isAvailable(): Flow<Boolean> = +    private val availability =          captioningInteractor.isSystemAudioCaptioningUiEnabled +            .onEach { visible -> +                uiEventLogger.log( +                    if (visible) VolumePanelUiEvent.VOLUME_PANEL_LIVE_CAPTION_TOGGLE_SHOWN +                    else VolumePanelUiEvent.VOLUME_PANEL_LIVE_CAPTION_TOGGLE_GONE +                ) +            } +            .shareIn(scope, SharingStarted.WhileSubscribed(), replay = 1) + +    override fun isAvailable(): Flow<Boolean> = availability  } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModel.kt index 92f8f221d918..01421f86311f 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModel.kt @@ -17,11 +17,13 @@  package com.android.systemui.volume.panel.component.captioning.ui.viewmodel  import android.content.Context +import com.android.internal.logging.UiEventLogger  import com.android.settingslib.view.accessibility.domain.interactor.CaptioningInteractor  import com.android.systemui.common.shared.model.Icon  import com.android.systemui.res.R  import com.android.systemui.volume.panel.component.button.ui.viewmodel.ToggleButtonViewModel  import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent  import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.flow.SharingStarted @@ -38,6 +40,7 @@ constructor(      private val context: Context,      private val captioningInteractor: CaptioningInteractor,      @VolumePanelScope private val coroutineScope: CoroutineScope, +    private val uiEventLogger: UiEventLogger,  ) {      val buttonViewModel: StateFlow<ToggleButtonViewModel?> = @@ -57,6 +60,13 @@ constructor(              .stateIn(coroutineScope, SharingStarted.Eagerly, null)      fun setIsSystemAudioCaptioningEnabled(enabled: Boolean) { +        uiEventLogger.logWithPosition( +            VolumePanelUiEvent.VOLUME_PANEL_LIVE_CAPTION_TOGGLE_CLICKED, +            0, +            null, +            if (enabled) VolumePanelUiEvent.LIVE_CAPTION_TOGGLE_ENABLED +            else VolumePanelUiEvent.LIVE_CAPTION_TOGGLE_DISABLED +        )          coroutineScope.launch { captioningInteractor.setIsSystemAudioCaptioningEnabled(enabled) }      }  } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt index fc9602e6017f..6b237f8e329b 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt @@ -17,6 +17,7 @@  package com.android.systemui.volume.panel.component.mediaoutput.ui.viewmodel  import android.content.Context +import com.android.internal.logging.UiEventLogger  import com.android.systemui.animation.Expandable  import com.android.systemui.common.shared.model.Color  import com.android.systemui.common.shared.model.Icon @@ -26,6 +27,7 @@ import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor  import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor  import com.android.systemui.volume.panel.component.mediaoutput.shared.model.SessionWithPlayback  import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent  import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -48,6 +50,7 @@ constructor(      private val actionsInteractor: MediaOutputActionsInteractor,      private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor,      interactor: MediaOutputInteractor, +    private val uiEventLogger: UiEventLogger,  ) {      private val sessionWithPlayback: StateFlow<SessionWithPlayback?> = @@ -126,6 +129,7 @@ constructor(              )      fun onBarClick(expandable: Expandable) { +        uiEventLogger.log(VolumePanelUiEvent.VOLUME_PANEL_MEDIA_OUTPUT_CLICKED)          actionsInteractor.onBarClick(sessionWithPlayback.value, expandable)      }  } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioButtonViewModel.kt index 9f9275baf4f9..e5c5a655c73e 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioButtonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioButtonViewModel.kt @@ -16,13 +16,10 @@  package com.android.systemui.volume.panel.component.spatial.ui.viewmodel -import com.android.systemui.common.shared.model.Color  import com.android.systemui.volume.panel.component.button.ui.viewmodel.ToggleButtonViewModel  import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel  data class SpatialAudioButtonViewModel(      val model: SpatialAudioEnabledModel,      val button: ToggleButtonViewModel, -    val iconColor: Color, -    val labelColor: Color,  ) diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt index f022039e9cde..b5e9ed27d664 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/ui/viewmodel/SpatialAudioViewModel.kt @@ -17,7 +17,7 @@  package com.android.systemui.volume.panel.component.spatial.ui.viewmodel  import android.content.Context -import com.android.systemui.common.shared.model.Color +import com.android.internal.logging.UiEventLogger  import com.android.systemui.common.shared.model.Icon  import com.android.systemui.dagger.qualifiers.Application  import com.android.systemui.res.R @@ -29,6 +29,7 @@ import com.android.systemui.volume.panel.component.spatial.domain.interactor.Spa  import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel  import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel  import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent  import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.flow.SharingStarted @@ -46,6 +47,7 @@ constructor(      @VolumePanelScope private val scope: CoroutineScope,      availabilityCriteria: SpatialAudioAvailabilityCriteria,      private val interactor: SpatialAudioComponentInteractor, +    private val uiEventLogger: UiEventLogger,  ) {      val spatialAudioButton: StateFlow<ButtonViewModel?> = @@ -76,31 +78,25 @@ constructor(                          val isChecked = isEnabled == currentIsEnabled                          val buttonViewModel: ToggleButtonViewModel =                              isEnabled.toViewModel(isChecked) -                        SpatialAudioButtonViewModel( -                            button = buttonViewModel, -                            model = isEnabled, -                            iconColor = -                                Color.Attribute( -                                    if (isChecked) { -                                        com.android.internal.R.attr.materialColorOnPrimaryContainer -                                    } else { -                                        com.android.internal.R.attr.materialColorOnSurfaceVariant -                                    } -                                ), -                            labelColor = -                                Color.Attribute( -                                    if (isChecked) { -                                        com.android.internal.R.attr.materialColorOnSurface -                                    } else { -                                        com.android.internal.R.attr.materialColorOnSurfaceVariant -                                    } -                                ), -                        ) +                        SpatialAudioButtonViewModel(button = buttonViewModel, model = isEnabled)                      }              }              .stateIn(scope, SharingStarted.Eagerly, emptyList())      fun setEnabled(model: SpatialAudioEnabledModel) { +        uiEventLogger.logWithPosition( +            VolumePanelUiEvent.VOLUME_PANEL_SPATIAL_AUDIO_TOGGLE_CLICKED, +            0, +            null, +            when (model) { +                SpatialAudioEnabledModel.Disabled -> 0 +                SpatialAudioEnabledModel.SpatialAudioEnabled -> 1 +                SpatialAudioEnabledModel.HeadTrackingEnabled -> 2 +                else -> { +                    -1 +                } +            } +        )          scope.launch { interactor.setEnabled(model) }      } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractor.kt deleted file mode 100644 index ecd89eab1d4b..000000000000 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractor.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - *  Licensed under the Apache License, Version 2.0 (the "License"); - *  you may not use this file except in compliance with the License. - *  You may obtain a copy of the License at - * - *       http://www.apache.org/licenses/LICENSE-2.0 - * - *  Unless required by applicable law or agreed to in writing, software - *  distributed under the License is distributed on an "AS IS" BASIS, - *  WITHOUT 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.volume.panel.component.volume.domain.interactor - -import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope -import javax.inject.Inject - -/** Converts from slider value to volume and back. */ -@VolumePanelScope -class VolumeSliderInteractor @Inject constructor() { - -    /** mimic percentage volume setting */ -    private val displayValueRange: ClosedFloatingPointRange<Float> = 0f..100f - -    /** -     * Translates [volume], that belongs to [volumeRange] to the value that belongs to -     * [displayValueRange]. -     */ -    fun processVolumeToValue( -        volume: Int, -        volumeRange: ClosedRange<Int>, -    ): Float { -        val currentRangeStart: Float = volumeRange.start.toFloat() -        val targetRangeStart: Float = displayValueRange.start -        val currentRangeLength: Float = (volumeRange.endInclusive.toFloat() - currentRangeStart) -        val targetRangeLength: Float = displayValueRange.endInclusive - targetRangeStart -        if (currentRangeLength == 0f || targetRangeLength == 0f) { -            return 0f -        } -        val volumeFraction: Float = (volume.toFloat() - currentRangeStart) / currentRangeLength -        return targetRangeStart + volumeFraction * targetRangeLength -    } -} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt index 57b5d570fbbd..c8cd6fdbea70 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt @@ -18,13 +18,14 @@ package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel  import android.content.Context  import android.media.AudioManager +import com.android.internal.logging.UiEventLogger  import com.android.settingslib.volume.domain.interactor.AudioVolumeInteractor  import com.android.settingslib.volume.shared.model.AudioStream  import com.android.settingslib.volume.shared.model.AudioStreamModel  import com.android.settingslib.volume.shared.model.RingerMode  import com.android.systemui.common.shared.model.Icon  import com.android.systemui.res.R -import com.android.systemui.volume.panel.component.volume.domain.interactor.VolumeSliderInteractor +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent  import dagger.assisted.Assisted  import dagger.assisted.AssistedFactory  import dagger.assisted.AssistedInject @@ -44,7 +45,7 @@ constructor(      @Assisted private val coroutineScope: CoroutineScope,      private val context: Context,      private val audioVolumeInteractor: AudioVolumeInteractor, -    private val volumeSliderInteractor: VolumeSliderInteractor, +    private val uiEventLogger: UiEventLogger,  ) : SliderViewModel {      private val audioStream = audioStreamWrapper.audioStream @@ -71,6 +72,19 @@ constructor(              AudioStream(AudioManager.STREAM_ALARM) to R.string.stream_alarm_unavailable,              AudioStream(AudioManager.STREAM_MUSIC) to R.string.stream_media_unavailable,          ) +    private val uiEventByStream = +        mapOf( +            AudioStream(AudioManager.STREAM_MUSIC) to +                VolumePanelUiEvent.VOLUME_PANEL_MUSIC_SLIDER_TOUCHED, +            AudioStream(AudioManager.STREAM_VOICE_CALL) to +                VolumePanelUiEvent.VOLUME_PANEL_VOICE_CALL_SLIDER_TOUCHED, +            AudioStream(AudioManager.STREAM_RING) to +                VolumePanelUiEvent.VOLUME_PANEL_RING_SLIDER_TOUCHED, +            AudioStream(AudioManager.STREAM_NOTIFICATION) to +                VolumePanelUiEvent.VOLUME_PANEL_NOTIFICATION_SLIDER_TOUCHED, +            AudioStream(AudioManager.STREAM_ALARM) to +                VolumePanelUiEvent.VOLUME_PANEL_ALARM_SLIDER_TOUCHED, +        )      override val slider: StateFlow<SliderState> =          combine( @@ -90,6 +104,10 @@ constructor(          }      } +    override fun onValueChangeFinished() { +        uiEventByStream[audioStream]?.let { uiEventLogger.log(it) } +    } +      override fun toggleMuted(state: SliderState) {          val audioViewModel = state as? State          audioViewModel ?: return @@ -105,10 +123,6 @@ constructor(          return State(              value = volume.toFloat(),              valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(), -            valueText = -                SliderViewModel.formatValue( -                    volumeSliderInteractor.processVolumeToValue(volume, volumeRange) -                ),              icon = getIcon(ringerMode),              label = labelsByStream[audioStream]?.let(context::getString)                      ?: error("No label for the stream: $audioStream"), @@ -157,7 +171,6 @@ constructor(          override val valueRange: ClosedFloatingPointRange<Float>,          override val icon: Icon,          override val label: String, -        override val valueText: String,          override val disabledMessage: String?,          override val isEnabled: Boolean,          override val a11yStep: Int, diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt index 8d8fa17bf986..956ab66ac0c3 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt @@ -22,7 +22,6 @@ import com.android.systemui.common.shared.model.Icon  import com.android.systemui.res.R  import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaDeviceSessionInteractor  import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession -import com.android.systemui.volume.panel.component.volume.domain.interactor.VolumeSliderInteractor  import dagger.assisted.Assisted  import dagger.assisted.AssistedFactory  import dagger.assisted.AssistedInject @@ -41,7 +40,6 @@ constructor(      @Assisted private val coroutineScope: CoroutineScope,      private val context: Context,      private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor, -    private val volumeSliderInteractor: VolumeSliderInteractor,  ) : SliderViewModel {      override val slider: StateFlow<SliderState> = @@ -56,6 +54,8 @@ constructor(          }      } +    override fun onValueChangeFinished() {} +      override fun toggleMuted(state: SliderState) {          // do nothing because this action isn't supported for Cast sliders.      } @@ -66,13 +66,6 @@ constructor(              value = currentVolume.toFloat(),              valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(),              icon = Icon.Resource(R.drawable.ic_cast, null), -            valueText = -                SliderViewModel.formatValue( -                    volumeSliderInteractor.processVolumeToValue( -                        volume = currentVolume, -                        volumeRange = volumeRange, -                    ) -                ),              label = context.getString(R.string.media_device_cast),              isEnabled = true,              a11yStep = 1 @@ -83,13 +76,13 @@ constructor(          override val value: Float,          override val valueRange: ClosedFloatingPointRange<Float>,          override val icon: Icon, -        override val valueText: String,          override val label: String,          override val isEnabled: Boolean,          override val a11yStep: Int,      ) : SliderState {          override val disabledMessage: String?              get() = null +          override val isMutable: Boolean              get() = false      } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt index 8eb0b8947c37..d71a9d8dae94 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt @@ -28,7 +28,6 @@ sealed interface SliderState {      val valueRange: ClosedFloatingPointRange<Float>      val icon: Icon?      val isEnabled: Boolean -    val valueText: String      val label: String      /**       * A11y slider controls works by adjusting one step up or down. The default slider step isn't @@ -42,7 +41,6 @@ sealed interface SliderState {          override val value: Float = 0f          override val valueRange: ClosedFloatingPointRange<Float> = 0f..1f          override val icon: Icon? = null -        override val valueText: String = ""          override val label: String = ""          override val disabledMessage: String? = null          override val a11yStep: Int = 0 diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderViewModel.kt index e78f833086f8..7ded8c5c9fc1 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderViewModel.kt @@ -25,10 +25,7 @@ interface SliderViewModel {      fun onValueChanged(state: SliderState, newValue: Float) -    fun toggleMuted(state: SliderState) - -    companion object { +    fun onValueChangeFinished() -        fun formatValue(value: Float): String = "%.0f".format(value) -    } +    fun toggleMuted(state: SliderState)  } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/DefaultMultibindsModule.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/DefaultMultibindsModule.kt index d1d539003f93..f889ed6e06be 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/DefaultMultibindsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/DefaultMultibindsModule.kt @@ -17,6 +17,7 @@  package com.android.systemui.volume.panel.dagger  import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria +import com.android.systemui.volume.panel.domain.VolumePanelStartable  import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey  import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent  import dagger.Module @@ -31,4 +32,6 @@ interface DefaultMultibindsModule {      @Multibinds fun criteriaMap(): Map<VolumePanelComponentKey, ComponentAvailabilityCriteria>      @Multibinds fun components(): Map<VolumePanelComponentKey, VolumePanelUiComponent> + +    @Multibinds fun startables(): Set<VolumePanelStartable>  } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt index d868c33d0887..ec64f3d93012 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt @@ -16,6 +16,7 @@  package com.android.systemui.volume.panel.dagger +import com.android.systemui.volume.dagger.UiEventLoggerStartableModule  import com.android.systemui.volume.panel.component.anc.AncModule  import com.android.systemui.volume.panel.component.bottombar.BottomBarModule  import com.android.systemui.volume.panel.component.captioning.CaptioningModule @@ -25,6 +26,7 @@ import com.android.systemui.volume.panel.component.volume.VolumeSlidersModule  import com.android.systemui.volume.panel.dagger.factory.VolumePanelComponentFactory  import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope  import com.android.systemui.volume.panel.domain.DomainModule +import com.android.systemui.volume.panel.domain.VolumePanelStartable  import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractor  import com.android.systemui.volume.panel.ui.UiModule  import com.android.systemui.volume.panel.ui.composable.ComponentsFactory @@ -47,6 +49,7 @@ import kotlinx.coroutines.CoroutineScope              DefaultMultibindsModule::class,              DomainModule::class,              UiModule::class, +            UiEventLoggerStartableModule::class,              // Components modules              BottomBarModule::class,              AncModule::class, @@ -66,6 +69,8 @@ interface VolumePanelComponent {      fun componentsLayoutManager(): ComponentsLayoutManager +    fun volumePanelStartables(): Set<VolumePanelStartable> +      @Subcomponent.Factory      interface Factory : VolumePanelComponentFactory { diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/domain/VolumePanelStartable.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/domain/VolumePanelStartable.kt new file mode 100644 index 000000000000..9c39f5e75f88 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/domain/VolumePanelStartable.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.volume.panel.domain + +/** Code that needs to be run when Volume Panel is started.. */ +interface VolumePanelStartable { +    fun start() +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/VolumePanelUiEvent.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/VolumePanelUiEvent.kt new file mode 100644 index 000000000000..8b8714fcca8c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/VolumePanelUiEvent.kt @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.volume.panel.ui + +import com.android.internal.logging.UiEvent +import com.android.internal.logging.UiEventLogger + +/** UI events for Volume Panel. */ +enum class VolumePanelUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum { +    @UiEvent(doc = "The volume panel is shown") VOLUME_PANEL_SHOWN(1634), +    @UiEvent(doc = "The volume panel is gone") VOLUME_PANEL_GONE(1635), +    @UiEvent(doc = "Media output is clicked") VOLUME_PANEL_MEDIA_OUTPUT_CLICKED(1636), +    @UiEvent(doc = "Audio mode changed to normal") VOLUME_PANEL_AUDIO_MODE_CHANGE_TO_NORMAL(1680), +    @UiEvent(doc = "Audio mode changed to calling") VOLUME_PANEL_AUDIO_MODE_CHANGE_TO_CALLING(1681), +    @UiEvent(doc = "Sound settings is clicked") VOLUME_PANEL_SOUND_SETTINGS_CLICKED(1638), +    @UiEvent(doc = "The music volume slider is touched") VOLUME_PANEL_MUSIC_SLIDER_TOUCHED(1639), +    @UiEvent(doc = "The voice call volume slider is touched") +    VOLUME_PANEL_VOICE_CALL_SLIDER_TOUCHED(1640), +    @UiEvent(doc = "The ring volume slider is touched") VOLUME_PANEL_RING_SLIDER_TOUCHED(1641), +    @UiEvent(doc = "The notification volume slider is touched") +    VOLUME_PANEL_NOTIFICATION_SLIDER_TOUCHED(1642), +    @UiEvent(doc = "The alarm volume slider is touched") VOLUME_PANEL_ALARM_SLIDER_TOUCHED(1643), +    @UiEvent(doc = "Live caption toggle is shown") VOLUME_PANEL_LIVE_CAPTION_TOGGLE_SHOWN(1644), +    @UiEvent(doc = "Live caption toggle is gone") VOLUME_PANEL_LIVE_CAPTION_TOGGLE_GONE(1645), +    @UiEvent(doc = "Live caption toggle is clicked") VOLUME_PANEL_LIVE_CAPTION_TOGGLE_CLICKED(1646), +    @UiEvent(doc = "Spatial audio button is shown") VOLUME_PANEL_SPATIAL_AUDIO_BUTTON_SHOWN(1647), +    @UiEvent(doc = "Spatial audio button is gone") VOLUME_PANEL_SPATIAL_AUDIO_BUTTON_GONE(1648), +    @UiEvent(doc = "Spatial audio popup is shown") VOLUME_PANEL_SPATIAL_AUDIO_POP_UP_SHOWN(1649), +    @UiEvent(doc = "Spatial audio toggle is clicked") +    VOLUME_PANEL_SPATIAL_AUDIO_TOGGLE_CLICKED(1650), +    @UiEvent(doc = "ANC button is shown") VOLUME_PANEL_ANC_BUTTON_SHOWN(1651), +    @UiEvent(doc = "ANC button is gone") VOLUME_PANEL_ANC_BUTTON_GONE(1652), +    @UiEvent(doc = "ANC popup is shown") VOLUME_PANEL_ANC_POPUP_SHOWN(1653), +    @UiEvent(doc = "ANC toggle is clicked") VOLUME_PANEL_ANC_TOGGLE_CLICKED(1654); + +    override fun getId() = metricId + +    companion object { +        const val LIVE_CAPTION_TOGGLE_DISABLED = 0 +        const val LIVE_CAPTION_TOGGLE_ENABLED = 1 +    } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt index c728fefa77e6..ccb91ac79b6a 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/activity/VolumePanelActivity.kt @@ -21,8 +21,10 @@ import androidx.activity.ComponentActivity  import androidx.activity.compose.setContent  import androidx.activity.enableEdgeToEdge  import androidx.activity.viewModels +import com.android.internal.logging.UiEventLogger  import com.android.systemui.statusbar.policy.ConfigurationController  import com.android.systemui.volume.panel.shared.flag.VolumePanelFlag +import com.android.systemui.volume.panel.ui.VolumePanelUiEvent  import com.android.systemui.volume.panel.ui.composable.VolumePanelRoot  import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel  import javax.inject.Inject @@ -34,6 +36,7 @@ constructor(      private val volumePanelViewModelFactory: Provider<VolumePanelViewModel.Factory>,      private val volumePanelFlag: VolumePanelFlag,      private val configurationController: ConfigurationController, +    private val uiEventLogger: UiEventLogger,  ) : ComponentActivity() {      private val viewModel: VolumePanelViewModel by @@ -43,8 +46,16 @@ constructor(          enableEdgeToEdge()          super.onCreate(savedInstanceState)          volumePanelFlag.assertNewVolumePanel() - -        setContent { VolumePanelRoot(viewModel = viewModel, onDismiss = ::finish) } +        uiEventLogger.log(VolumePanelUiEvent.VOLUME_PANEL_SHOWN) +        setContent { +            VolumePanelRoot( +                viewModel = viewModel, +                onDismiss = { +                    uiEventLogger.log(VolumePanelUiEvent.VOLUME_PANEL_GONE) +                    finish() +                } +            ) +        }      }      override fun onContentChanged() { diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModel.kt index 5ae827ff4e3d..1de4fd1f9593 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModel.kt @@ -26,6 +26,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController  import com.android.systemui.statusbar.policy.onConfigChanged  import com.android.systemui.volume.panel.dagger.VolumePanelComponent  import com.android.systemui.volume.panel.dagger.factory.VolumePanelComponentFactory +import com.android.systemui.volume.panel.domain.VolumePanelStartable  import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractor  import com.android.systemui.volume.panel.ui.composable.ComponentsFactory  import com.android.systemui.volume.panel.ui.layout.ComponentsLayout @@ -109,6 +110,10 @@ class VolumePanelViewModel(                  replay = 1,              ) +    init { +        volumePanelComponent.volumePanelStartables().onEach(VolumePanelStartable::start) +    } +      fun dismissPanel() {          mutablePanelVisibility.update { false }      } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index ca55dd8ba5fa..e72027a921b7 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -142,7 +142,6 @@ class ClockEventControllerTest : SysuiTestCase() {                  context.resources,                  context,                  mainExecutor, -                IMMEDIATE,                  bgExecutor,                  clockBuffers,                  withDeps.featureFlags, @@ -320,9 +319,19 @@ class ClockEventControllerTest : SysuiTestCase() {      fun listenForDozeAmountTransition_updatesClockDozeAmount() =          runBlocking(IMMEDIATE) {              val transitionStep = MutableStateFlow(TransitionStep()) -            whenever(keyguardTransitionInteractor.lockscreenToAodTransition) +            whenever( +                    keyguardTransitionInteractor.transition( +                        KeyguardState.LOCKSCREEN, +                        KeyguardState.AOD +                    ) +                )                  .thenReturn(transitionStep) -            whenever(keyguardTransitionInteractor.aodToLockscreenTransition) +            whenever( +                    keyguardTransitionInteractor.transition( +                        KeyguardState.AOD, +                        KeyguardState.LOCKSCREEN +                    ) +                )                  .thenReturn(transitionStep)              val job = underTest.listenForDozeAmountTransition(this) @@ -362,6 +371,27 @@ class ClockEventControllerTest : SysuiTestCase() {          }      @Test +    fun listenForTransitionToLSFromOccluded_updatesClockDozeAmountToOne() = +        runBlocking(IMMEDIATE) { +            val transitionStep = MutableStateFlow(TransitionStep()) +            whenever(keyguardTransitionInteractor.transitionStepsToState(KeyguardState.LOCKSCREEN)) +                    .thenReturn(transitionStep) + +            val job = underTest.listenForAnyStateToLockscreenTransition(this) +            transitionStep.value = +                    TransitionStep( +                            from = KeyguardState.OCCLUDED, +                            to = KeyguardState.LOCKSCREEN, +                            transitionState = TransitionState.STARTED, +                    ) +            yield() + +            verify(animations, times(2)).doze(0f) + +            job.cancel() +        } + +    @Test      fun listenForTransitionToAodFromLockscreen_neverUpdatesClockDozeAmount() =          runBlocking(IMMEDIATE) {              val transitionStep = MutableStateFlow(TransitionStep()) @@ -379,6 +409,27 @@ class ClockEventControllerTest : SysuiTestCase() {              verify(animations, never()).doze(1f) +                job.cancel() +            } + +    @Test +    fun listenForAnyStateToLockscreenTransition_neverUpdatesClockDozeAmount() = +        runBlocking(IMMEDIATE) { +            val transitionStep = MutableStateFlow(TransitionStep()) +            whenever(keyguardTransitionInteractor.transitionStepsToState(KeyguardState.LOCKSCREEN)) +                    .thenReturn(transitionStep) + +            val job = underTest.listenForAnyStateToLockscreenTransition(this) +            transitionStep.value = +                    TransitionStep( +                            from = KeyguardState.AOD, +                            to = KeyguardState.LOCKSCREEN, +                            transitionState = TransitionState.STARTED, +                    ) +            yield() + +            verify(animations, never()).doze(0f) +              job.cancel()          } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index fde45d34a4fd..5af0c1f9765d 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -52,6 +52,7 @@ import static org.mockito.Mockito.atLeastOnce;  import static org.mockito.Mockito.clearInvocations;  import static org.mockito.Mockito.doNothing;  import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.inOrder;  import static org.mockito.Mockito.mock;  import static org.mockito.Mockito.never;  import static org.mockito.Mockito.spy; @@ -157,7 +158,6 @@ import org.mockito.ArgumentCaptor;  import org.mockito.Captor;  import org.mockito.InOrder;  import org.mockito.Mock; -import org.mockito.Mockito;  import org.mockito.MockitoAnnotations;  import org.mockito.MockitoSession;  import org.mockito.internal.util.reflection.FieldSetter; @@ -809,6 +809,31 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {      }      @Test +    public void whenFaceAuthenticated_biometricAuthenticatedCallback_beforeUpdatingFpState() { +        // GIVEN listening for UDFPS fingerprint +        when(mAuthController.isUdfpsSupported()).thenReturn(true); +        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON); +        mTestableLooper.processAllMessages(); +        keyguardIsVisible(); +        final CancellationSignal fpCancel = spy(mKeyguardUpdateMonitor.mFingerprintCancelSignal); +        mKeyguardUpdateMonitor.mFingerprintCancelSignal = fpCancel; + +        // WHEN face is authenticated +        when(mFaceAuthInteractor.isAuthenticated()).thenReturn(true); +        when(mFaceAuthInteractor.isFaceAuthStrong()).thenReturn(true); +        when(mFaceAuthInteractor.isLockedOut()).thenReturn(false); +        mKeyguardUpdateMonitor.onFaceAuthenticated(0, true); +        mTestableLooper.processAllMessages(); + +        // THEN verify keyguardUpdateMonitorCallback receives an onAuthenticated callback +        // before cancelling the fingerprint request +        InOrder inOrder = inOrder(mTestCallback, fpCancel); +        inOrder.verify(mTestCallback).onBiometricAuthenticated( +                eq(0), eq(BiometricSourceType.FACE), eq(true)); +        inOrder.verify(fpCancel).cancel(); +    } + +    @Test      public void whenDetectFingerprint_biometricDetectCallback() {          ArgumentCaptor<FingerprintManager.FingerprintDetectionCallback> fpDetectCallbackCaptor =                  ArgumentCaptor.forClass(FingerprintManager.FingerprintDetectionCallback.class); @@ -2133,7 +2158,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {                  null /* trustGrantedMessages */);          // THEN onTrustChanged is called FIRST -        final InOrder inOrder = Mockito.inOrder(callback); +        final InOrder inOrder = inOrder(callback);          inOrder.verify(callback).onTrustChanged(eq(mSelectedUserInteractor.getSelectedUserId()));          // AND THEN onTrustGrantedForCurrentUser callback called diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index c20367efa5da..d267ad449f45 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -1274,6 +1274,28 @@ public class ScreenDecorationsTest extends SysuiTestCase {      }      @Test +    public void delayedFaceSensorLocationChangesAddsFaceScanningOverlay() { +        setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, +                null /* roundedTopDrawable */, null /* roundedBottomDrawable */, +                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */); +        mScreenDecorations.start(); +        verifyFaceScanningViewExists(false); // face scanning view not added yet + +        // WHEN the sensor location is updated +        mFaceScanningProviders = new ArrayList<>(); +        mFaceScanningProviders.add(mFaceScanningDecorProvider); +        when(mFaceScanningProviderFactory.getProviders()).thenReturn(mFaceScanningProviders); +        when(mFaceScanningProviderFactory.getHasProviders()).thenReturn(true); +        final Point location = new Point(); +        mFakeFacePropertyRepository.setSensorLocation(location); +        mScreenDecorations.onFaceSensorLocationChanged(location); +        mExecutor.runAllReady(); + +        // THEN the face scanning view is added +        verifyFaceScanningViewExists(true); +    } + +    @Test      public void testPrivacyDotShowingListenerWorkWellWithNullParameter() {          mPrivacyDotShowingListener.onPrivacyDotShown(null);          mPrivacyDotShowingListener.onPrivacyDotHidden(null); diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java index e0764205c85a..44207a0c434b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java @@ -477,9 +477,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {          });          // Verify the method is called in -        // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once and -        // {@link Animator.AnimatorListener#onAnimationEnd} once in {@link ValueAnimator#end()} -        verify(mSpyController, times(2)).updateWindowMagnificationInternal( +        // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once +        verify(mSpyController).updateWindowMagnificationInternal(                  mScaleCaptor.capture(),                  mCenterXCaptor.capture(), mCenterYCaptor.capture(),                  mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); @@ -594,10 +593,10 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {          final float expectedY = (int) (windowBounds.exactCenterY() + expectedOffset                  - defaultMagnificationWindowSize / 2); -        // This is called 5 times when (1) first creating WindowlessMirrorWindow (2) SurfaceView is +        // This is called 4 times when (1) first creating WindowlessMirrorWindow (2) SurfaceView is          // created and we place the mirrored content as a child of the SurfaceView -        // (3) the animation starts (4) the animation updates (5) the animation ends -        verify(mTransaction, times(5)) +        // (3) the animation starts (4) the animation updates +        verify(mTransaction, times(4))                  .setPosition(any(SurfaceControl.class), eq(expectedX), eq(expectedY));      } @@ -788,9 +787,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {          waitForIdleSync();          // Verify the method is called in -        // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once and -        // {@link Animator.AnimatorListener#onAnimationEnd} once in {@link ValueAnimator#end()} -        verify(mSpyController, times(2)).updateWindowMagnificationInternal( +        // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once +        verify(mSpyController).updateWindowMagnificationInternal(                  mScaleCaptor.capture(),                  mCenterXCaptor.capture(), mCenterYCaptor.capture(),                  mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); @@ -832,10 +830,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {          deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback2);          // Verify the method is called in -        // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once and -        // {@link Animator.AnimatorListener#onAnimationEnd} once when running the animation at -        // the final duration time. -        verify(mSpyController, times(2)).updateWindowMagnificationInternal( +        // {@link ValueAnimator.AnimatorUpdateListener#onAnimationUpdate} once +        verify(mSpyController).updateWindowMagnificationInternal(                  mScaleCaptor.capture(),                  mCenterXCaptor.capture(), mCenterYCaptor.capture(),                  mOffsetXCaptor.capture(), mOffsetYCaptor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java index a88654bdbecc..01e4d58b68c2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerWindowlessMagnifierTest.java @@ -46,6 +46,7 @@ import static org.mockito.Mockito.atLeastOnce;  import static org.mockito.Mockito.doAnswer;  import static org.mockito.Mockito.mock;  import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset;  import static org.mockito.Mockito.spy;  import static org.mockito.Mockito.timeout;  import static org.mockito.Mockito.times; @@ -459,6 +460,7 @@ public class WindowMagnificationControllerWindowlessMagnifierTest extends SysuiT          final float targetCenterX = sourceBoundsCaptor.getValue().exactCenterX() + 10;          final float targetCenterY = sourceBoundsCaptor.getValue().exactCenterY() + 10; +        reset(mWindowMagnifierCallback);          mInstrumentation.runOnMainSync(() -> {              mWindowMagnificationController.moveWindowMagnifierToPosition(                      targetCenterX, targetCenterY, mAnimationCallback); @@ -491,6 +493,7 @@ public class WindowMagnificationControllerWindowlessMagnifierTest extends SysuiT          final float centerX = sourceBoundsCaptor.getValue().exactCenterX();          final float centerY = sourceBoundsCaptor.getValue().exactCenterY(); +        reset(mWindowMagnifierCallback);          mInstrumentation.runOnMainSync(() -> {              mWindowMagnificationController.moveWindowMagnifierToPosition(                      centerX + 10, centerY + 10, mAnimationCallback); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt index 33a6010d816c..8f3fed74fe97 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt @@ -15,6 +15,7 @@   */  package com.android.systemui.biometrics +import android.app.ActivityTaskManager  import android.app.admin.DevicePolicyManager  import android.content.pm.PackageManager  import android.hardware.biometrics.BiometricAuthenticator @@ -44,9 +45,12 @@ import com.android.internal.jank.InteractionJankMonitor  import com.android.internal.widget.LockPatternUtils  import com.android.systemui.Flags.FLAG_CONSTRAINT_BP  import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository  import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository  import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository  import com.android.systemui.biometrics.data.repository.FakePromptRepository +import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor +import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl  import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor  import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl  import com.android.systemui.biometrics.domain.interactor.FakeCredentialInteractor @@ -120,10 +124,12 @@ open class AuthContainerViewTest : SysuiTestCase() {      lateinit var selectedUserInteractor: SelectedUserInteractor      @Mock      private lateinit var packageManager: PackageManager +    @Mock private lateinit var activityTaskManager: ActivityTaskManager      private val testScope = TestScope(StandardTestDispatcher())      private val fakeExecutor = FakeExecutor(FakeSystemClock())      private val biometricPromptRepository = FakePromptRepository() +    private val biometricStatusRepository = FakeBiometricStatusRepository()      private val fingerprintRepository = FakeFingerprintPropertyRepository()      private val displayStateRepository = FakeDisplayStateRepository()      private val credentialInteractor = FakeCredentialInteractor() @@ -143,6 +149,7 @@ open class AuthContainerViewTest : SysuiTestCase() {      private lateinit var displayRepository: FakeDisplayRepository      private lateinit var displayStateInteractor: DisplayStateInteractor      private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor +    private lateinit var biometricStatusInteractor: BiometricStatusInteractor      private val credentialViewModel = CredentialViewModel(mContext, bpCredentialInteractor)      private val defaultLogoIcon = context.getDrawable(R.drawable.ic_android) @@ -168,6 +175,8 @@ open class AuthContainerViewTest : SysuiTestCase() {                          selectedUserInteractor,                          testScope.backgroundScope,                  ) +        biometricStatusInteractor = +                BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)          // Set up default logo icon          whenever(packageManager.getApplicationIcon(OP_PACKAGE_NAME)).thenReturn(defaultLogoIcon)          context.setMockPackageManager(packageManager) @@ -645,6 +654,7 @@ open class AuthContainerViewTest : SysuiTestCase() {              promptSelectorInteractor,              context,              udfpsOverlayInteractor, +            biometricStatusInteractor,              udfpsUtils          ),          { credentialViewModel }, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt index bf6caad688e2..31bdde2bc895 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorImplTest.kt @@ -1,13 +1,11 @@  package com.android.systemui.biometrics.domain.interactor -import android.view.Display  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository  import com.android.systemui.biometrics.shared.model.DisplayRotation  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.display.data.repository.FakeDisplayRepository -import com.android.systemui.display.data.repository.display  import com.android.systemui.unfold.compat.ScreenSizeFoldProvider  import com.android.systemui.unfold.updates.FoldProvider  import com.android.systemui.util.concurrency.FakeExecutor @@ -101,14 +99,11 @@ class DisplayStateInteractorImplTest : SysuiTestCase() {      fun isDefaultDisplayOffChanges() =          testScope.runTest {              val isDefaultDisplayOff by collectLastValue(interactor.isDefaultDisplayOff) -            runCurrent() -            displayRepository.emit(setOf(display(0, 0, Display.DEFAULT_DISPLAY, Display.STATE_OFF))) -            displayRepository.emitDisplayChangeEvent(Display.DEFAULT_DISPLAY) +            displayRepository.setDefaultDisplayOff(true)              assertThat(isDefaultDisplayOff).isTrue() -            displayRepository.emit(setOf(display(0, 0, Display.DEFAULT_DISPLAY, Display.STATE_ON))) -            displayRepository.emitDisplayChangeEvent(Display.DEFAULT_DISPLAY) +            displayRepository.setDefaultDisplayOff(false)              assertThat(isDefaultDisplayOff).isFalse()          }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt index 99c2c4076403..aff93bd339ad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt @@ -465,10 +465,34 @@ private val ROTATION_90_INPUTS =          nativeYOutsideSensor = 150f,      ) -/* ROTATION_180 is not supported. It's treated the same as ROTATION_0. */ +/* + * ROTATION_180 map: + * _ _ _ _ + * _ _ s _ + * _ _ s _ + * _ _ _ _ + * _ O _ _ + * _ _ _ _ + * + * (_) empty space + * (S) sensor + * (O) touch outside of the sensor + */ +private val ROTATION_180_NATIVE_SENSOR_BOUNDS = +    Rect( +        200, /* left */ +        100, /* top */ +        300, /* right */ +        300, /* bottom */ +    )  private val ROTATION_180_INPUTS = -    ROTATION_0_INPUTS.copy( +    OrientationBasedInputs(          rotation = Surface.ROTATION_180, +        nativeOrientation = (ORIENTATION - Math.PI.toFloat() / 2), +        nativeXWithinSensor = ROTATION_180_NATIVE_SENSOR_BOUNDS.exactCenterX(), +        nativeYWithinSensor = ROTATION_180_NATIVE_SENSOR_BOUNDS.exactCenterY(), +        nativeXOutsideSensor = 150f, +        nativeYOutsideSensor = 450f,      )  /* @@ -639,33 +663,6 @@ private fun genPositiveTestCases(      }  } -private fun genTestCasesForUnsupportedAction( -    motionEventAction: Int -): List<SinglePointerTouchProcessorTest.TestCase> { -    val isGoodOverlap = true -    val previousPointerOnSensorIds = listOf(INVALID_POINTER_ID, POINTER_ID_1) -    return previousPointerOnSensorIds.map { previousPointerOnSensorId -> -        val overlayParams = ROTATION_0_INPUTS.toOverlayParams(scaleFactor = 1f) -        val nativeX = ROTATION_0_INPUTS.getNativeX(isGoodOverlap) -        val nativeY = ROTATION_0_INPUTS.getNativeY(isGoodOverlap) -        val event = -            MOTION_EVENT.copy( -                action = motionEventAction, -                x = nativeX, -                y = nativeY, -                minor = NATIVE_MINOR, -                major = NATIVE_MAJOR, -            ) -        SinglePointerTouchProcessorTest.TestCase( -            event = event, -            currentPointers = listOf(TestPointer(id = POINTER_ID_1, onSensor = isGoodOverlap)), -            previousPointerOnSensorId = previousPointerOnSensorId, -            overlayParams = overlayParams, -            expected = TouchProcessorResult.Failure(), -        ) -    } -} -  private fun obtainMotionEvent(      action: Int,      pointerId: Int, diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt index 5b0df5d05703..a6c7f728ff3d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt @@ -16,12 +16,14 @@  package com.android.systemui.biometrics.ui.viewmodel +import android.app.ActivityTaskManager  import android.content.pm.ApplicationInfo  import android.content.pm.PackageManager  import android.content.res.Configuration  import android.graphics.Bitmap  import android.graphics.Point  import android.graphics.drawable.BitmapDrawable +import android.hardware.biometrics.BiometricFingerprintConstants  import android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT  import android.hardware.biometrics.PromptContentItemBulletedText  import android.hardware.biometrics.PromptContentView @@ -40,9 +42,12 @@ import com.android.systemui.Flags.FLAG_CONSTRAINT_BP  import com.android.systemui.SysuiTestCase  import com.android.systemui.biometrics.AuthController  import com.android.systemui.biometrics.UdfpsUtils +import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository  import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository  import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository  import com.android.systemui.biometrics.data.repository.FakePromptRepository +import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor +import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl  import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor  import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl  import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor @@ -51,6 +56,7 @@ import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor  import com.android.systemui.biometrics.extractAuthenticatorTypes  import com.android.systemui.biometrics.faceSensorPropertiesInternal  import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal +import com.android.systemui.biometrics.shared.model.AuthenticationReason  import com.android.systemui.biometrics.shared.model.BiometricModalities  import com.android.systemui.biometrics.shared.model.BiometricModality  import com.android.systemui.biometrics.shared.model.DisplayRotation @@ -59,6 +65,7 @@ import com.android.systemui.biometrics.shared.model.toSensorType  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.coroutines.collectValues  import com.android.systemui.display.data.repository.FakeDisplayRepository +import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus  import com.android.systemui.res.R  import com.android.systemui.user.domain.interactor.SelectedUserInteractor  import com.android.systemui.util.concurrency.FakeExecutor @@ -102,6 +109,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa      @Mock private lateinit var packageManager: PackageManager      @Mock private lateinit var applicationInfoWithIcon: ApplicationInfo      @Mock private lateinit var applicationInfoNoIcon: ApplicationInfo +    @Mock private lateinit var activityTaskManager: ActivityTaskManager      private val fakeExecutor = FakeExecutor(FakeSystemClock())      private val testScope = TestScope() @@ -115,9 +123,11 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa      private lateinit var fingerprintRepository: FakeFingerprintPropertyRepository      private lateinit var promptRepository: FakePromptRepository      private lateinit var displayStateRepository: FakeDisplayStateRepository +    private lateinit var biometricStatusRepository: FakeBiometricStatusRepository      private lateinit var displayRepository: FakeDisplayRepository      private lateinit var displayStateInteractor: DisplayStateInteractor      private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor +    private lateinit var biometricStatusInteractor: BiometricStatusInteractor      private lateinit var selector: PromptSelectorInteractor      private lateinit var viewModel: PromptViewModel @@ -157,6 +167,9 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa                  selectedUserInteractor,                  testScope.backgroundScope              ) +        biometricStatusRepository = FakeBiometricStatusRepository() +        biometricStatusInteractor = +            BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)          selector =              PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)          selector.resetPrompt() @@ -178,6 +191,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa                  selector,                  mContext,                  udfpsOverlayInteractor, +                biometricStatusInteractor,                  udfpsUtils              )          iconViewModel = viewModel.iconViewModel @@ -1053,8 +1067,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa      fun auto_confirm_authentication_when_finger_down() = runGenericTest {          val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false) -        // No icon button when face only, can't confirm before auth -        if (!testCase.isFaceOnly) { +        if (testCase.isCoex) {              viewModel.onOverlayTouch(obtainMotionEvent(MotionEvent.ACTION_DOWN))          }          viewModel.showAuthenticated(testCase.authenticatedModality, 0) @@ -1069,14 +1082,18 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa          assertThat(canTryAgain).isFalse()          assertThat(authenticated?.isAuthenticated).isTrue() -        if (testCase.isFaceOnly && expectConfirmation) { -            assertThat(size).isEqualTo(PromptSize.MEDIUM) -            assertButtonsVisible( -                cancel = true, -                confirm = true, -            ) +        if (expectConfirmation) { +            if (testCase.isFaceOnly) { +                assertThat(size).isEqualTo(PromptSize.MEDIUM) +                assertButtonsVisible( +                    cancel = true, +                    confirm = true, +                ) -            viewModel.confirmAuthenticated() +                viewModel.confirmAuthenticated() +            } else if (testCase.isCoex) { +                assertThat(authenticated?.isAuthenticatedAndConfirmed).isTrue() +            }              assertThat(message).isEqualTo(PromptMessage.Empty)              assertButtonsVisible()          } @@ -1086,8 +1103,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa      fun cannot_auto_confirm_authentication_when_finger_up() = runGenericTest {          val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false) -        // No icon button when face only, can't confirm before auth -        if (!testCase.isFaceOnly) { +        if (testCase.isCoex) {              viewModel.onOverlayTouch(obtainMotionEvent(MotionEvent.ACTION_DOWN))              viewModel.onOverlayTouch(obtainMotionEvent(MotionEvent.ACTION_UP))          } @@ -1413,6 +1429,12 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa              packageName = packageName,          ) +        biometricStatusRepository.setFingerprintAcquiredStatus( +            AcquiredFingerprintAuthenticationStatus( +                AuthenticationReason.BiometricPromptAuthentication, +                BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN +            ) +        )          // put the view model in the initial authenticating state, unless explicitly skipped          val startMode =              when { diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt new file mode 100644 index 000000000000..8a1a08249856 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.bluetooth.qsdialog + +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession +import com.android.dx.mockito.inline.extended.StaticMockitoSession +import com.android.settingslib.bluetooth.BluetoothUtils +import com.android.settingslib.bluetooth.CachedBluetoothDevice +import com.android.settingslib.bluetooth.LocalBluetoothManager +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.res.R +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +class AudioSharingInteractorTest : SysuiTestCase() { +    private val testDispatcher = UnconfinedTestDispatcher() +    private val testScope = TestScope(testDispatcher) +    private val bluetoothState = MutableStateFlow(false) +    private val deviceItemUpdate: MutableSharedFlow<List<DeviceItem>> = MutableSharedFlow() +    @Mock private lateinit var cachedBluetoothDevice: CachedBluetoothDevice +    @Mock private lateinit var localBluetoothManager: LocalBluetoothManager +    @Mock private lateinit var bluetoothStateInteractor: BluetoothStateInteractor +    @Mock private lateinit var deviceItemInteractor: DeviceItemInteractor +    @Mock private lateinit var deviceItem: DeviceItem +    private lateinit var mockitoSession: StaticMockitoSession +    private lateinit var audioSharingInteractor: AudioSharingInteractor + +    @Before +    fun setUp() { +        mockitoSession = +            mockitoSession().initMocks(this).mockStatic(BluetoothUtils::class.java).startMocking() +        whenever(bluetoothStateInteractor.bluetoothStateUpdate).thenReturn(bluetoothState) +        whenever(deviceItemInteractor.deviceItemUpdate).thenReturn(deviceItemUpdate) +        audioSharingInteractor = +            AudioSharingInteractor( +                localBluetoothManager, +                bluetoothStateInteractor, +                deviceItemInteractor, +                testScope.backgroundScope, +                testDispatcher, +            ) +    } + +    @After +    fun tearDown() { +        mockitoSession.finishMocking() +    } + +    @Test +    fun testButtonStateUpdate_bluetoothOff_returnGone() { +        testScope.runTest { +            val actual by collectLastValue(audioSharingInteractor.audioSharingButtonStateUpdate) + +            assertThat(actual).isEqualTo(AudioSharingButtonState.Gone) +        } +    } + +    @Test +    fun testButtonStateUpdate_noDevice_returnGone() { +        testScope.runTest { +            val actual by collectLastValue(audioSharingInteractor.audioSharingButtonStateUpdate) +            bluetoothState.value = true +            runCurrent() + +            assertThat(actual).isEqualTo(AudioSharingButtonState.Gone) +        } +    } + +    @Test +    fun testButtonStateUpdate_isBroadcasting_returnSharingAudio() { +        testScope.runTest { +            whenever(BluetoothUtils.isBroadcasting(localBluetoothManager)).thenReturn(true) + +            val actual by collectLastValue(audioSharingInteractor.audioSharingButtonStateUpdate) +            bluetoothState.value = true +            deviceItemUpdate.emit(listOf()) +            runCurrent() + +            assertThat(actual) +                .isEqualTo( +                    AudioSharingButtonState.Visible( +                        R.string.quick_settings_bluetooth_audio_sharing_button_sharing +                    ) +                ) +        } +    } + +    @Test +    fun testButtonStateUpdate_hasSource_returnGone() { +        testScope.runTest { +            whenever(BluetoothUtils.isBroadcasting(localBluetoothManager)).thenReturn(false) +            whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice) +            whenever( +                    BluetoothUtils.hasConnectedBroadcastSource( +                        cachedBluetoothDevice, +                        localBluetoothManager +                    ) +                ) +                .thenReturn(true) + +            val actual by collectLastValue(audioSharingInteractor.audioSharingButtonStateUpdate) +            bluetoothState.value = true +            deviceItemUpdate.emit(listOf(deviceItem)) +            runCurrent() + +            assertThat(actual).isEqualTo(AudioSharingButtonState.Gone) +        } +    } + +    @Test +    fun testButtonStateUpdate_hasActiveDevice_returnAudioSharing() { +        testScope.runTest { +            whenever(BluetoothUtils.isBroadcasting(localBluetoothManager)).thenReturn(false) +            whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice) +            whenever( +                    BluetoothUtils.hasConnectedBroadcastSource( +                        cachedBluetoothDevice, +                        localBluetoothManager +                    ) +                ) +                .thenReturn(false) +            whenever(BluetoothUtils.isActiveLeAudioDevice(cachedBluetoothDevice)).thenReturn(true) + +            val actual by collectLastValue(audioSharingInteractor.audioSharingButtonStateUpdate) +            bluetoothState.value = true +            deviceItemUpdate.emit(listOf(deviceItem)) +            runCurrent() + +            assertThat(actual) +                .isEqualTo( +                    AudioSharingButtonState.Visible( +                        R.string.quick_settings_bluetooth_audio_sharing_button +                    ) +                ) +        } +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt index a8f82eda51c7..6fe7d86faab8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothStateInteractorTest.kt @@ -23,6 +23,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothAdapter  import com.android.settingslib.bluetooth.LocalBluetoothManager  import com.android.systemui.SysuiTestCase  import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.StandardTestDispatcher  import kotlinx.coroutines.test.TestScope  import kotlinx.coroutines.test.runTest  import org.junit.Before @@ -41,7 +42,8 @@ import org.mockito.junit.MockitoRule  @TestableLooper.RunWithLooper(setAsMainLooper = true)  class BluetoothStateInteractorTest : SysuiTestCase() {      @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule() -    private val testScope = TestScope() +    private val testDispatcher = StandardTestDispatcher() +    private val testScope = TestScope(testDispatcher)      private lateinit var bluetoothStateInteractor: BluetoothStateInteractor @@ -52,7 +54,12 @@ class BluetoothStateInteractorTest : SysuiTestCase() {      @Before      fun setUp() {          bluetoothStateInteractor = -            BluetoothStateInteractor(localBluetoothManager, logger, testScope.backgroundScope) +            BluetoothStateInteractor( +                localBluetoothManager, +                logger, +                testScope.backgroundScope, +                testDispatcher +            )          `when`(localBluetoothManager.bluetoothAdapter).thenReturn(bluetoothAdapter)      } @@ -61,7 +68,7 @@ class BluetoothStateInteractorTest : SysuiTestCase() {          testScope.runTest {              `when`(bluetoothAdapter.isEnabled).thenReturn(true) -            assertThat(bluetoothStateInteractor.isBluetoothEnabled).isTrue() +            assertThat(bluetoothStateInteractor.isBluetoothEnabled()).isTrue()          }      } @@ -70,7 +77,7 @@ class BluetoothStateInteractorTest : SysuiTestCase() {          testScope.runTest {              `when`(bluetoothAdapter.isEnabled).thenReturn(false) -            assertThat(bluetoothStateInteractor.isBluetoothEnabled).isFalse() +            assertThat(bluetoothStateInteractor.isBluetoothEnabled()).isFalse()          }      } @@ -79,7 +86,7 @@ class BluetoothStateInteractorTest : SysuiTestCase() {          testScope.runTest {              `when`(bluetoothAdapter.isEnabled).thenReturn(false) -            bluetoothStateInteractor.isBluetoothEnabled = true +            bluetoothStateInteractor.setBluetoothEnabled(true)              verify(bluetoothAdapter).enable()              verify(logger)                  .logBluetoothState(BluetoothStateStage.BLUETOOTH_STATE_VALUE_SET, true.toString()) @@ -91,7 +98,7 @@ class BluetoothStateInteractorTest : SysuiTestCase() {          testScope.runTest {              `when`(bluetoothAdapter.isEnabled).thenReturn(false) -            bluetoothStateInteractor.isBluetoothEnabled = false +            bluetoothStateInteractor.setBluetoothEnabled(false)              verify(bluetoothAdapter, never()).enable()          }      } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt index 12dfe97649d3..62c98b05cbd5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt @@ -110,7 +110,6 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() {              BluetoothTileDialogDelegate(                  uiProperties,                  CONTENT_HEIGHT, -                ENABLED,                  bluetoothTileDialogCallback,                  {},                  dispatcher, @@ -211,7 +210,6 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() {              BluetoothTileDialogDelegate(                      uiProperties,                      CONTENT_HEIGHT, -                    ENABLED,                      bluetoothTileDialogCallback,                      {},                      dispatcher, @@ -267,7 +265,6 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() {                  BluetoothTileDialogDelegate(                          BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),                          cachedHeight, -                        ENABLED,                          bluetoothTileDialogCallback,                          {},                          dispatcher, @@ -291,7 +288,6 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() {                  BluetoothTileDialogDelegate(                          BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),                          MATCH_PARENT, -                        ENABLED,                          bluetoothTileDialogCallback,                          {},                          dispatcher, @@ -315,7 +311,6 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() {                  BluetoothTileDialogDelegate(                          BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED),                          MATCH_PARENT, -                        ENABLED,                          bluetoothTileDialogCallback,                          {},                          dispatcher, diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt index 6d99c5b62e9b..b05d9591d8a8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogViewModelTest.kt @@ -52,7 +52,6 @@ import org.junit.Before  import org.junit.Rule  import org.junit.Test  import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers  import org.mockito.ArgumentMatchers.anyInt  import org.mockito.Mock  import org.mockito.Mockito.anyBoolean @@ -74,7 +73,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {      @Mock private lateinit var bluetoothStateInteractor: BluetoothStateInteractor -    @Mock private lateinit var bluetoothAutoOnInteractor: BluetoothAutoOnInteractor +    @Mock private lateinit var audioSharingInteractor: AudioSharingInteractor      @Mock private lateinit var deviceItemInteractor: DeviceItemInteractor @@ -92,6 +91,8 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {      @Mock private lateinit var localBluetoothManager: LocalBluetoothManager +    @Mock private lateinit var bluetoothTileDialogLogger: BluetoothTileDialogLogger +      @Mock      private lateinit var mBluetoothTileDialogDelegateDelegateFactory:          BluetoothTileDialogDelegate.Factory @@ -115,7 +116,12 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {          bluetoothTileDialogViewModel =              BluetoothTileDialogViewModel(                  deviceItemInteractor, -                bluetoothStateInteractor, +                BluetoothStateInteractor( +                    localBluetoothManager, +                    bluetoothTileDialogLogger, +                    testScope.backgroundScope, +                    dispatcher +                ),                  // TODO(b/316822488): Create FakeBluetoothAutoOnInteractor.                  BluetoothAutoOnInteractor(                      BluetoothAutoOnRepository( @@ -125,6 +131,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {                          dispatcher                      )                  ), +                audioSharingInteractor,                  mDialogTransitionAnimator,                  activityStarter,                  uiEventLogger, @@ -135,20 +142,9 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {                  mBluetoothTileDialogDelegateDelegateFactory              )          whenever(deviceItemInteractor.deviceItemUpdate).thenReturn(MutableSharedFlow()) -        whenever(bluetoothStateInteractor.bluetoothStateUpdate) -            .thenReturn(MutableStateFlow(null).asStateFlow())          whenever(deviceItemInteractor.deviceItemUpdateRequest)              .thenReturn(MutableStateFlow(Unit).asStateFlow()) -        whenever(bluetoothStateInteractor.isBluetoothEnabled).thenReturn(true) -        whenever( -                mBluetoothTileDialogDelegateDelegateFactory.create( -                    any(), -                    anyInt(), -                    ArgumentMatchers.anyBoolean(), -                    any(), -                    any() -                ) -            ) +        whenever(mBluetoothTileDialogDelegateDelegateFactory.create(any(), anyInt(), any(), any()))              .thenReturn(bluetoothTileDialogDelegate)          whenever(bluetoothTileDialogDelegate.createDialog()).thenReturn(sysuiDialog)          whenever(sysuiDialog.context).thenReturn(mContext) @@ -159,6 +155,8 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {          whenever(bluetoothTileDialogDelegate.contentHeight).thenReturn(getMutableStateFlow(0))          whenever(bluetoothTileDialogDelegate.bluetoothAutoOnToggle)              .thenReturn(getMutableStateFlow(false)) +        whenever(audioSharingInteractor.audioSharingButtonStateUpdate) +            .thenReturn(getMutableStateFlow(AudioSharingButtonState.Gone))      }      @Test @@ -201,15 +199,6 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {      }      @Test -    fun testShowDialog_withBluetoothStateValue() { -        testScope.runTest { -            bluetoothTileDialogViewModel.showDialog(null) - -            verify(bluetoothStateInteractor).bluetoothStateUpdate -        } -    } - -    @Test      fun testStartSettingsActivity_activityLaunched_dialogDismissed() {          testScope.runTest {              whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice) diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt index eb735cbfec47..daf4a3cbb9de 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt @@ -1,5 +1,5 @@  /* - * Copyright (C) 2024 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project   *   * Licensed under the Apache License, Version 2.0 (the "License");   * you may not use this file except in compliance with the License. @@ -281,7 +281,7 @@ class DeviceItemInteractorTest : SysuiTestCase() {              override fun isFilterMatched(                  context: Context,                  cachedDevice: CachedBluetoothDevice, -                audioManager: AudioManager? +                audioManager: AudioManager              ) = isFilterMatchFunc(cachedDevice)              override fun create(context: Context, cachedDevice: CachedBluetoothDevice) = deviceItem diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt index dac88a340cb1..e06134bdf982 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt @@ -119,6 +119,7 @@ class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() {      fun faceAuthIsRequestedWhenLockscreenBecomesVisibleFromOffState() =          testScope.runTest {              underTest.start() +            runCurrent()              powerInteractor.setAwakeForTest(reason = PowerManager.WAKE_REASON_LID)              faceWakeUpTriggersConfig.setTriggerFaceAuthOnWakeUpFrom( @@ -160,6 +161,7 @@ class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() {      fun faceAuthIsRequestedWhenLockscreenBecomesVisibleFromAodState() =          testScope.runTest {              underTest.start() +            runCurrent()              powerInteractor.setAwakeForTest(reason = PowerManager.WAKE_REASON_LID)              faceWakeUpTriggersConfig.setTriggerFaceAuthOnWakeUpFrom( @@ -207,6 +209,7 @@ class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() {      fun faceAuthIsRequestedWhenLockscreenBecomesVisibleFromDozingState() =          testScope.runTest {              underTest.start() +            runCurrent()              powerInteractor.setAwakeForTest(reason = PowerManager.WAKE_REASON_LID)              faceWakeUpTriggersConfig.setTriggerFaceAuthOnWakeUpFrom( diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt index 806930d091b1..68d49c78c567 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt @@ -22,6 +22,7 @@ import android.testing.AndroidTestingRunner  import android.testing.TestableLooper  import android.view.Display  import android.view.Display.TYPE_EXTERNAL +import android.view.Display.TYPE_INTERNAL  import androidx.test.filters.SmallTest  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.FlowValue @@ -427,6 +428,35 @@ class DisplayRepositoryTest : SysuiTestCase() {              assertThat(display!!.type).isEqualTo(TYPE_EXTERNAL)          } +    @Test +    fun defaultDisplayOff_changes() = +        testScope.runTest { +            val defaultDisplayOff by latestDefaultDisplayOffFlowValue() +            setDisplays( +                listOf( +                    display( +                        type = TYPE_INTERNAL, +                        id = Display.DEFAULT_DISPLAY, +                        state = Display.STATE_OFF +                    ) +                ) +            ) +            displayListener.value.onDisplayChanged(Display.DEFAULT_DISPLAY) +            assertThat(defaultDisplayOff).isTrue() + +            setDisplays( +                listOf( +                    display( +                        type = TYPE_INTERNAL, +                        id = Display.DEFAULT_DISPLAY, +                        state = Display.STATE_ON +                    ) +                ) +            ) +            displayListener.value.onDisplayChanged(Display.DEFAULT_DISPLAY) +            assertThat(defaultDisplayOff).isFalse() +        } +      private fun Iterable<Display>.ids(): List<Int> = map { it.displayId }      // Wrapper to capture the displayListener. @@ -436,6 +466,13 @@ class DisplayRepositoryTest : SysuiTestCase() {          return flowValue      } +    // Wrapper to capture the displayListener. +    private fun TestScope.latestDefaultDisplayOffFlowValue(): FlowValue<Boolean?> { +        val flowValue = collectLastValue(displayRepository.defaultDisplayOff) +        captureAddedRemovedListener() +        return flowValue +    } +      private fun TestScope.lastPendingDisplay(): FlowValue<DisplayRepository.PendingDisplay?> {          val flowValue = collectLastValue(displayRepository.pendingDisplay)          captureAddedRemovedListener() diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/InputSessionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/InputSessionTest.java new file mode 100644 index 000000000000..8685384bb243 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/InputSessionTest.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.dreams.touch; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +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.platform.test.annotations.EnableFlags; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.Choreographer; +import android.view.GestureDetector; +import android.view.InputEvent; +import android.view.MotionEvent; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.Flags; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.shared.system.InputChannelCompat; +import com.android.systemui.shared.system.InputMonitorCompat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +/** + * A test suite for exercising {@link InputSession}. + */ +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper() +public class InputSessionTest extends SysuiTestCase { +    @Mock +    InputMonitorCompat mInputMonitor; + +    @Mock +    GestureDetector mGestureDetector; + +    @Mock +    InputChannelCompat.InputEventListener mInputEventListener; + +    TestableLooper mLooper; + +    @Mock +    Choreographer mChoreographer; + +    @Mock +    InputChannelCompat.InputEventReceiver mInputEventReceiver; + +    InputSession mSession; + +    InputChannelCompat.InputEventListener mEventListener; + + +    @Before +    public void setup() { +        MockitoAnnotations.initMocks(this); +        mLooper = TestableLooper.get(this); +    } + +    private void createSession(boolean pilfer) { +        when(mInputMonitor.getInputReceiver(any(), any(), any())) +                .thenReturn(mInputEventReceiver); +        mSession = new InputSession(mInputMonitor, mGestureDetector, +                mInputEventListener, mChoreographer, mLooper.getLooper(), pilfer); +        final ArgumentCaptor<InputChannelCompat.InputEventListener> listenerCaptor = +                ArgumentCaptor.forClass(InputChannelCompat.InputEventListener.class); +        verify(mInputMonitor).getInputReceiver(any(), any(), listenerCaptor.capture()); +        mEventListener = listenerCaptor.getValue(); +    } + +    /** +     * Ensures consumed motion events are pilfered when option is set. +     */ +    @Test +    public void testPilferOnMotionEventGestureConsume() { +        createSession(true); +        final MotionEvent event = Mockito.mock(MotionEvent.class); +        when(mGestureDetector.onTouchEvent(event)).thenReturn(true); +        mEventListener.onInputEvent(event); +        verify(mInputEventListener).onInputEvent(eq(event)); +        verify(mInputMonitor).pilferPointers(); +    } + +    /** +     * Ensures consumed motion events are not pilfered when option is not set. +     */ +    @Test +    public void testNoPilferOnMotionEventGestureConsume() { +        createSession(false); +        final MotionEvent event = Mockito.mock(MotionEvent.class); +        when(mGestureDetector.onTouchEvent(event)).thenReturn(true); +        mEventListener.onInputEvent(event); +        verify(mInputEventListener).onInputEvent(eq(event)); +        verify(mInputMonitor, never()).pilferPointers(); +    } + +    /** +     * Ensures input events are never pilfered. +     */ +    @Test +    public void testNoPilferOnInputEvent() { +        createSession(true); +        final InputEvent event = Mockito.mock(InputEvent.class); +        mEventListener.onInputEvent(event); +        verify(mInputEventListener).onInputEvent(eq(event)); +        verify(mInputMonitor, never()).pilferPointers(); +    } + +    @Test +    @EnableFlags(Flags.FLAG_DREAM_INPUT_SESSION_PILFER_ONCE) +    public void testPilferOnce() { +        createSession(true); +        final MotionEvent event = Mockito.mock(MotionEvent.class); +        when(mGestureDetector.onTouchEvent(event)).thenReturn(true); +        mEventListener.onInputEvent(event); +        mEventListener.onInputEvent(event); +        verify(mInputEventListener, times(2)).onInputEvent(eq(event)); +        verify(mInputMonitor, times(1)).pilferPointers(); +    } + +    /** +     * Ensures components are properly disposed. +     */ +    @Test +    public void testDispose() { +        createSession(true); +        mSession.dispose(); +        verify(mInputMonitor).dispose(); +        verify(mInputEventReceiver).dispose(); +    } +} 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 11ec417fc5f8..318227f2d1a1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -91,6 +91,7 @@ import com.android.systemui.biometrics.AuthController;  import com.android.systemui.broadcast.BroadcastDispatcher;  import com.android.systemui.classifier.FalsingCollectorFake;  import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.communal.ui.viewmodel.CommunalTransitionViewModel;  import com.android.systemui.dreams.DreamOverlayStateController;  import com.android.systemui.dreams.ui.viewmodel.DreamViewModel;  import com.android.systemui.dump.DumpManager; @@ -219,6 +220,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {      private @Mock CoroutineDispatcher mDispatcher;      private @Mock DreamViewModel mDreamViewModel; +    private @Mock CommunalTransitionViewModel mCommunalTransitionViewModel;      private @Mock SystemPropertiesHelper mSystemPropertiesHelper;      private @Mock SceneContainerFlags mSceneContainerFlags; @@ -241,6 +243,10 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {                  .thenReturn(mock(Flow.class));          when(mDreamViewModel.getTransitionEnded())                  .thenReturn(mock(Flow.class)); +        when(mCommunalTransitionViewModel.getShowByDefault()) +                .thenReturn(mock(Flow.class)); +        when(mCommunalTransitionViewModel.getTransitionFromOccludedEnded()) +                .thenReturn(mock(Flow.class));          when(mSelectedUserInteractor.getSelectedUserId()).thenReturn(mDefaultUserId);          when(mSelectedUserInteractor.getSelectedUserId(anyBoolean())).thenReturn(mDefaultUserId);          mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl( @@ -1229,6 +1235,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {                  mSystemClock,                  mDispatcher,                  () -> mDreamViewModel, +                () -> mCommunalTransitionViewModel,                  mSystemPropertiesHelper,                  () -> mock(WindowManagerLockscreenVisibilityManager.class),                  mSelectedUserInteractor, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt index 2b51863117e9..b0aace6f650e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt @@ -15,6 +15,8 @@ import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepos  import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory  import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor  import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope  import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest  import com.android.systemui.power.domain.interactor.powerInteractor  import com.android.systemui.testKosmos @@ -22,7 +24,6 @@ import com.android.systemui.util.mockito.any  import com.android.systemui.utils.GlobalWindowManager  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.UnconfinedTestDispatcher  import kotlinx.coroutines.test.runCurrent  import kotlinx.coroutines.test.runTest  import org.junit.Before @@ -42,8 +43,7 @@ import org.mockito.MockitoAnnotations  class ResourceTrimmerTest : SysuiTestCase() {      val kosmos = testKosmos() -    private val testDispatcher = UnconfinedTestDispatcher() -    private val testScope = TestScope(testDispatcher) +    private val testScope = kosmos.testScope      private val keyguardRepository = kosmos.fakeKeyguardRepository      private val featureFlags = kosmos.fakeFeatureFlagsClassic      private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository @@ -74,7 +74,7 @@ class ResourceTrimmerTest : SysuiTestCase() {                  kosmos.keyguardTransitionInteractor,                  globalWindowManager,                  testScope.backgroundScope, -                testDispatcher, +                kosmos.testDispatcher,                  featureFlags              )          resourceTrimmer.start() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryTest.kt index d75cbec8c542..d52e911d31f9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepositoryTest.kt @@ -21,7 +21,10 @@ import androidx.test.filters.SmallTest  import com.android.keyguard.ClockEventController  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.flags.FakeFeatureFlagsClassic +import com.android.systemui.flags.Flags  import com.android.systemui.keyguard.shared.model.SettingsClockSize +import com.android.systemui.res.R  import com.android.systemui.shared.clocks.ClockRegistry  import com.android.systemui.util.settings.FakeSettings  import com.google.common.truth.Truth @@ -49,6 +52,7 @@ class KeyguardClockRepositoryTest : SysuiTestCase() {      private lateinit var fakeSettings: FakeSettings      @Mock private lateinit var clockRegistry: ClockRegistry      @Mock private lateinit var clockEventController: ClockEventController +    private val fakeFeatureFlagsClassic = FakeFeatureFlagsClassic()      @Before      fun setup() { @@ -63,7 +67,9 @@ class KeyguardClockRepositoryTest : SysuiTestCase() {                  clockRegistry,                  clockEventController,                  dispatcher, -                scope.backgroundScope +                scope.backgroundScope, +                context, +                fakeFeatureFlagsClassic,              )      } @@ -82,4 +88,12 @@ class KeyguardClockRepositoryTest : SysuiTestCase() {              val value = collectLastValue(underTest.selectedClockSize)              Truth.assertThat(value()).isEqualTo(SettingsClockSize.DYNAMIC)          } + +    @Test +    fun testShouldForceSmallClock() = +        scope.runTest { +            overrideResource(R.bool.force_small_clock_on_lockscreen, true) +            fakeFeatureFlagsClassic.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, true) +            Truth.assertThat(underTest.shouldForceSmallClock).isTrue() +        }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt index b6b457142a3f..4270236f761e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt @@ -27,16 +27,12 @@ import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRe  import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID  import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint  import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint  import com.android.systemui.kosmos.testScope -import com.android.systemui.plugins.clocks.ClockConfig  import com.android.systemui.plugins.clocks.ClockController  import com.android.systemui.res.R  import com.android.systemui.testKosmos -import com.android.systemui.util.mockito.whenever  import com.google.common.truth.Truth.assertThat  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.test.runCurrent @@ -103,72 +99,6 @@ class KeyguardBlueprintInteractorTest : SysuiTestCase() {      }      @Test -    @DisableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) -    fun composeLockscreenOff_DoesAppliesSplitShadeWeatherClockBlueprint() { -        testScope.runTest { -            val blueprint by collectLastValue(underTest.blueprint) -            whenever(clockController.config) -                .thenReturn( -                    ClockConfig( -                        id = "DIGITAL_CLOCK_WEATHER", -                        name = "clock", -                        description = "clock", -                    ) -                ) -            clockRepository.setCurrentClock(clockController) -            overrideResource(R.bool.config_use_split_notification_shade, true) -            configurationRepository.onConfigurationChange() -            runCurrent() - -            assertThat(blueprint?.id).isNotEqualTo(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID) -        } -    } - -    @Test -    @EnableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) -    fun testDoesAppliesSplitShadeWeatherClockBlueprint() { -        testScope.runTest { -            val blueprint by collectLastValue(underTest.blueprint) -            whenever(clockController.config) -                .thenReturn( -                    ClockConfig( -                        id = "DIGITAL_CLOCK_WEATHER", -                        name = "clock", -                        description = "clock", -                    ) -                ) -            clockRepository.setCurrentClock(clockController) -            overrideResource(R.bool.config_use_split_notification_shade, true) -            configurationRepository.onConfigurationChange() -            runCurrent() - -            assertThat(blueprint?.id).isEqualTo(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID) -        } -    } - -    @Test -    @EnableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) -    fun testAppliesWeatherClockBlueprint() { -        testScope.runTest { -            val blueprint by collectLastValue(underTest.blueprint) -            whenever(clockController.config) -                .thenReturn( -                    ClockConfig( -                        id = "DIGITAL_CLOCK_WEATHER", -                        name = "clock", -                        description = "clock", -                    ) -                ) -            clockRepository.setCurrentClock(clockController) -            overrideResource(R.bool.config_use_split_notification_shade, false) -            configurationRepository.onConfigurationChange() -            runCurrent() - -            assertThat(blueprint?.id).isEqualTo(WEATHER_CLOCK_BLUEPRINT_ID) -        } -    } - -    @Test      @EnableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)      fun testDoesNotApplySplitShadeBlueprint() {          testScope.runTest { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index 2c0a518350da..085b70e61339 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -27,6 +27,8 @@ import com.android.systemui.SysuiTestCase  import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository  import com.android.systemui.communal.domain.interactor.communalInteractor  import com.android.systemui.communal.shared.model.CommunalScenes +import com.android.systemui.dock.DockManager +import com.android.systemui.dock.fakeDockManager  import com.android.systemui.flags.FakeFeatureFlags  import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository  import com.android.systemui.keyguard.data.repository.fakeCommandQueue @@ -108,6 +110,7 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {      private val powerInteractor = kosmos.powerInteractor      private val communalInteractor = kosmos.communalInteractor +    private val dockManager = kosmos.fakeDockManager      @Before      fun setUp() { @@ -1230,6 +1233,38 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {          }      @Test +    fun occludedToGlanceableHubWhenDocked() = +        testScope.runTest { +            // GIVEN a device on lockscreen +            keyguardRepository.setKeyguardShowing(true) +            runCurrent() + +            // GIVEN a prior transition has run to OCCLUDED +            runTransitionAndSetWakefulness(KeyguardState.GLANCEABLE_HUB, KeyguardState.OCCLUDED) +            keyguardRepository.setKeyguardOccluded(true) +            runCurrent() + +            // GIVEN device is docked +            dockManager.setIsDocked(true) +            dockManager.setDockEvent(DockManager.STATE_DOCKED) + +            // WHEN occlusion ends +            keyguardRepository.setKeyguardOccluded(false) +            runCurrent() + +            // THEN a transition to GLANCEABLE_HUB should occur +            assertThat(transitionRepository) +                .startedTransition( +                    ownerName = FromOccludedTransitionInteractor::class.simpleName, +                    from = KeyguardState.OCCLUDED, +                    to = KeyguardState.GLANCEABLE_HUB, +                    animatorAssertion = { it.isNotNull() }, +                ) + +            coroutineContext.cancelChildren() +        } + +    @Test      fun occludedToAlternateBouncer() =          testScope.runTest {              // GIVEN a prior transition has run to OCCLUDED @@ -1354,6 +1389,30 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {          }      @Test +    fun dreamingToPrimaryBouncer() = +        testScope.runTest { +            // GIVEN a prior transition has run to DREAMING +            keyguardRepository.setDreaming(true) +            runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.DREAMING) +            runCurrent() + +            // WHEN the primary bouncer is set to show +            bouncerRepository.setPrimaryShow(true) +            runCurrent() + +            // THEN a transition to PRIMARY_BOUNCER should occur +            assertThat(transitionRepository) +                .startedTransition( +                    ownerName = "FromDreamingTransitionInteractor", +                    from = KeyguardState.DREAMING, +                    to = KeyguardState.PRIMARY_BOUNCER, +                    animatorAssertion = { it.isNotNull() }, +                ) + +            coroutineContext.cancelChildren() +        } + +    @Test      fun dreamingToAod() =          testScope.runTest {              // GIVEN a prior transition has run to DREAMING diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt index 6d605a564022..b1a8dd1d3fdc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt @@ -281,6 +281,14 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() {              // Oh no, we're still surfaceBehindAnimating=true, but no longer transitioning to GONE.              transitionRepository.sendTransitionStep(                  TransitionStep( +                    transitionState = TransitionState.CANCELED, +                    from = KeyguardState.LOCKSCREEN, +                    to = KeyguardState.GONE, +                ) +            ) +            runCurrent() +            transitionRepository.sendTransitionStep( +                TransitionStep(                      transitionState = TransitionState.STARTED,                      from = KeyguardState.LOCKSCREEN,                      to = KeyguardState.AOD, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt index b5f668cef08c..4f2b690f9fcd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt @@ -38,7 +38,6 @@ import com.android.systemui.shade.NotificationPanelView  import com.android.systemui.statusbar.VibratorHelper  import com.android.systemui.util.mockito.whenever  import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.CoroutineDispatcher  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.test.TestScope @@ -86,7 +85,6 @@ class DefaultDeviceEntrySectionTest : SysuiTestCase() {                  { mock(DeviceEntryBackgroundViewModel::class.java) },                  { falsingManager },                  { mock(VibratorHelper::class.java) }, -                mock(CoroutineDispatcher::class.java),              )      } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt index 143c4dacb6be..1396b20a800d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt @@ -57,11 +57,18 @@ class AlternateBouncerWindowViewModelTest : SysuiTestCase() {                      stepFromAlternateBouncer(0f, TransitionState.STARTED),                      stepFromAlternateBouncer(.4f),                      stepFromAlternateBouncer(.6f), -                    stepFromAlternateBouncer(1f),                  ),                  testScope,              )              assertThat(alternateBouncerWindowRequired).isTrue() + +            transitionRepository.sendTransitionSteps( +                listOf( +                    stepFromAlternateBouncer(1.0f, TransitionState.FINISHED), +                ), +                testScope, +            ) +            assertThat(alternateBouncerWindowRequired).isFalse()          }      @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt index 7b5dd1fc6c7a..01754c4b5598 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt @@ -1,5 +1,5 @@  /* - * Copyright (C) 2023 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project   *   * Licensed under the Apache License, Version 2.0 (the "License");   * you may not use this file except in compliance with the License. @@ -12,191 +12,235 @@   * WITHOUT 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.keyguard.ui.viewmodel -import android.provider.Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags  import androidx.test.filters.SmallTest -import com.android.keyguard.ClockEventController -import com.android.keyguard.KeyguardClockSwitch.LARGE -import com.android.keyguard.KeyguardClockSwitch.SMALL +import com.android.keyguard.KeyguardClockSwitch +import com.android.systemui.Flags  import com.android.systemui.SysuiTestCase  import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.keyguard.data.repository.KeyguardClockRepository -import com.android.systemui.keyguard.data.repository.KeyguardClockRepositoryImpl -import com.android.systemui.keyguard.data.repository.KeyguardRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory -import com.android.systemui.keyguard.shared.ComposeLockscreen +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository +import com.android.systemui.keyguard.data.repository.keyguardClockRepository +import com.android.systemui.keyguard.data.repository.keyguardRepository +import com.android.systemui.keyguard.shared.model.SettingsClockSize +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope  import com.android.systemui.plugins.clocks.ClockController  import com.android.systemui.plugins.clocks.ClockFaceConfig  import com.android.systemui.plugins.clocks.ClockFaceController  import com.android.systemui.res.R -import com.android.systemui.shade.domain.interactor.ShadeInteractor +import com.android.systemui.shade.data.repository.shadeRepository  import com.android.systemui.shade.shared.model.ShadeMode -import com.android.systemui.shared.clocks.ClockRegistry -import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor +import com.android.systemui.testKosmos  import com.android.systemui.util.Utils  import com.android.systemui.util.mockito.whenever -import com.android.systemui.util.settings.FakeSettings  import com.google.common.truth.Truth.assertThat  import kotlin.test.Test -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.test.StandardTestDispatcher -import kotlinx.coroutines.test.TestCoroutineScheduler  import kotlinx.coroutines.test.TestScope  import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.runner.RunWith  import org.junit.runners.JUnit4 -import org.mockito.Mock -import org.mockito.MockitoAnnotations +import org.mockito.Mockito.mock  @SmallTest  @RunWith(JUnit4::class) +@DisableSceneContainer  class KeyguardClockViewModelTest : SysuiTestCase() { -    private lateinit var scheduler: TestCoroutineScheduler -    private lateinit var dispatcher: CoroutineDispatcher -    private lateinit var scope: TestScope +    private lateinit var kosmos: Kosmos      private lateinit var underTest: KeyguardClockViewModel -    private lateinit var keyguardInteractor: KeyguardInteractor -    private lateinit var keyguardRepository: KeyguardRepository -    private lateinit var keyguardClockInteractor: KeyguardClockInteractor -    private lateinit var keyguardClockRepository: KeyguardClockRepository -    private lateinit var fakeSettings: FakeSettings -    private val shadeMode = MutableStateFlow<ShadeMode>(ShadeMode.Single) -    @Mock private lateinit var clockRegistry: ClockRegistry -    @Mock private lateinit var clock: ClockController -    @Mock private lateinit var largeClock: ClockFaceController -    @Mock private lateinit var clockFaceConfig: ClockFaceConfig -    @Mock private lateinit var eventController: ClockEventController -    @Mock private lateinit var notifsKeyguardInteractor: NotificationsKeyguardInteractor -    @Mock private lateinit var areNotificationsFullyHidden: Flow<Boolean> -    @Mock private lateinit var shadeInteractor: ShadeInteractor +    private lateinit var testScope: TestScope +    private lateinit var clockController: ClockController +    private lateinit var config: ClockFaceConfig      @Before      fun setup() { -        MockitoAnnotations.initMocks(this) -        KeyguardInteractorFactory.create().let { -            keyguardInteractor = it.keyguardInteractor -            keyguardRepository = it.repository -        } -        fakeSettings = FakeSettings() -        scheduler = TestCoroutineScheduler() -        dispatcher = StandardTestDispatcher(scheduler) -        scope = TestScope(dispatcher) -        setupMockClock() -        keyguardClockRepository = -            KeyguardClockRepositoryImpl( -                fakeSettings, -                clockRegistry, -                eventController, -                dispatcher, -                scope.backgroundScope -            ) -        keyguardClockInteractor = KeyguardClockInteractor(keyguardClockRepository) -        whenever(notifsKeyguardInteractor.areNotificationsFullyHidden) -            .thenReturn(areNotificationsFullyHidden) -        whenever(shadeInteractor.shadeMode).thenReturn(shadeMode) -        underTest = -            KeyguardClockViewModel( -                keyguardInteractor, -                keyguardClockInteractor, -                scope.backgroundScope, -                notifsKeyguardInteractor, -                shadeInteractor, -            ) +        kosmos = testKosmos() +        testScope = kosmos.testScope +        underTest = kosmos.keyguardClockViewModel + +        clockController = mock(ClockController::class.java) +        val largeClock = mock(ClockFaceController::class.java) +        config = mock(ClockFaceConfig::class.java) + +        whenever(clockController.largeClock).thenReturn(largeClock) +        whenever(largeClock.config).thenReturn(config)      }      @Test -    fun testClockSize_alwaysSmallClock() = -        scope.runTest { -            // When use double line clock is disabled, -            // should always return small -            fakeSettings.putInt(LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 0) -            keyguardClockRepository.setClockSize(LARGE) -            val value = collectLastValue(underTest.clockSize) -            assertThat(value()).isEqualTo(SMALL) +    fun currentClockLayout_splitShadeOn_clockCentered_largeClock() = +        testScope.runTest { +            with(kosmos) { +                shadeRepository.setShadeMode(ShadeMode.Split) +                keyguardRepository.setClockShouldBeCentered(true) +                keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) +            } +            val currentClockLayout by collectLastValue(underTest.currentClockLayout) +            assertThat(currentClockLayout).isEqualTo(KeyguardClockViewModel.ClockLayout.LARGE_CLOCK) +        } + +    @Test +    fun currentClockLayout_splitShadeOn_clockNotCentered_largeClock_splitShadeLargeClock() = +        testScope.runTest { +            with(kosmos) { +                shadeRepository.setShadeMode(ShadeMode.Split) +                keyguardRepository.setClockShouldBeCentered(false) +                keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) +            } +            val currentClockLayout by collectLastValue(underTest.currentClockLayout) +            assertThat(currentClockLayout) +                .isEqualTo(KeyguardClockViewModel.ClockLayout.SPLIT_SHADE_LARGE_CLOCK) +        } + +    @Test +    fun currentClockLayout_splitShadeOn_clockNotCentered_smallClock_splitShadeSmallClock() = +        testScope.runTest { +            with(kosmos) { +                shadeRepository.setShadeMode(ShadeMode.Split) +                keyguardRepository.setClockShouldBeCentered(false) +                keyguardClockRepository.setClockSize(KeyguardClockSwitch.SMALL) +            } +            val currentClockLayout by collectLastValue(underTest.currentClockLayout) +            assertThat(currentClockLayout) +                .isEqualTo(KeyguardClockViewModel.ClockLayout.SPLIT_SHADE_SMALL_CLOCK) +        } + +    @Test +    fun currentClockLayout_singleShade_smallClock_smallClock() = +        testScope.runTest { +            with(kosmos) { +                shadeRepository.setShadeMode(ShadeMode.Single) +                keyguardClockRepository.setClockSize(KeyguardClockSwitch.SMALL) +            } +            val currentClockLayout by collectLastValue(underTest.currentClockLayout) +            assertThat(currentClockLayout).isEqualTo(KeyguardClockViewModel.ClockLayout.SMALL_CLOCK) +        } + +    @Test +    fun currentClockLayout_singleShade_largeClock_largeClock() = +        testScope.runTest { +            with(kosmos) { +                shadeRepository.setShadeMode(ShadeMode.Single) +                keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) +            } +            val currentClockLayout by collectLastValue(underTest.currentClockLayout) +            assertThat(currentClockLayout).isEqualTo(KeyguardClockViewModel.ClockLayout.LARGE_CLOCK) +        } + +    @Test +    fun hasCustomPositionUpdatedAnimation_withConfigTrue_isTrue() = +        testScope.runTest { +            with(kosmos) { +                keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) +                whenever(config.hasCustomPositionUpdatedAnimation).thenReturn(true) +                fakeKeyguardClockRepository.setCurrentClock(clockController) +            } + +            val hasCustomPositionUpdatedAnimation by +                collectLastValue(underTest.hasCustomPositionUpdatedAnimation) +            assertThat(hasCustomPositionUpdatedAnimation).isEqualTo(true) +        } + +    @Test +    fun hasCustomPositionUpdatedAnimation_withConfigFalse_isFalse() = +        testScope.runTest { +            with(kosmos) { +                keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) + +                whenever(config.hasCustomPositionUpdatedAnimation).thenReturn(false) +                fakeKeyguardClockRepository.setCurrentClock(clockController) +            } + +            val hasCustomPositionUpdatedAnimation by +                collectLastValue(underTest.hasCustomPositionUpdatedAnimation) +            assertThat(hasCustomPositionUpdatedAnimation).isEqualTo(false) +        } + +    @Test +    fun testClockSize_alwaysSmallClockSize() = +        testScope.runTest { +            kosmos.fakeKeyguardClockRepository.setSelectedClockSize(SettingsClockSize.SMALL) +            kosmos.keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) + +            val value by collectLastValue(underTest.clockSize) +            assertThat(value).isEqualTo(KeyguardClockSwitch.SMALL)          }      @Test      fun testClockSize_dynamicClockSize() = -        scope.runTest { -            fakeSettings.putInt(LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 1) -            keyguardClockRepository.setClockSize(SMALL) -            var value = collectLastValue(underTest.clockSize) -            assertThat(value()).isEqualTo(SMALL) - -            keyguardClockRepository.setClockSize(LARGE) -            value = collectLastValue(underTest.clockSize) -            assertThat(value()).isEqualTo(LARGE) +        testScope.runTest { +            kosmos.keyguardClockRepository.setClockSize(KeyguardClockSwitch.SMALL) +            kosmos.fakeKeyguardClockRepository.setSelectedClockSize(SettingsClockSize.DYNAMIC) +            val value by collectLastValue(underTest.clockSize) +            assertThat(value).isEqualTo(KeyguardClockSwitch.SMALL) + +            kosmos.keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) +            assertThat(value).isEqualTo(KeyguardClockSwitch.LARGE)          }      @Test      fun isLargeClockVisible_whenLargeClockSize_isTrue() = -        scope.runTest { -            fakeSettings.putInt(LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 1) -            keyguardClockRepository.setClockSize(LARGE) -            var value = collectLastValue(underTest.isLargeClockVisible) -            assertThat(value()).isEqualTo(true) +        testScope.runTest { +            kosmos.keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) +            val value by collectLastValue(underTest.isLargeClockVisible) +            assertThat(value).isEqualTo(true)          }      @Test      fun isLargeClockVisible_whenSmallClockSize_isFalse() = -        scope.runTest { -            fakeSettings.putInt(LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 1) -            keyguardClockRepository.setClockSize(SMALL) -            var value = collectLastValue(underTest.isLargeClockVisible) -            assertThat(value()).isEqualTo(false) +        testScope.runTest { +            kosmos.keyguardClockRepository.setClockSize(KeyguardClockSwitch.SMALL) +            val value by collectLastValue(underTest.isLargeClockVisible) +            assertThat(value).isEqualTo(false)          }      @Test -    fun testSmallClockTop_splitshade() = -        scope.runTest { -            shadeMode.value = ShadeMode.Split -            if (!ComposeLockscreen.isEnabled) { -                assertThat(underTest.getSmallClockTopMargin(context)) -                    .isEqualTo( -                        context.resources.getDimensionPixelSize( -                            R.dimen.keyguard_split_shade_top_margin -                        ) -                    ) -            } else { -                assertThat(underTest.getSmallClockTopMargin(context)) -                    .isEqualTo( -                        context.resources.getDimensionPixelSize( -                            R.dimen.keyguard_split_shade_top_margin -                        ) - Utils.getStatusBarHeaderHeightKeyguard(context) -                    ) -            } +    @EnableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) +    fun testSmallClockTop_splitShade_composeLockscreenOn() = +        testScope.runTest { +            kosmos.shadeRepository.setShadeMode(ShadeMode.Split) +            assertThat(underTest.getSmallClockTopMargin(context)) +                .isEqualTo( +                    context.resources.getDimensionPixelSize( +                        R.dimen.keyguard_split_shade_top_margin +                    ) - Utils.getStatusBarHeaderHeightKeyguard(context) +                )          }      @Test -    fun testSmallClockTop_nonSplitshade() = -        scope.runTest { -            if (!ComposeLockscreen.isEnabled) { -                assertThat(underTest.getSmallClockTopMargin(context)) -                    .isEqualTo( -                        context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) + -                            Utils.getStatusBarHeaderHeightKeyguard(context) -                    ) -            } else { -                assertThat(underTest.getSmallClockTopMargin(context)) -                    .isEqualTo( -                        context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) -                    ) -            } +    @DisableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) +    fun testSmallClockTop_splitShade_composeLockscreenOff() = +        testScope.runTest { +            kosmos.shadeRepository.setShadeMode(ShadeMode.Split) +            assertThat(underTest.getSmallClockTopMargin(context)) +                .isEqualTo( +                    context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin) +                )          } -    private fun setupMockClock() { -        whenever(clock.largeClock).thenReturn(largeClock) -        whenever(largeClock.config).thenReturn(clockFaceConfig) -        whenever(clockFaceConfig.hasCustomWeatherDataDisplay).thenReturn(false) -        whenever(clockRegistry.createCurrentClock()).thenReturn(clock) -    } +    @Test +    @EnableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) +    fun testSmallClockTop_nonSplitShade_composeLockscreenOn() = +        testScope.runTest { +            assertThat(underTest.getSmallClockTopMargin(context)) +                .isEqualTo( +                    context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +                ) +        } + +    @Test +    @DisableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN) +    fun testSmallClockTop_nonSplitShade_composeLockscreenOff() = +        testScope.runTest { +            assertThat(underTest.getSmallClockTopMargin(context)) +                .isEqualTo( +                    context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) + +                        Utils.getStatusBarHeaderHeightKeyguard(context) +                ) +        }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelWithKosmosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelWithKosmosTest.kt deleted file mode 100644 index d12980a74a18..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelWithKosmosTest.kt +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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.keyguard.ui.viewmodel - -import androidx.test.filters.SmallTest -import com.android.keyguard.KeyguardClockSwitch -import com.android.systemui.SysuiTestCase -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository -import com.android.systemui.keyguard.data.repository.keyguardClockRepository -import com.android.systemui.keyguard.data.repository.keyguardRepository -import com.android.systemui.kosmos.testScope -import com.android.systemui.plugins.clocks.ClockController -import com.android.systemui.plugins.clocks.ClockFaceConfig -import com.android.systemui.plugins.clocks.ClockFaceController -import com.android.systemui.shade.data.repository.shadeRepository -import com.android.systemui.shade.shared.model.ShadeMode -import com.android.systemui.testKosmos -import com.android.systemui.util.mockito.whenever -import com.google.common.truth.Truth.assertThat -import kotlin.test.Test -import kotlinx.coroutines.test.runTest -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 -import org.mockito.Mockito.mock - -@SmallTest -@RunWith(JUnit4::class) -class KeyguardClockViewModelWithKosmosTest : SysuiTestCase() { -    private val kosmos = testKosmos() -    private val underTest = kosmos.keyguardClockViewModel -    private val testScope = kosmos.testScope - -    @Test -    fun currentClockLayout_splitShadeOn_clockCentered_largeClock() = -        testScope.runTest { -            with(kosmos) { -                shadeRepository.setShadeMode(ShadeMode.Split) -                keyguardRepository.setClockShouldBeCentered(true) -                keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) -            } -            val currentClockLayout by collectLastValue(underTest.currentClockLayout) -            assertThat(currentClockLayout).isEqualTo(KeyguardClockViewModel.ClockLayout.LARGE_CLOCK) -        } - -    @Test -    fun currentClockLayout_splitShadeOn_clockNotCentered_largeClock_splitShadeLargeClock() = -        testScope.runTest { -            with(kosmos) { -                shadeRepository.setShadeMode(ShadeMode.Split) -                keyguardRepository.setClockShouldBeCentered(false) -                keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) -            } -            val currentClockLayout by collectLastValue(underTest.currentClockLayout) -            assertThat(currentClockLayout) -                .isEqualTo(KeyguardClockViewModel.ClockLayout.SPLIT_SHADE_LARGE_CLOCK) -        } - -    @Test -    fun currentClockLayout_splitShadeOn_clockNotCentered_smallClock_splitShadeSmallClock() = -        testScope.runTest { -            with(kosmos) { -                shadeRepository.setShadeMode(ShadeMode.Split) -                keyguardRepository.setClockShouldBeCentered(false) -                keyguardClockRepository.setClockSize(KeyguardClockSwitch.SMALL) -            } -            val currentClockLayout by collectLastValue(underTest.currentClockLayout) -            assertThat(currentClockLayout) -                .isEqualTo(KeyguardClockViewModel.ClockLayout.SPLIT_SHADE_SMALL_CLOCK) -        } - -    @Test -    fun currentClockLayout_singleShade_smallClock_smallClock() = -        testScope.runTest { -            with(kosmos) { -                shadeRepository.setShadeMode(ShadeMode.Single) -                keyguardClockRepository.setClockSize(KeyguardClockSwitch.SMALL) -            } -            val currentClockLayout by collectLastValue(underTest.currentClockLayout) -            assertThat(currentClockLayout).isEqualTo(KeyguardClockViewModel.ClockLayout.SMALL_CLOCK) -        } - -    @Test -    fun currentClockLayout_singleShade_largeClock_largeClock() = -        testScope.runTest { -            with(kosmos) { -                shadeRepository.setShadeMode(ShadeMode.Single) -                keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) -            } -            val currentClockLayout by collectLastValue(underTest.currentClockLayout) -            assertThat(currentClockLayout).isEqualTo(KeyguardClockViewModel.ClockLayout.LARGE_CLOCK) -        } - -    @Test -    fun hasCustomPositionUpdatedAnimation_withConfigTrue_isTrue() = -        testScope.runTest { -            with(kosmos) { -                keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) -                fakeKeyguardClockRepository.setCurrentClock( -                    buildClockController(hasCustomPositionUpdatedAnimation = true) -                ) -            } - -            val hasCustomPositionUpdatedAnimation by -                collectLastValue(underTest.hasCustomPositionUpdatedAnimation) -            assertThat(hasCustomPositionUpdatedAnimation).isEqualTo(true) -        } - -    @Test -    fun hasCustomPositionUpdatedAnimation_withConfigFalse_isFalse() = -        testScope.runTest { -            with(kosmos) { -                keyguardClockRepository.setClockSize(KeyguardClockSwitch.LARGE) -                fakeKeyguardClockRepository.setCurrentClock( -                    buildClockController(hasCustomPositionUpdatedAnimation = false) -                ) -            } - -            val hasCustomPositionUpdatedAnimation by -                collectLastValue(underTest.hasCustomPositionUpdatedAnimation) -            assertThat(hasCustomPositionUpdatedAnimation).isEqualTo(false) -        } - -    private fun buildClockController( -        hasCustomPositionUpdatedAnimation: Boolean = false -    ): ClockController { -        val clockController = mock(ClockController::class.java) -        val largeClock = mock(ClockFaceController::class.java) -        val config = mock(ClockFaceConfig::class.java) - -        whenever(clockController.largeClock).thenReturn(largeClock) -        whenever(largeClock.config).thenReturn(config) -        whenever(config.hasCustomPositionUpdatedAnimation) -            .thenReturn(hasCustomPositionUpdatedAnimation) - -        return clockController -    } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt index b70cc30eb3e1..fe8fdc042ae4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt @@ -29,7 +29,9 @@ import com.android.systemui.media.controls.MediaTestUtils  import com.android.systemui.media.controls.data.repository.MediaFilterRepository  import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_RESUME  import com.android.systemui.media.controls.shared.model.MediaData +import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel  import com.android.systemui.media.controls.shared.model.SmartspaceMediaData +import com.android.systemui.media.controls.shared.model.SmartspaceMediaLoadingModel  import com.android.systemui.media.controls.ui.controller.MediaPlayerData  import com.android.systemui.media.controls.util.MediaFlags  import com.android.systemui.media.controls.util.MediaUiEventLogger @@ -48,12 +50,10 @@ import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test  import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.anyBoolean  import org.mockito.ArgumentMatchers.anyInt  import org.mockito.ArgumentMatchers.anyLong  import org.mockito.Mock  import org.mockito.Mockito.never -import org.mockito.Mockito.reset  import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations @@ -76,7 +76,6 @@ private val SMARTSPACE_INSTANCE_ID = InstanceId.fakeInstanceId(456)!!  @TestableLooper.RunWithLooper  class MediaDataFilterImplTest : SysuiTestCase() { -    @Mock private lateinit var listener: MediaDataFilterImpl.Listener      @Mock private lateinit var userTracker: UserTracker      @Mock private lateinit var broadcastSender: BroadcastSender      @Mock private lateinit var mediaDataManager: MediaDataManager @@ -89,7 +88,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {      @Mock private lateinit var cardAction: SmartspaceAction      private lateinit var mediaDataFilter: MediaDataFilterImpl -    private lateinit var mediaFilterRepository: MediaFilterRepository +    private lateinit var repository: MediaFilterRepository      private lateinit var testScope: TestScope      private lateinit var dataMain: MediaData      private lateinit var dataGuest: MediaData @@ -102,7 +101,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {          MediaPlayerData.clear()          whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)          testScope = TestScope() -        mediaFilterRepository = MediaFilterRepository() +        repository = MediaFilterRepository()          mediaDataFilter =              MediaDataFilterImpl(                  context, @@ -113,10 +112,9 @@ class MediaDataFilterImplTest : SysuiTestCase() {                  clock,                  logger,                  mediaFlags, -                mediaFilterRepository, +                repository,              )          mediaDataFilter.mediaDataManager = mediaDataManager -        mediaDataFilter.addListener(listener)          // Start all tests as main user          setUser(USER_MAIN) @@ -162,91 +160,114 @@ class MediaDataFilterImplTest : SysuiTestCase() {      }      @Test -    fun testOnDataLoadedForCurrentUser_callsListener() { -        // GIVEN a media for main user -        mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) +    fun onDataLoadedForCurrentUser_updatesLoadedStates() = +        testScope.runTest { +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates) +            val mediaDataLoadingModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId)) -        // THEN we should tell the listener -        verify(listener).onMediaDataLoaded(eq(dataMain.instanceId), eq(true), eq(0), eq(false)) -    } +            mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) + +            assertThat(mediaDataLoadedStates).isEqualTo(mediaDataLoadingModel) +        }      @Test -    fun testOnDataLoadedForGuest_doesNotCallListener() { -        // GIVEN a media for guest user -        mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) +    fun onDataLoadedForGuest_doesNotUpdateLoadedStates() = +        testScope.runTest { +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates) +            val mediaLoadedStatesModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId)) -        // THEN we should NOT tell the listener -        verify(listener, never()).onMediaDataLoaded(any(), anyBoolean(), anyInt(), anyBoolean()) -    } +            mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) + +            assertThat(mediaDataLoadedStates).isNotEqualTo(mediaLoadedStatesModel) +        }      @Test -    fun testOnRemovedForCurrent_callsListener() { -        // GIVEN a media was removed for main user -        mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) -        mediaDataFilter.onMediaDataRemoved(KEY) +    fun onRemovedForCurrent_updatesLoadedStates() = +        testScope.runTest { +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates) +            val mediaLoadedStatesModel = +                mutableListOf(MediaDataLoadingModel.Loaded(dataMain.instanceId)) -        // THEN we should tell the listener -        verify(listener).onMediaDataRemoved(eq(dataMain.instanceId)) -    } +            // GIVEN a media was removed for main user +            mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) + +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel) + +            mediaLoadedStatesModel.remove(MediaDataLoadingModel.Loaded(dataMain.instanceId)) +            mediaDataFilter.onMediaDataRemoved(KEY) + +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel) +        }      @Test -    fun testOnRemovedForGuest_doesNotCallListener() { -        // GIVEN a media was removed for guest user -        mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) -        mediaDataFilter.onMediaDataRemoved(KEY) +    fun onRemovedForGuest_doesNotUpdateLoadedStates() = +        testScope.runTest { +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates) -        // THEN we should NOT tell the listener -        verify(listener, never()).onMediaDataRemoved(eq(dataGuest.instanceId)) -    } +            // GIVEN a media was removed for guest user +            mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) +            mediaDataFilter.onMediaDataRemoved(KEY) + +            assertThat(mediaDataLoadedStates).isEmpty() +        }      @Test -    fun testOnUserSwitched_removesOldUserControls() { -        // GIVEN that we have a media loaded for main user -        mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) +    fun onUserSwitched_removesOldUserControls() = +        testScope.runTest { +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates) +            val mediaLoadedStatesModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId)) -        // and we switch to guest user -        setUser(USER_GUEST) +            // GIVEN that we have a media loaded for main user +            mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) -        // THEN we should remove the main user's media -        verify(listener).onMediaDataRemoved(eq(dataMain.instanceId)) -    } +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel) + +            // and we switch to guest user +            setUser(USER_GUEST) + +            // THEN we should remove the main user's media +            assertThat(mediaDataLoadedStates).isEmpty() +        }      @Test -    fun testOnUserSwitched_addsNewUserControls() { -        // GIVEN that we had some media for both users -        mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) -        mediaDataFilter.onMediaDataLoaded(KEY_ALT, null, dataGuest) -        reset(listener) +    fun onUserSwitched_addsNewUserControls() = +        testScope.runTest { +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates) +            val guestLoadedStatesModel = listOf(MediaDataLoadingModel.Loaded(dataGuest.instanceId)) +            val mainLoadedStatesModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId)) -        // and we switch to guest user -        setUser(USER_GUEST) +            // GIVEN that we had some media for both users +            mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) +            mediaDataFilter.onMediaDataLoaded(KEY_ALT, null, dataGuest) -        // THEN we should add back the guest user media -        verify(listener).onMediaDataLoaded(eq(dataGuest.instanceId), eq(true), eq(0), eq(false)) +            // and we switch to guest user +            setUser(USER_GUEST) -        // but not the main user's -        verify(listener, never()) -            .onMediaDataLoaded(eq(dataMain.instanceId), anyBoolean(), anyInt(), anyBoolean()) -    } +            assertThat(mediaDataLoadedStates).isEqualTo(guestLoadedStatesModel) +            assertThat(mediaDataLoadedStates).isNotEqualTo(mainLoadedStatesModel) +        }      @Test -    fun testOnProfileChanged_profileUnavailable_loadControls() { -        // GIVEN that we had some media for both profiles -        mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) -        mediaDataFilter.onMediaDataLoaded(KEY_ALT, null, dataPrivateProfile) -        reset(listener) +    fun onProfileChanged_profileUnavailable_updateStates() = +        testScope.runTest { +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates) -        // and we change profile status -        setPrivateProfileUnavailable() +            // GIVEN that we had some media for both profiles +            mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) +            mediaDataFilter.onMediaDataLoaded(KEY_ALT, null, dataPrivateProfile) -        // THEN we should add the private profile media -        verify(listener).onMediaDataRemoved(eq(dataPrivateProfile.instanceId)) -    } +            // and we change profile status +            setPrivateProfileUnavailable() + +            val mediaLoadedStatesModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId)) +            // THEN we should remove the private profile media +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel) +        }      @Test      fun hasAnyMedia_mediaSet_returnsTrue() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries)              mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain)              assertThat(hasAnyMedia(selectedUserEntries)).isTrue() @@ -255,7 +276,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {      @Test      fun hasAnyMedia_recommendationSet_returnsFalse() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)              assertThat(hasAnyMedia(selectedUserEntries)).isFalse() @@ -264,8 +285,8 @@ class MediaDataFilterImplTest : SysuiTestCase() {      @Test      fun hasAnyMediaOrRecommendation_mediaSet_returnsTrue() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData)              mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain)              assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData)) @@ -275,8 +296,8 @@ class MediaDataFilterImplTest : SysuiTestCase() {      @Test      fun hasAnyMediaOrRecommendation_recommendationSet_returnsTrue() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)              assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData)) @@ -286,7 +307,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {      @Test      fun hasActiveMedia_inactiveMediaSet_returnsFalse() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries)              val data = dataMain.copy(active = false)              mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) @@ -297,7 +318,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {      @Test      fun hasActiveMedia_activeMediaSet_returnsTrue() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries)              val data = dataMain.copy(active = true)              mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) @@ -307,9 +328,9 @@ class MediaDataFilterImplTest : SysuiTestCase() {      @Test      fun hasActiveMediaOrRecommendation_inactiveMediaSet_returnsFalse() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId)              val data = dataMain.copy(active = false)              mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) @@ -326,9 +347,9 @@ class MediaDataFilterImplTest : SysuiTestCase() {      @Test      fun hasActiveMediaOrRecommendation_activeMediaSet_returnsTrue() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId)              val data = dataMain.copy(active = true)              mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data) @@ -345,9 +366,9 @@ class MediaDataFilterImplTest : SysuiTestCase() {      @Test      fun hasActiveMediaOrRecommendation_inactiveRecommendationSet_returnsFalse() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId)              whenever(smartspaceData.isActive).thenReturn(false)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) @@ -364,9 +385,9 @@ class MediaDataFilterImplTest : SysuiTestCase() {      @Test      fun hasActiveMediaOrRecommendation_invalidRecommendationSet_returnsFalse() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId)              whenever(smartspaceData.isValid()).thenReturn(false)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) @@ -383,9 +404,9 @@ class MediaDataFilterImplTest : SysuiTestCase() {      @Test      fun hasActiveMediaOrRecommendation_activeAndValidRecommendationSet_returnsTrue() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId)              whenever(smartspaceData.isActive).thenReturn(true)              whenever(smartspaceData.isValid()).thenReturn(true)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) @@ -401,10 +422,10 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testHasAnyMediaOrRecommendation_onlyCurrentUser() = +    fun hasAnyMediaOrRecommendation_onlyCurrentUser() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData)              assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData))                  .isFalse() @@ -415,11 +436,11 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testHasActiveMediaOrRecommendation_onlyCurrentUser() = +    fun hasActiveMediaOrRecommendation_onlyCurrentUser() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -443,10 +464,10 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testOnNotificationRemoved_doesNotHaveMedia() = +    fun onNotificationRemoved_doesNotHaveMedia() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData)              mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain)              mediaDataFilter.onMediaDataRemoved(KEY) @@ -456,7 +477,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testOnSwipeToDismiss_setsTimedOut() { +    fun onSwipeToDismiss_setsTimedOut() {          mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)          mediaDataFilter.onSwipeToDismiss() @@ -464,15 +485,19 @@ class MediaDataFilterImplTest : SysuiTestCase() {      }      @Test -    fun testOnSmartspaceMediaDataLoaded_noMedia_activeValidRec_prioritizesSmartspace() = +    fun onSmartspaceMediaDataLoaded_noMedia_activeValidRec_prioritizesSmartspace() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState) +            val recommendationsLoadingModel = +                SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY, isPrioritized = true)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) -            verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(true)) +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -487,18 +512,19 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testOnSmartspaceMediaDataLoaded_noMedia_inactiveRec_showsNothing() = +    fun onSmartspaceMediaDataLoaded_noMedia_inactiveRec_showsNothing() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState)              whenever(smartspaceData.isActive).thenReturn(false)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) -            verify(listener, never()).onMediaDataLoaded(any(), anyBoolean(), anyInt(), anyBoolean()) -            verify(listener, never()).onSmartspaceMediaDataLoaded(any(), anyBoolean()) +            assertThat(recommendationsLoadingState).isEqualTo(SmartspaceMediaLoadingModel.Unknown)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -513,17 +539,21 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testOnSmartspaceMediaDataLoaded_noRecentMedia_activeValidRec_prioritizesSmartspace() = +    fun onSmartspaceMediaDataLoaded_noRecentMedia_activeValidRec_prioritizesSmartspace() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState) +            val recommendationsLoadingModel = +                SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY, isPrioritized = true)              val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())              mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld)              clock.advanceTime(MediaDataFilterImpl.SMARTSPACE_MAX_AGE + 100)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) -            verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(true)) +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -538,11 +568,13 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testOnSmartspaceMediaDataLoaded_noRecentMedia_inactiveRec_showsNothing() = +    fun onSmartspaceMediaDataLoaded_noRecentMedia_inactiveRec_showsNothing() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState)              whenever(smartspaceData.isActive).thenReturn(false)              val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) @@ -550,7 +582,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {              clock.advanceTime(MediaDataFilterImpl.SMARTSPACE_MAX_AGE + 100)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) -            verify(listener, never()).onSmartspaceMediaDataLoaded(any(), anyBoolean()) +            assertThat(recommendationsLoadingState).isEqualTo(SmartspaceMediaLoadingModel.Unknown)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -565,27 +597,29 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_inactiveRec_showsNothing() = +    fun onSmartspaceMediaDataLoaded_hasRecentMedia_inactiveRec_showsNothing() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState) +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates)              whenever(smartspaceData.isActive).thenReturn(false)              // WHEN we have media that was recently played, but not currently active              val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) +            val mediaLoadedStatesModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId))              mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) -            verify(listener) -                .onMediaDataLoaded(eq(dataCurrent.instanceId), eq(true), eq(0), eq(false)) -            reset(listener) +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel) +              // AND we get a smartspace signal              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) -            // THEN we should tell listeners to treat the media as not active instead -            verify(listener, never()).onMediaDataLoaded(any(), anyBoolean(), anyInt(), anyBoolean()) -            verify(listener, never()).onSmartspaceMediaDataLoaded(any(), anyBoolean()) +            // THEN we should treat the media as not active instead +            assertThat(recommendationsLoadingState).isEqualTo(SmartspaceMediaLoadingModel.Unknown)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -600,27 +634,28 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_activeInvalidRec_usesMedia() = +    fun onSmartspaceMediaDataLoaded_hasRecentMedia_activeInvalidRec_usesMedia() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState) +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates)              whenever(smartspaceData.isValid()).thenReturn(false)              // WHEN we have media that was recently played, but not currently active              val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) +            val mediaLoadedStatesModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId))              mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) -            verify(listener) -                .onMediaDataLoaded(eq(dataCurrent.instanceId), eq(true), eq(0), eq(false)) +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel)              // AND we get a smartspace signal              runCurrent()              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) -            // THEN we should tell listeners to treat the media as active instead -            val dataCurrentAndActive = dataCurrent.copy(active = true) -            verify(listener) -                .onMediaDataLoaded(eq(dataCurrentAndActive.instanceId), eq(true), eq(100), eq(true)) +            // THEN we should treat the media as active instead +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -630,31 +665,35 @@ class MediaDataFilterImplTest : SysuiTestCase() {                  )                  .isTrue()              // Smartspace update shouldn't be propagated for the empty rec list. -            verify(listener, never()).onSmartspaceMediaDataLoaded(any(), anyBoolean()) +            assertThat(recommendationsLoadingState).isEqualTo(SmartspaceMediaLoadingModel.Unknown)              verify(logger, never()).logRecommendationAdded(any(), any())              verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID))          }      @Test -    fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_activeValidRec_usesBoth() = +    fun onSmartspaceMediaDataLoaded_hasRecentMedia_activeValidRec_usesBoth() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState) +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates)              // WHEN we have media that was recently played, but not currently active              val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) +            val mediaDataLoadingModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId)) +            val recommendationsLoadingModel = SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) +              mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) -            verify(listener) -                .onMediaDataLoaded(eq(dataCurrent.instanceId), eq(true), eq(0), eq(false)) + +            assertThat(mediaDataLoadedStates).isEqualTo(mediaDataLoadingModel)              // AND we get a smartspace signal              runCurrent()              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) -            // THEN we should tell listeners to treat the media as active instead -            val dataCurrentAndActive = dataCurrent.copy(active = true) -            verify(listener) -                .onMediaDataLoaded(eq(dataCurrentAndActive.instanceId), eq(true), eq(100), eq(true)) +            // THEN we should treat the media as active instead +            assertThat(mediaDataLoadedStates).isEqualTo(mediaDataLoadingModel)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -664,22 +703,25 @@ class MediaDataFilterImplTest : SysuiTestCase() {                  )                  .isTrue()              // Smartspace update should also be propagated but not prioritized. -            verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(false)) +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel)              verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)              verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID))          }      @Test -    fun testOnSmartspaceMediaDataRemoved_usedSmartspace_clearsSmartspace() = +    fun onSmartspaceMediaDataRemoved_usedSmartspace_clearsSmartspace() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState) +            val recommendationsLoadingModel = SmartspaceMediaLoadingModel.Removed(SMARTSPACE_KEY)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)              mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) -            verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -692,26 +734,28 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testOnSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBoth() = +    fun onSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBoth() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState) +            val recommendationsLoadingModel = SmartspaceMediaLoadingModel.Removed(SMARTSPACE_KEY) +            val mediaLoadedStatesModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId))              val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())              mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) -            verify(listener) -                .onMediaDataLoaded(eq(dataCurrent.instanceId), eq(true), eq(0), eq(false)) +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel)              runCurrent()              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) -            val dataCurrentAndActive = dataCurrent.copy(active = true) -            verify(listener) -                .onMediaDataLoaded(eq(dataCurrentAndActive.instanceId), eq(true), eq(100), eq(true)) +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel)              mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) -            verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -724,17 +768,20 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testOnSmartspaceLoaded_persistentEnabled_isInactive_notifiesListeners() = +    fun onSmartspaceLoaded_persistentEnabled_isInactive() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState) +            val recommendationsLoadingModel = SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY)              whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true)              whenever(smartspaceData.isActive).thenReturn(false)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) -            verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(false)) +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -748,11 +795,16 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testOnSmartspaceLoaded_persistentEnabled_inactive_hasRecentMedia_staysInactive() = +    fun onSmartspaceLoaded_persistentEnabled_inactive_hasRecentMedia_staysInactive() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState) +            val recommendationsLoadingModel = SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) +            val mediaLoadedStatesModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId))              whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true)              whenever(smartspaceData.isActive).thenReturn(false) @@ -760,16 +812,14 @@ class MediaDataFilterImplTest : SysuiTestCase() {              // If there is media that was recently played but inactive              val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())              mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) -            verify(listener) -                .onMediaDataLoaded(eq(dataCurrent.instanceId), eq(true), eq(0), eq(false)) -            reset(listener) +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel) +              // And an inactive recommendation is loaded              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)              // Smartspace is loaded but the media stays inactive -            verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(false)) -            verify(listener, never()).onMediaDataLoaded(any(), anyBoolean(), anyInt(), anyBoolean()) +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -783,7 +833,7 @@ class MediaDataFilterImplTest : SysuiTestCase() {          }      @Test -    fun testOnSwipeToDismiss_persistentEnabled_recommendationSetInactive() { +    fun onSwipeToDismiss_persistentEnabled_recommendationSetInactive() {          whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(true)          val data = @@ -802,16 +852,21 @@ class MediaDataFilterImplTest : SysuiTestCase() {      }      @Test -    fun testSmartspaceLoaded_shouldTriggerResume_doesTrigger() = +    fun smartspaceLoaded_shouldTriggerResume_doesTrigger() =          testScope.runTest { -            val selectedUserEntries by collectLastValue(mediaFilterRepository.selectedUserEntries) -            val smartspaceMediaData by collectLastValue(mediaFilterRepository.smartspaceMediaData) -            val reactivatedKey by collectLastValue(mediaFilterRepository.reactivatedId) +            val selectedUserEntries by collectLastValue(repository.selectedUserEntries) +            val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) +            val reactivatedKey by collectLastValue(repository.reactivatedId) +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState) +            val recommendationsLoadingModel = SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) +            val mediaLoadedStatesModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId))              // WHEN we have media that was recently played, but not currently active              val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())              mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) -            verify(listener) -                .onMediaDataLoaded(eq(dataCurrent.instanceId), eq(true), eq(0), eq(false)) + +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel)              // AND we get a smartspace signal with extra to trigger resume              runCurrent() @@ -819,10 +874,8 @@ class MediaDataFilterImplTest : SysuiTestCase() {              whenever(cardAction.extras).thenReturn(extras)              mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) -            // THEN we should tell listeners to treat the media as active instead -            val dataCurrentAndActive = dataCurrent.copy(active = true) -            verify(listener) -                .onMediaDataLoaded(eq(dataCurrentAndActive.instanceId), eq(true), eq(100), eq(true)) +            // THEN we should treat the media as active instead +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel)              assertThat(                      hasActiveMediaOrRecommendation(                          selectedUserEntries, @@ -831,27 +884,33 @@ class MediaDataFilterImplTest : SysuiTestCase() {                      )                  )                  .isTrue() -            // And send the smartspace data, but not prioritized -            verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(false)) +            // And update the smartspace data state, but not prioritized +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel)          }      @Test -    fun testSmartspaceLoaded_notShouldTriggerResume_doesNotTrigger() { -        // WHEN we have media that was recently played, but not currently active -        val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) -        mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) -        verify(listener).onMediaDataLoaded(eq(dataCurrent.instanceId), eq(true), eq(0), eq(false)) +    fun smartspaceLoaded_notShouldTriggerResume_doesNotTrigger() = +        testScope.runTest { +            val mediaDataLoadedStates by collectLastValue(repository.mediaDataLoadedStates) +            val recommendationsLoadingState by +                collectLastValue(repository.recommendationsLoadingState) +            val recommendationsLoadingModel = SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) +            val mediaLoadedStatesModel = listOf(MediaDataLoadingModel.Loaded(dataMain.instanceId)) -        // AND we get a smartspace signal with extra to not trigger resume -        val extras = Bundle().apply { putBoolean(EXTRA_KEY_TRIGGER_RESUME, false) } -        whenever(cardAction.extras).thenReturn(extras) -        mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) +            // WHEN we have media that was recently played, but not currently active +            val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) +            mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) -        // THEN listeners are not updated to show media -        verify(listener, never()).onMediaDataLoaded(any(), eq(true), eq(100), eq(true)) -        // But the smartspace update is still propagated -        verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(false)) -    } +            assertThat(mediaDataLoadedStates).isEqualTo(mediaLoadedStatesModel) + +            // AND we get a smartspace signal with extra to not trigger resume +            val extras = Bundle().apply { putBoolean(EXTRA_KEY_TRIGGER_RESUME, false) } +            whenever(cardAction.extras).thenReturn(extras) +            mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) + +            // But the smartspace update is still propagated +            assertThat(recommendationsLoadingState).isEqualTo(recommendationsLoadingModel) +        }      private fun hasActiveMediaOrRecommendation(          entries: Map<InstanceId, MediaData>?, diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt index 8b79fa45b8ba..253607846e0f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt @@ -258,6 +258,7 @@ class MediaProjectionAppSelectorControllerTest : SysuiTestCase() {              colorBackground = 0,              isForegroundTask = isForegroundTask,              userType = RecentTask.UserType.STANDARD, +            splitBounds = null,          )      } diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt index dd621129ad9a..6ac86f58517d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt @@ -195,6 +195,7 @@ class ShellRecentTaskListProviderTest : SysuiTestCase() {              colorBackground = null,              isForegroundTask = false,              userType = userType, +            splitBounds = null          )      private fun createSingleTask( diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt index a84008b0353c..f4c5ccfc8388 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewControllerTest.kt @@ -18,22 +18,28 @@ package com.android.systemui.mediaprojection.appselector.view  import android.app.ActivityOptions  import android.app.IActivityTaskManager +import android.graphics.Rect  import android.os.Bundle  import android.view.View  import android.view.ViewGroup  import androidx.test.filters.SmallTest  import com.android.systemui.Flags.FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX +import com.android.systemui.Flags.FLAG_PSS_APP_SELECTOR_RECENTS_SPLIT_SCREEN  import com.android.systemui.SysuiTestCase  import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler  import com.android.systemui.mediaprojection.appselector.data.RecentTask  import com.android.systemui.util.mockito.mock +import com.android.wm.shell.splitscreen.SplitScreen +import com.android.wm.shell.util.SplitBounds  import com.google.common.truth.Expect  import com.google.common.truth.Truth.assertThat +import java.util.Optional  import org.junit.Rule  import org.junit.Test  import org.mockito.ArgumentCaptor  import org.mockito.ArgumentMatchers.eq  import org.mockito.Mockito.any +import org.mockito.Mockito.anyInt  import org.mockito.Mockito.verify  @SmallTest @@ -46,9 +52,10 @@ class MediaProjectionRecentsViewControllerTest : SysuiTestCase() {      private val taskViewSizeProvider = mock<TaskPreviewSizeProvider>()      private val activityTaskManager = mock<IActivityTaskManager>()      private val resultHandler = mock<MediaProjectionAppSelectorResultHandler>() +    private val splitScreen = Optional.of(mock<SplitScreen>())      private val bundleCaptor = ArgumentCaptor.forClass(Bundle::class.java) -    private val task = +    private val fullScreenTask =          RecentTask(              taskId = 123,              displayId = 456, @@ -58,6 +65,20 @@ class MediaProjectionRecentsViewControllerTest : SysuiTestCase() {              colorBackground = null,              isForegroundTask = false,              userType = RecentTask.UserType.STANDARD, +            splitBounds = null +        ) + +    private val splitScreenTask = +        RecentTask( +            taskId = 123, +            displayId = 456, +            userId = 789, +            topActivityComponent = null, +            baseIntentComponent = null, +            colorBackground = null, +            isForegroundTask = false, +            userType = RecentTask.UserType.STANDARD, +            splitBounds = SplitBounds(Rect(), Rect(), 0, 0, 0)          )      private val taskView = @@ -70,61 +91,97 @@ class MediaProjectionRecentsViewControllerTest : SysuiTestCase() {              tasksAdapterFactory,              taskViewSizeProvider,              activityTaskManager, -            resultHandler +            resultHandler, +            splitScreen,          )      @Test -    fun onRecentAppClicked_taskWithSameIdIsStartedFromRecents() { -        controller.onRecentAppClicked(task, taskView) +    fun onRecentAppClicked_fullScreenTaskWithSameIdIsStartedFromRecents() { +        controller.onRecentAppClicked(fullScreenTask, taskView) -        verify(activityTaskManager).startActivityFromRecents(eq(task.taskId), any()) +        verify(activityTaskManager).startActivityFromRecents(eq(fullScreenTask.taskId), any()) +    } + +    @Test +    fun onRecentAppClicked_splitScreenTaskWithSameIdIsStartedFromRecents() { +        mSetFlagsRule.enableFlags(FLAG_PSS_APP_SELECTOR_RECENTS_SPLIT_SCREEN) +        controller.onRecentAppClicked(splitScreenTask, taskView) + +        verify(splitScreen.get()) +            .startTasks( +                eq(splitScreenTask.taskId), +                any(), +                anyInt(), +                any(), +                anyInt(), +                anyInt(), +                any(), +                any() +            )      }      @Test      fun onRecentAppClicked_launchDisplayIdIsSet() { -        controller.onRecentAppClicked(task, taskView) +        controller.onRecentAppClicked(fullScreenTask, taskView) -        assertThat(getStartedTaskActivityOptions().launchDisplayId).isEqualTo(task.displayId) +        assertThat(getStartedTaskActivityOptions(fullScreenTask.taskId).launchDisplayId) +            .isEqualTo(fullScreenTask.displayId)      }      @Test -    fun onRecentAppClicked_taskNotInForeground_usesScaleUpAnimation() { -        controller.onRecentAppClicked(task, taskView) +    fun onRecentAppClicked_fullScreenTaskNotInForeground_usesScaleUpAnimation() { +        assertThat(fullScreenTask.isForegroundTask).isFalse() +        controller.onRecentAppClicked(fullScreenTask, taskView) -        assertThat(getStartedTaskActivityOptions().animationType) +        assertThat(getStartedTaskActivityOptions(fullScreenTask.taskId).animationType)              .isEqualTo(ActivityOptions.ANIM_SCALE_UP)      }      @Test -    fun onRecentAppClicked_taskInForeground_flagOff_usesScaleUpAnimation() { +    fun onRecentAppClicked_fullScreenTaskInForeground_flagOff_usesScaleUpAnimation() {          mSetFlagsRule.disableFlags(FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX) -        controller.onRecentAppClicked(task, taskView) +        controller.onRecentAppClicked(fullScreenTask, taskView) -        assertThat(getStartedTaskActivityOptions().animationType) +        assertThat(getStartedTaskActivityOptions(fullScreenTask.taskId).animationType)              .isEqualTo(ActivityOptions.ANIM_SCALE_UP)      }      @Test -    fun onRecentAppClicked_taskInForeground_flagOn_usesDefaultAnimation() { +    fun onRecentAppClicked_fullScreenTaskInForeground_flagOn_usesDefaultAnimation() {          mSetFlagsRule.enableFlags(FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX) -        val foregroundTask = task.copy(isForegroundTask = true) +        assertForegroundTaskUsesDefaultCloseAnimation(fullScreenTask) +    } +    @Test +    fun onRecentAppClicked_splitScreenTaskInForeground_flagOn_usesDefaultAnimation() { +        mSetFlagsRule.enableFlags( +            FLAG_PSS_APP_SELECTOR_ABRUPT_EXIT_FIX, +            FLAG_PSS_APP_SELECTOR_RECENTS_SPLIT_SCREEN +        ) +        assertForegroundTaskUsesDefaultCloseAnimation(splitScreenTask) +    } + +    private fun assertForegroundTaskUsesDefaultCloseAnimation(task: RecentTask) { +        val foregroundTask = task.copy(isForegroundTask = true)          controller.onRecentAppClicked(foregroundTask, taskView)          expect -            .that(getStartedTaskActivityOptions().animationType) +            .that(getStartedTaskActivityOptions(foregroundTask.taskId).animationType)              .isEqualTo(ActivityOptions.ANIM_CUSTOM) -        expect.that(getStartedTaskActivityOptions().overrideTaskTransition).isTrue()          expect -            .that(getStartedTaskActivityOptions().customExitResId) +            .that(getStartedTaskActivityOptions(foregroundTask.taskId).overrideTaskTransition) +            .isTrue() +        expect +            .that(getStartedTaskActivityOptions(foregroundTask.taskId).customExitResId)              .isEqualTo(com.android.internal.R.anim.resolver_close_anim) -        expect.that(getStartedTaskActivityOptions().customEnterResId).isEqualTo(0) +        expect +            .that(getStartedTaskActivityOptions(foregroundTask.taskId).customEnterResId) +            .isEqualTo(0)      } -    private fun getStartedTaskActivityOptions(): ActivityOptions { -        verify(activityTaskManager) -            .startActivityFromRecents(eq(task.taskId), bundleCaptor.capture()) +    private fun getStartedTaskActivityOptions(taskId: Int): ActivityOptions { +        verify(activityTaskManager).startActivityFromRecents(eq(taskId), bundleCaptor.capture())          return ActivityOptions.fromBundle(bundleCaptor.value)      }  } diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt new file mode 100644 index 000000000000..e044eeca8303 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.mediaprojection.permission + +import android.app.AlertDialog +import android.media.projection.MediaProjectionConfig +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.view.WindowManager +import android.widget.Spinner +import android.widget.TextView +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.flags.Flags +import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger +import com.android.systemui.res.R +import com.android.systemui.statusbar.phone.AlertDialogWithDelegate +import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.util.mockito.mock +import junit.framework.Assert.assertEquals +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.`when` as whenever + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +class MediaProjectionPermissionDialogDelegateTest : SysuiTestCase() { + +    private lateinit var dialog: AlertDialog + +    private val flags = mock<FeatureFlagsClassic>() +    private val onStartRecordingClicked = mock<Runnable>() +    private val mediaProjectionMetricsLogger = mock<MediaProjectionMetricsLogger>() + +    private val mediaProjectionConfig: MediaProjectionConfig = +        MediaProjectionConfig.createConfigForDefaultDisplay() +    private val appName: String = "testApp" +    private val hostUid: Int = 12345 + +    private val resIdSingleApp = R.string.screen_share_permission_dialog_option_single_app +    private val resIdFullScreen = R.string.screen_share_permission_dialog_option_entire_screen +    private val resIdSingleAppDisabled = +        R.string.media_projection_entry_app_permission_dialog_single_app_disabled + +    @Before +    fun setUp() { +        whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true) +    } + +    @After +    fun teardown() { +        if (::dialog.isInitialized) { +            dialog.dismiss() +        } +    } + +    @Test +    fun showDialog_forceShowPartialScreenShareFalse() { +        // Set up dialog with MediaProjectionConfig.createConfigForDefaultDisplay() and +        // overrideDisableSingleAppOption = false +        val overrideDisableSingleAppOption = false +        setUpAndShowDialog(overrideDisableSingleAppOption) + +        val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner) +        val secondOptionText = +            spinner.adapter +                .getDropDownView(1, null, spinner) +                .findViewById<TextView>(android.R.id.text2) +                ?.text + +        // check that the first option is full screen and enabled +        assertEquals(context.getString(resIdFullScreen), spinner.selectedItem) + +        // check that the second option is single app and disabled +        assertEquals(context.getString(resIdSingleAppDisabled, appName), secondOptionText) +    } + +    @Test +    fun showDialog_forceShowPartialScreenShareTrue() { +        // Set up dialog with MediaProjectionConfig.createConfigForDefaultDisplay() and +        // overrideDisableSingleAppOption = true +        val overrideDisableSingleAppOption = true +        setUpAndShowDialog(overrideDisableSingleAppOption) + +        val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner) +        val secondOptionText = +            spinner.adapter +                .getDropDownView(1, null, spinner) +                .findViewById<TextView>(android.R.id.text1) +                ?.text + +        // check that the first option is single app and enabled +        assertEquals(context.getString(resIdSingleApp), spinner.selectedItem) + +        // check that the second option is full screen and enabled +        assertEquals(context.getString(resIdFullScreen), secondOptionText) +    } + +    private fun setUpAndShowDialog(overrideDisableSingleAppOption: Boolean) { +        val delegate = +            MediaProjectionPermissionDialogDelegate( +                context, +                mediaProjectionConfig, +                {}, +                onStartRecordingClicked, +                appName, +                overrideDisableSingleAppOption, +                hostUid, +                mediaProjectionMetricsLogger +            ) + +        dialog = AlertDialogWithDelegate(context, R.style.Theme_SystemUI_Dialog, delegate) +        SystemUIDialog.applyFlags(dialog) +        SystemUIDialog.setDialogSize(dialog) + +        dialog.window?.addSystemFlags( +            WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS +        ) + +        delegate.onCreate(dialog, savedInstanceState = null) +        dialog.show() +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java index 0101741a9242..542bfaaa8484 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java @@ -16,6 +16,8 @@  package com.android.systemui.qs; +import static com.android.systemui.Flags.FLAG_QUICK_SETTINGS_VISUAL_HAPTICS_LONGPRESS; +  import static com.google.common.truth.Truth.assertThat;  import static org.junit.Assert.assertEquals; @@ -33,6 +35,8 @@ import static org.mockito.Mockito.when;  import android.content.res.Configuration;  import android.content.res.Resources; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags;  import android.testing.AndroidTestingRunner;  import android.testing.TestableLooper.RunWithLooper;  import android.view.ContextThemeWrapper; @@ -45,13 +49,14 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;  import com.android.internal.logging.testing.UiEventLoggerFake;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.dump.DumpManager; +import com.android.systemui.haptics.qs.QSLongPressEffect; +import com.android.systemui.kosmos.KosmosJavaAdapter;  import com.android.systemui.media.controls.ui.view.MediaHost;  import com.android.systemui.plugins.qs.QSTile;  import com.android.systemui.qs.customize.QSCustomizerController;  import com.android.systemui.qs.logging.QSLogger;  import com.android.systemui.qs.tileimpl.QSTileImpl;  import com.android.systemui.res.R; -import com.android.systemui.statusbar.VibratorHelper;  import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;  import com.android.systemui.util.animation.DisappearParameters; @@ -66,11 +71,14 @@ import java.io.StringWriter;  import java.util.Collections;  import java.util.List; +import javax.inject.Provider; +  @RunWith(AndroidTestingRunner.class)  @RunWithLooper  @SmallTest  public class QSPanelControllerBaseTest extends SysuiTestCase { +    private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);      @Mock      private QSPanel mQSPanel;      @Mock @@ -101,8 +109,8 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {      Configuration mConfiguration;      @Mock      Runnable mHorizontalLayoutListener; -    @Mock -    VibratorHelper mVibratorHelper; +    private TestableLongPressEffectProvider mLongPressEffectProvider = +            new TestableLongPressEffectProvider();      private QSPanelControllerBase<QSPanel> mController; @@ -114,7 +122,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {                  DumpManager dumpManager) {              super(view, host, qsCustomizerController, true, mediaHost, metricsLogger, uiEventLogger,                      qsLogger, dumpManager, new ResourcesSplitShadeStateController(), -                    mVibratorHelper); +                    mLongPressEffectProvider);          }          @Override @@ -123,6 +131,17 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {          }      } +    private class TestableLongPressEffectProvider implements Provider<QSLongPressEffect> { + +        private int mEffectsProvided = 0; + +        @Override +        public QSLongPressEffect get() { +            mEffectsProvided++; +            return mKosmos.getQsLongPressEffect(); +        } +    } +      @Before      public void setup() throws Exception {          MockitoAnnotations.initMocks(this); @@ -421,6 +440,27 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {      }      @Test +    @EnableFlags(FLAG_QUICK_SETTINGS_VISUAL_HAPTICS_LONGPRESS) +    public void setTiles_longPressEffectEnabled_nonNullLongPressEffectsAreProvided() { +        mLongPressEffectProvider.mEffectsProvided = 0; +        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile)); +        mController.setTiles(); + +        // There is one non-null effect provided for each tile in the host +        assertThat(mLongPressEffectProvider.mEffectsProvided).isEqualTo(2); +    } + +    @Test +    @DisableFlags(FLAG_QUICK_SETTINGS_VISUAL_HAPTICS_LONGPRESS) +    public void setTiles_longPressEffectDisabled_noLongPressEffectsAreProvided() { +        mLongPressEffectProvider.mEffectsProvided = 0; +        when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile)); +        mController.setTiles(); + +        assertThat(mLongPressEffectProvider.mEffectsProvided).isEqualTo(0); +    } + +    @Test      public void setTiles_differentTiles_extraTileRemoved() {          when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));          mController.setTiles(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt index 916e8ddb6e8a..a60494f87fb4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt @@ -7,19 +7,19 @@ import android.testing.TestableResources  import android.view.ContextThemeWrapper  import com.android.internal.logging.MetricsLogger  import com.android.internal.logging.UiEventLogger -import com.android.systemui.res.R  import com.android.systemui.SysuiTestCase  import com.android.systemui.dump.DumpManager +import com.android.systemui.haptics.qs.QSLongPressEffect  import com.android.systemui.media.controls.ui.view.MediaHost  import com.android.systemui.media.controls.ui.view.MediaHostState  import com.android.systemui.plugins.FalsingManager  import com.android.systemui.plugins.qs.QSTile  import com.android.systemui.qs.customize.QSCustomizerController  import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.res.R  import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags  import com.android.systemui.settings.brightness.BrightnessController  import com.android.systemui.settings.brightness.BrightnessSliderController -import com.android.systemui.statusbar.VibratorHelper  import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager  import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController  import com.android.systemui.tuner.TunerService @@ -36,6 +36,7 @@ import org.mockito.Mockito.never  import org.mockito.Mockito.reset  import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations +import javax.inject.Provider  import org.mockito.Mockito.`when` as whenever  @SmallTest @@ -62,7 +63,7 @@ class QSPanelControllerTest : SysuiTestCase() {      @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager      @Mock private lateinit var configuration: Configuration      @Mock private lateinit var pagedTileLayout: PagedTileLayout -    @Mock private lateinit var vibratorHelper: VibratorHelper +    @Mock private lateinit var longPressEffectProvider: Provider<QSLongPressEffect>      private val sceneContainerFlags = FakeSceneContainerFlags() @@ -103,7 +104,7 @@ class QSPanelControllerTest : SysuiTestCase() {              statusBarKeyguardViewManager,              ResourcesSplitShadeStateController(),              sceneContainerFlags, -            vibratorHelper, +            longPressEffectProvider,          )      } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt index 71a9a8b3318f..1eb0a51bcaf6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt @@ -22,15 +22,15 @@ import android.view.ContextThemeWrapper  import androidx.test.filters.SmallTest  import com.android.internal.logging.MetricsLogger  import com.android.internal.logging.testing.UiEventLoggerFake -import com.android.systemui.res.R  import com.android.systemui.SysuiTestCase  import com.android.systemui.dump.DumpManager +import com.android.systemui.haptics.qs.QSLongPressEffect  import com.android.systemui.media.controls.ui.view.MediaHost  import com.android.systemui.media.controls.ui.view.MediaHostState  import com.android.systemui.plugins.qs.QSTile  import com.android.systemui.qs.customize.QSCustomizerController  import com.android.systemui.qs.logging.QSLogger -import com.android.systemui.statusbar.VibratorHelper +import com.android.systemui.res.R  import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController  import com.android.systemui.util.leak.RotationUtils  import org.junit.After @@ -45,6 +45,7 @@ import org.mockito.Mockito.reset  import org.mockito.Mockito.times  import org.mockito.Mockito.verify  import org.mockito.MockitoAnnotations +import javax.inject.Provider  import org.mockito.Mockito.`when` as whenever  @SmallTest @@ -60,7 +61,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() {      @Mock private lateinit var tile: QSTile      @Mock private lateinit var tileLayout: TileLayout      @Captor private lateinit var captor: ArgumentCaptor<QSPanel.OnConfigurationChangedListener> -    @Mock private lateinit var vibratorHelper: VibratorHelper +    @Mock private lateinit var longPressEffectProvider: Provider<QSLongPressEffect>      private val uiEventLogger = UiEventLoggerFake()      private val dumpManager = DumpManager() @@ -92,7 +93,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() {                  uiEventLogger,                  qsLogger,                  dumpManager, -                vibratorHelper, +                longPressEffectProvider,              )          controller.init() @@ -161,7 +162,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() {          uiEventLogger: UiEventLoggerFake,          qsLogger: QSLogger,          dumpManager: DumpManager, -        vibratorHelper: VibratorHelper, +        longPressEffectProvider: Provider<QSLongPressEffect>,      ) :          QuickQSPanelController(              view, @@ -175,7 +176,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() {              qsLogger,              dumpManager,              ResourcesSplitShadeStateController(), -            vibratorHelper, +            longPressEffectProvider,          ) {          private var rotation = RotationUtils.ROTATION_NONE diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt index 2b1ac915f430..512ca5315530 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.tileimpl  import android.content.Context  import android.graphics.drawable.Drawable -import android.platform.test.annotations.EnableFlags  import android.service.quicksettings.Tile  import android.testing.AndroidTestingRunner  import android.testing.TestableLooper @@ -28,10 +27,12 @@ import android.view.View  import android.view.accessibility.AccessibilityNodeInfo  import android.widget.TextView  import androidx.test.filters.SmallTest -import com.android.systemui.Flags.FLAG_QUICK_SETTINGS_VISUAL_HAPTICS_LONGPRESS  import com.android.systemui.res.R  import com.android.systemui.SysuiTestCase +import com.android.systemui.haptics.qs.QSLongPressEffect +import com.android.systemui.haptics.qs.qsLongPressEffect  import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.testKosmos  import com.google.common.truth.Truth.assertThat  import org.junit.Before  import org.junit.Test @@ -50,13 +51,14 @@ class QSTileViewImplTest : SysuiTestCase() {      private lateinit var tileView: FakeTileView      private lateinit var customDrawableView: View      private lateinit var chevronView: View +    private val kosmos = testKosmos()      @Before      fun setUp() {          MockitoAnnotations.initMocks(this)          context.ensureTestableResources() -        tileView = FakeTileView(context, false) +        tileView = FakeTileView(context, false, kosmos.qsLongPressEffect)          customDrawableView = tileView.requireViewById(R.id.customDrawable)          chevronView = tileView.requireViewById(R.id.chevron)      } @@ -383,7 +385,6 @@ class QSTileViewImplTest : SysuiTestCase() {      }      @Test -    @EnableFlags(FLAG_QUICK_SETTINGS_VISUAL_HAPTICS_LONGPRESS)      fun onStateChange_longPressEffectActive_withInvalidDuration_doesNotCreateEffect() {          val state = QSTile.State() // A state that handles longPress @@ -393,12 +394,11 @@ class QSTileViewImplTest : SysuiTestCase() {          // WHEN the state changes          tileView.changeState(state) -        // THEN the long-press effect is not created -        assertThat(tileView.hasLongPressEffect).isFalse() +        // THEN the long-press effect is not initialized +        assertThat(tileView.isLongPressEffectInitialized).isFalse()      }      @Test -    @EnableFlags(FLAG_QUICK_SETTINGS_VISUAL_HAPTICS_LONGPRESS)      fun onStateChange_longPressEffectActive_withValidDuration_createsEffect() {          // GIVEN a test state that handles long-press and a valid long-press effect duration          val state = QSTile.State() @@ -406,12 +406,11 @@ class QSTileViewImplTest : SysuiTestCase() {          // WHEN the state changes          tileView.changeState(state) -        // THEN the long-press effect created -        assertThat(tileView.hasLongPressEffect).isTrue() +        // THEN the long-press effect is initialized +        assertThat(tileView.isLongPressEffectInitialized).isTrue()      }      @Test -    @EnableFlags(FLAG_QUICK_SETTINGS_VISUAL_HAPTICS_LONGPRESS)      fun onStateChange_fromLongPress_to_noLongPress_unBoundsTile() {          // GIVEN a state that no longer handles long-press          val state = QSTile.State() @@ -421,11 +420,10 @@ class QSTileViewImplTest : SysuiTestCase() {          tileView.changeState(state)          // THEN the view binder no longer binds the view to the long-press effect -        assertThat(tileView.isLongPressEffectBound).isFalse() +        assertThat(tileView.longPressEffectHandle).isNull()      }      @Test -    @EnableFlags(FLAG_QUICK_SETTINGS_VISUAL_HAPTICS_LONGPRESS)      fun onStateChange_fromNoLongPress_to_longPress_bindsTile() {          // GIVEN that the tile has changed to a state that does not handle long-press          val state = QSTile.State() @@ -437,15 +435,53 @@ class QSTileViewImplTest : SysuiTestCase() {          tileView.changeState(state)          // THEN the view is bounded to the long-press effect -        assertThat(tileView.isLongPressEffectBound).isTrue() +        assertThat(tileView.longPressEffectHandle).isNotNull() +    } + +    @Test +    fun onStateChange_withoutLongPressEffect_fromLongPress_to_noLongPress_neverBindsEffect() { +        // GIVEN a tile where the long-press effect is null +        tileView = FakeTileView(context, false, null) + +        // GIVEN a state that no longer handles long-press +        val state = QSTile.State() +        state.handlesLongClick = false + +        // WHEN the state changes +        tileView.changeState(state) + +        // THEN the view binder does not bind the view and no effect is initialized +        assertThat(tileView.longPressEffectHandle).isNull() +        assertThat(tileView.isLongPressEffectInitialized).isFalse() +    } + +    @Test +    fun onStateChange_withoutLongPressEffect_fromNoLongPress_to_longPress_neverBindsEffect() { +        // GIVEN a tile where the long-press effect is null +        tileView = FakeTileView(context, false, null) + +        // GIVEN that the tile has changed to a state that does not handle long-press +        val state = QSTile.State() +        state.handlesLongClick = false +        tileView.changeState(state) + +        // WHEN the state changes back to handling long-press +        state.handlesLongClick = true +        tileView.changeState(state) + +        // THEN the view binder does not bind the view and no effect is initialized +        assertThat(tileView.longPressEffectHandle).isNull() +        assertThat(tileView.isLongPressEffectInitialized).isFalse()      }      class FakeTileView(          context: Context, -        collapsed: Boolean +        collapsed: Boolean, +        longPressEffect: QSLongPressEffect?,      ) : QSTileViewImpl(              ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings), -            collapsed +            collapsed, +            longPressEffect,      ) {          var constantLongPressEffectDuration = 500 diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt index 5e7d8fb5df02..91f39126c67c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt @@ -28,6 +28,7 @@ import com.android.systemui.SysuiTestCase  import com.android.systemui.util.mockito.argumentCaptor  import com.android.systemui.util.mockito.mock  import com.google.common.truth.Truth.assertThat +import kotlin.test.Ignore  import kotlin.test.Test  import kotlinx.coroutines.test.StandardTestDispatcher  import kotlinx.coroutines.test.TestCoroutineScheduler @@ -55,6 +56,7 @@ class ActionExecutorTest : SysuiTestCase() {      private lateinit var actionExecutor: ActionExecutor +    @Ignore // Fixed with newer mockito version (in main)      @Test      fun startSharedTransition_callsLaunchIntent() = runTest {          actionExecutor = createActionExecutor() diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt index bde821b79469..853e50a12ea5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt @@ -16,8 +16,6 @@  package com.android.systemui.screenshot -import android.app.Notification -import android.app.PendingIntent  import android.content.Intent  import android.net.Uri  import android.os.Process @@ -27,8 +25,6 @@ import android.view.accessibility.AccessibilityManager  import androidx.test.filters.SmallTest  import com.android.internal.logging.UiEventLogger  import com.android.systemui.SysuiTestCase -import com.android.systemui.clipboardoverlay.EditTextActivity -import com.android.systemui.res.R  import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel  import com.android.systemui.util.mockito.argumentCaptor  import com.android.systemui.util.mockito.capture @@ -41,10 +37,7 @@ import org.junit.Assert.assertNotNull  import org.junit.Before  import org.junit.runner.RunWith  import org.mockito.Mockito.verifyNoMoreInteractions -import org.mockito.kotlin.any -import org.mockito.kotlin.never  import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever  @RunWith(AndroidTestingRunner::class)  @SmallTest @@ -52,7 +45,6 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() {      private val actionExecutor = mock<ActionExecutor>()      private val accessibilityManager = mock<AccessibilityManager>()      private val uiEventLogger = mock<UiEventLogger>() -    private val smartActionsProvider = mock<SmartActionsProvider>()      private val request = ScreenshotData.forTesting()      private val validResult = ScreenshotSavedResult(Uri.EMPTY, Process.myUserHandle(), 0) @@ -119,42 +111,10 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() {          assertThat(intentCaptor.value.action).isEqualTo(Intent.ACTION_CHOOSER)      } -    @Test -    fun quickShareTapped_wrapsAndSendsIntent() = runTest { -        val quickShare = -            Notification.Action( -                R.drawable.ic_screenshot_edit, -                "TestQuickShare", -                PendingIntent.getActivity( -                    context, -                    0, -                    Intent(context, EditTextActivity::class.java), -                    PendingIntent.FLAG_MUTABLE -                ) -            ) -        whenever(smartActionsProvider.requestQuickShare(any(), any(), any())).then { -            (it.getArgument(2) as ((Notification.Action) -> Unit)).invoke(quickShare) -        } -        whenever(smartActionsProvider.wrapIntent(any(), any(), any(), any())).thenAnswer { -            (it.getArgument(0) as Notification.Action).actionIntent -        } -        actionsProvider = createActionsProvider() - -        viewModel.actions.value[2].onClicked?.invoke() -        verify(uiEventLogger, never()) -            .log(eq(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED), any(), any()) -        verify(smartActionsProvider, never()).wrapIntent(any(), any(), any(), any()) -        actionsProvider.setCompletedScreenshot(validResult) -        verify(smartActionsProvider) -            .wrapIntent(eq(quickShare), eq(validResult.uri), eq(validResult.subject), eq("testid")) -        verify(uiEventLogger).log(eq(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED), eq(0), eq("")) -    } -      private fun createActionsProvider(): ScreenshotActionsProvider {          return DefaultScreenshotActionsProvider(              context,              viewModel, -            smartActionsProvider,              uiEventLogger,              request,              "testid", diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt index 587da2d5d677..b051df21389e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt @@ -18,11 +18,6 @@ package com.android.systemui.screenshot  import android.app.ActivityTaskManager.RootTaskInfo  import android.app.IActivityTaskManager -import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME -import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD -import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED -import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN -import android.app.WindowConfiguration.WINDOWING_MODE_PINNED  import android.content.ComponentName  import android.content.Context  import android.graphics.Rect @@ -31,6 +26,12 @@ import android.os.UserManager  import android.testing.AndroidTestingRunner  import com.android.systemui.SysuiTestCase  import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo +import com.android.systemui.screenshot.policy.ActivityType.Home +import com.android.systemui.screenshot.policy.ActivityType.Undefined +import com.android.systemui.screenshot.policy.WindowingMode.FullScreen +import com.android.systemui.screenshot.policy.WindowingMode.PictureInPicture +import com.android.systemui.screenshot.policy.newChildTask +import com.android.systemui.screenshot.policy.newRootTaskInfo  import com.android.systemui.settings.FakeDisplayTracker  import com.android.systemui.util.mockito.mock  import com.google.common.truth.Truth.assertThat @@ -58,20 +59,19 @@ class ScreenshotPolicyImplTest : SysuiTestCase() {                      ),                      Rect(0, 0, 1080, 2400),                      UserHandle.of(MANAGED_PROFILE_USER), -                    65)) +                    65 +                ) +            )      }      @Test      fun findPrimaryContent_ignoresPipTask() = runBlocking { -        val policy = fakeTasksPolicyImpl( -            mContext, -            shadeExpanded = false, -            tasks = listOf( -                    pipTask, -                    fullScreenWorkProfileTask, -                    launcherTask, -                    emptyTask) -        ) +        val policy = +            fakeTasksPolicyImpl( +                mContext, +                shadeExpanded = false, +                tasks = listOf(pipTask, fullScreenWorkProfileTask, launcherTask, emptyTask) +            )          val info = policy.findPrimaryContent(DISPLAY_ID)          assertThat(info).isEqualTo(fullScreenWorkProfileTask.toDisplayContentInfo()) @@ -79,14 +79,12 @@ class ScreenshotPolicyImplTest : SysuiTestCase() {      @Test      fun findPrimaryContent_shadeExpanded_ignoresTopTask() = runBlocking { -        val policy = fakeTasksPolicyImpl( -            mContext, -            shadeExpanded = true, -            tasks = listOf( -                fullScreenWorkProfileTask, -                launcherTask, -                emptyTask) -        ) +        val policy = +            fakeTasksPolicyImpl( +                mContext, +                shadeExpanded = true, +                tasks = listOf(fullScreenWorkProfileTask, launcherTask, emptyTask) +            )          val info = policy.findPrimaryContent(DISPLAY_ID)          assertThat(info).isEqualTo(policy.systemUiContent) @@ -94,11 +92,7 @@ class ScreenshotPolicyImplTest : SysuiTestCase() {      @Test      fun findPrimaryContent_emptyTaskList() = runBlocking { -        val policy = fakeTasksPolicyImpl( -            mContext, -            shadeExpanded = false, -            tasks = listOf() -        ) +        val policy = fakeTasksPolicyImpl(mContext, shadeExpanded = false, tasks = listOf())          val info = policy.findPrimaryContent(DISPLAY_ID)          assertThat(info).isEqualTo(policy.systemUiContent) @@ -106,14 +100,12 @@ class ScreenshotPolicyImplTest : SysuiTestCase() {      @Test      fun findPrimaryContent_workProfileNotOnTop() = runBlocking { -        val policy = fakeTasksPolicyImpl( -            mContext, -            shadeExpanded = false, -            tasks = listOf( -                launcherTask, -                fullScreenWorkProfileTask, -                emptyTask) -        ) +        val policy = +            fakeTasksPolicyImpl( +                mContext, +                shadeExpanded = false, +                tasks = listOf(launcherTask, fullScreenWorkProfileTask, emptyTask) +            )          val info = policy.findPrimaryContent(DISPLAY_ID)          assertThat(info).isEqualTo(launcherTask.toDisplayContentInfo()) @@ -129,102 +121,80 @@ class ScreenshotPolicyImplTest : SysuiTestCase() {          val dispatcher = Dispatchers.Unconfined          val displayTracker = FakeDisplayTracker(context) -        return object : ScreenshotPolicyImpl(context, userManager, atmService, dispatcher, -                displayTracker) { +        return object : +            ScreenshotPolicyImpl(context, userManager, atmService, dispatcher, displayTracker) {              override suspend fun isManagedProfile(userId: Int) = (userId == MANAGED_PROFILE_USER)              override suspend fun getAllRootTaskInfosOnDisplay(displayId: Int) = tasks              override suspend fun isNotificationShadeExpanded() = shadeExpanded          }      } -    private val pipTask = RootTaskInfo().apply { -        configuration.windowConfiguration.apply { -            windowingMode = WINDOWING_MODE_PINNED -            setBounds(Rect(628, 1885, 1038, 2295)) -            activityType = ACTIVITY_TYPE_STANDARD +    private val pipTask = +        newRootTaskInfo( +            taskId = 66, +            userId = PRIMARY_USER, +            displayId = DISPLAY_ID, +            bounds = Rect(628, 1885, 1038, 2295), +            windowingMode = PictureInPicture, +            topActivity = ComponentName.unflattenFromString(YOUTUBE_PIP_ACTIVITY), +        ) { +            listOf(newChildTask(taskId = 66, userId = 0, name = YOUTUBE_HOME_ACTIVITY))          } -        displayId = DISPLAY_ID -        userId = PRIMARY_USER -        taskId = 66 -        visible = true -        isVisible = true -        isRunning = true -        numActivities = 1 -        topActivity = ComponentName( -            "com.google.android.youtube", -            "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity" -        ) -        childTaskIds = intArrayOf(66) -        childTaskNames = arrayOf("com.google.android.youtube/" + -                "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity") -        childTaskUserIds = intArrayOf(0) -        childTaskBounds = arrayOf(Rect(628, 1885, 1038, 2295)) -    } -    private val fullScreenWorkProfileTask = RootTaskInfo().apply { -        configuration.windowConfiguration.apply { -            windowingMode = WINDOWING_MODE_FULLSCREEN -            setBounds(Rect(0, 0, 1080, 2400)) -            activityType = ACTIVITY_TYPE_STANDARD +    private val fullScreenWorkProfileTask = +        newRootTaskInfo( +            taskId = 65, +            userId = MANAGED_PROFILE_USER, +            displayId = DISPLAY_ID, +            bounds = Rect(0, 0, 1080, 2400), +            windowingMode = FullScreen, +            topActivity = ComponentName.unflattenFromString(FILES_HOME_ACTIVITY), +        ) { +            listOf( +                newChildTask(taskId = 65, userId = MANAGED_PROFILE_USER, name = FILES_HOME_ACTIVITY) +            )          } -        displayId = DISPLAY_ID -        userId = MANAGED_PROFILE_USER -        taskId = 65 -        visible = true -        isVisible = true -        isRunning = true -        numActivities = 1 -        topActivity = ComponentName( -            "com.google.android.apps.nbu.files", -            "com.google.android.apps.nbu.files.home.HomeActivity" -        ) -        childTaskIds = intArrayOf(65) -        childTaskNames = arrayOf("com.google.android.apps.nbu.files/" + -                "com.google.android.apps.nbu.files.home.HomeActivity") -        childTaskUserIds = intArrayOf(MANAGED_PROFILE_USER) -        childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400)) -    } - -    private val launcherTask = RootTaskInfo().apply { -        configuration.windowConfiguration.apply { -            windowingMode = WINDOWING_MODE_FULLSCREEN -            setBounds(Rect(0, 0, 1080, 2400)) -            activityType = ACTIVITY_TYPE_HOME +    private val launcherTask = +        newRootTaskInfo( +            taskId = 1, +            userId = PRIMARY_USER, +            displayId = DISPLAY_ID, +            activityType = Home, +            windowingMode = FullScreen, +            bounds = Rect(0, 0, 1080, 2400), +            topActivity = ComponentName.unflattenFromString(LAUNCHER_ACTIVITY), +        ) { +            listOf(newChildTask(taskId = 1, userId = 0, name = LAUNCHER_ACTIVITY))          } -        displayId = DISPLAY_ID -        taskId = 1 -        userId = PRIMARY_USER -        visible = true -        isVisible = true -        isRunning = true -        numActivities = 1 -        topActivity = ComponentName( -            "com.google.android.apps.nexuslauncher", -            "com.google.android.apps.nexuslauncher.NexusLauncherActivity", -        ) -        childTaskIds = intArrayOf(1) -        childTaskNames = arrayOf("com.google.android.apps.nexuslauncher/" + -                "com.google.android.apps.nexuslauncher.NexusLauncherActivity") -        childTaskUserIds = intArrayOf(0) -        childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400)) -    } -    private val emptyTask = RootTaskInfo().apply { -        configuration.windowConfiguration.apply { -            windowingMode = WINDOWING_MODE_FULLSCREEN -            setBounds(Rect(0, 0, 1080, 2400)) -            activityType = ACTIVITY_TYPE_UNDEFINED +    private val emptyTask = +        newRootTaskInfo( +            taskId = 2, +            userId = PRIMARY_USER, +            displayId = DISPLAY_ID, +            visible = false, +            running = false, +            numActivities = 0, +            activityType = Undefined, +            bounds = Rect(0, 0, 1080, 2400), +        ) { +            listOf( +                newChildTask(taskId = 3, name = ""), +                newChildTask(taskId = 4, name = ""), +            )          } -        displayId = DISPLAY_ID -        taskId = 2 -        userId = PRIMARY_USER -        visible = false -        isVisible = false -        isRunning = false -        numActivities = 0 -        childTaskIds = intArrayOf(3, 4) -        childTaskNames = arrayOf("", "") -        childTaskUserIds = intArrayOf(0, 0) -        childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400), Rect(0, 2400, 1080, 4800)) -    }  } + +const val YOUTUBE_HOME_ACTIVITY = +    "com.google.android.youtube/" + "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity" + +const val FILES_HOME_ACTIVITY = +    "com.google.android.apps.nbu.files/" + "com.google.android.apps.nbu.files.home.HomeActivity" + +const val YOUTUBE_PIP_ACTIVITY = +    "com.google.android.youtube/" + +        "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity" + +const val LAUNCHER_ACTIVITY = +    "com.google.android.apps.nexuslauncher/" + +        "com.google.android.apps.nexuslauncher.NexusLauncherActivity" diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt new file mode 100644 index 000000000000..6c35b233ffec --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/policy/NewRootTaskInfo.kt @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.screenshot.policy + +import android.app.ActivityTaskManager.RootTaskInfo +import android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT +import android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM +import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME +import android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS +import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD +import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN +import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW +import android.app.WindowConfiguration.WINDOWING_MODE_PINNED +import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED +import android.content.ComponentName +import android.graphics.Rect +import android.os.UserHandle +import android.view.Display +import com.android.systemui.screenshot.data.model.ChildTaskModel +import com.android.systemui.screenshot.policy.ActivityType.Standard +import com.android.systemui.screenshot.policy.WindowingMode.FullScreen + +/** An enum mapping to [android.app.WindowConfiguration] constants via [toInt]. */ +enum class ActivityType(private val intValue: Int) { +    Undefined(ACTIVITY_TYPE_UNDEFINED), +    Standard(ACTIVITY_TYPE_STANDARD), +    Home(ACTIVITY_TYPE_HOME), +    Recents(ACTIVITY_TYPE_RECENTS), +    Assistant(ACTIVITY_TYPE_ASSISTANT), +    Dream(ACTIVITY_TYPE_DREAM); + +    /** Returns the [android.app.WindowConfiguration] int constant for the type. */ +    fun toInt() = intValue +} + +/** An enum mapping to [android.app.WindowConfiguration] constants via [toInt]. */ +enum class WindowingMode(private val intValue: Int) { +    Undefined(WINDOWING_MODE_UNDEFINED), +    FullScreen(WINDOWING_MODE_FULLSCREEN), +    PictureInPicture(WINDOWING_MODE_PINNED), +    Freeform(WINDOWING_MODE_FREEFORM), +    MultiWindow(WINDOWING_MODE_MULTI_WINDOW); + +    /** Returns the [android.app.WindowConfiguration] int constant for the mode. */ +    fun toInt() = intValue +} + +/** + * Constructs a child task for a [RootTaskInfo], copying [RootTaskInfo.bounds] and + * [RootTaskInfo.userId] from the parent by default. + */ +fun RootTaskInfo.newChildTask( +    taskId: Int, +    name: String, +    bounds: Rect? = null, +    userId: Int? = null +): ChildTaskModel { +    return ChildTaskModel(taskId, name, bounds ?: this.bounds, userId ?: this.userId) +} + +/** Constructs a new [RootTaskInfo]. */ +fun newRootTaskInfo( +    taskId: Int, +    userId: Int = UserHandle.USER_SYSTEM, +    displayId: Int = Display.DEFAULT_DISPLAY, +    visible: Boolean = true, +    running: Boolean = true, +    activityType: ActivityType = Standard, +    windowingMode: WindowingMode = FullScreen, +    bounds: Rect? = null, +    topActivity: ComponentName? = null, +    topActivityType: ActivityType = Standard, +    numActivities: Int? = null, +    childTaskListBuilder: RootTaskInfo.() -> List<ChildTaskModel>, +): RootTaskInfo { +    return RootTaskInfo().apply { +        configuration.windowConfiguration.apply { +            setWindowingMode(windowingMode.toInt()) +            setActivityType(activityType.toInt()) +            setBounds(bounds) +        } +        this.bounds = bounds +        this.displayId = displayId +        this.userId = userId +        this.taskId = taskId +        this.visible = visible +        this.isVisible = visible +        this.isRunning = running +        this.topActivity = topActivity +        this.topActivityType = topActivityType.toInt() +        // NOTE: topActivityInfo is _not_ populated by this code + +        val childTasks = childTaskListBuilder(this) +        this.numActivities = numActivities ?: childTasks.size + +        childTaskNames = childTasks.map { it.name }.toTypedArray() +        childTaskIds = childTasks.map { it.id }.toIntArray() +        childTaskBounds = childTasks.map { it.bounds }.toTypedArray() +        childTaskUserIds = childTasks.map { it.userId }.toIntArray() +    } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index dfe72cf11dcb..0a8e470f8a7c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -398,7 +398,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {          mFakeKeyguardRepository = keyguardInteractorDeps.getRepository();          mKeyguardBottomAreaInteractor = new KeyguardBottomAreaInteractor(mFakeKeyguardRepository);          mFakeKeyguardClockRepository = new FakeKeyguardClockRepository(); -        mKeyguardClockInteractor = new KeyguardClockInteractor(mFakeKeyguardClockRepository); +        mKeyguardClockInteractor = mKosmos.getKeyguardClockInteractor();          mKeyguardInteractor = keyguardInteractorDeps.getKeyguardInteractor();          mShadeRepository = new FakeShadeRepository();          mShadeAnimationInteractor = new ShadeAnimationInteractorLegacyImpl( @@ -410,6 +410,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {                  mock(DeviceEntryUdfpsInteractor.class);          when(deviceEntryUdfpsInteractor.isUdfpsSupported()).thenReturn(MutableStateFlow(false)); +        when(mKeyguardTransitionInteractor.isInTransitionToState(any())).thenReturn(emptyFlow()); +          mShadeInteractor = new ShadeInteractorImpl(                  mTestScope.getBackgroundScope(),                  mKosmos.getDeviceProvisioningInteractor(), @@ -539,7 +541,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {          }).when(mView).setOnTouchListener(any(NotificationPanelViewController.TouchHandler.class));          // Dreaming->Lockscreen -        when(mKeyguardTransitionInteractor.getDreamingToLockscreenTransition()) +        when(mKeyguardTransitionInteractor.transition(any(), any()))                  .thenReturn(emptyFlow());          when(mDreamingToLockscreenTransitionViewModel.getLockscreenAlpha())                  .thenReturn(emptyFlow()); @@ -547,46 +549,28 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {                  .thenReturn(emptyFlow());          // Occluded->Lockscreen -        when(mKeyguardTransitionInteractor.getOccludedToLockscreenTransition()) -                .thenReturn(emptyFlow());          when(mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha())                  .thenReturn(emptyFlow());          when(mOccludedToLockscreenTransitionViewModel.getLockscreenTranslationY())                  .thenReturn(emptyFlow());          // Lockscreen->Dreaming -        when(mKeyguardTransitionInteractor.getLockscreenToDreamingTransition()) -                .thenReturn(emptyFlow());          when(mLockscreenToDreamingTransitionViewModel.getLockscreenAlpha())                  .thenReturn(emptyFlow());          when(mLockscreenToDreamingTransitionViewModel.lockscreenTranslationY(anyInt()))                  .thenReturn(emptyFlow());          // Gone->Dreaming -        when(mKeyguardTransitionInteractor.getGoneToDreamingTransition()) -                .thenReturn(emptyFlow());          when(mGoneToDreamingTransitionViewModel.getLockscreenAlpha())                  .thenReturn(emptyFlow());          when(mGoneToDreamingTransitionViewModel.lockscreenTranslationY(anyInt()))                  .thenReturn(emptyFlow());          // Gone->Dreaming lockscreen hosted -        when(mKeyguardTransitionInteractor.getGoneToDreamingLockscreenHostedTransition()) -                .thenReturn(emptyFlow());          when(mGoneToDreamingLockscreenHostedTransitionViewModel.getLockscreenAlpha())                  .thenReturn(emptyFlow()); -        // Dreaming lockscreen hosted->Lockscreen -        when(mKeyguardTransitionInteractor.getDreamingLockscreenHostedToLockscreenTransition()) -                .thenReturn(emptyFlow()); - -        // Lockscreen->Dreaming lockscreen hosted -        when(mKeyguardTransitionInteractor.getLockscreenToDreamingLockscreenHostedTransition()) -                .thenReturn(emptyFlow()); -          // Lockscreen->Occluded -        when(mKeyguardTransitionInteractor.getLockscreenToOccludedTransition()) -                .thenReturn(emptyFlow());          when(mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha())                  .thenReturn(emptyFlow());          when(mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index 2c0a15dd4e5a..b04503b8e031 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -43,6 +43,8 @@ import com.android.systemui.flags.Flags.TRACKPAD_GESTURE_FEATURES  import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler  import com.android.systemui.keyguard.KeyguardUnlockAnimationController  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING +import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN  import com.android.systemui.keyguard.shared.model.TransitionStep  import com.android.systemui.res.R  import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler @@ -160,7 +162,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {              .thenReturn(keyguardBouncerComponent)          whenever(keyguardBouncerComponent.securityContainerController)              .thenReturn(keyguardSecurityContainerController) -        whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition) +        whenever(keyguardTransitionInteractor.transition(LOCKSCREEN, DREAMING))              .thenReturn(emptyFlow<TransitionStep>())          featureFlagsClassic = FakeFeatureFlagsClassic() diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt index 98a815cabe83..ba8eb6f4ba36 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt @@ -36,6 +36,8 @@ import com.android.systemui.flags.Flags  import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler  import com.android.systemui.keyguard.KeyguardUnlockAnimationController  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING +import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN  import com.android.systemui.res.R  import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler  import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor @@ -149,7 +151,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {          whenever(statusBarStateController.isDozing).thenReturn(false)          mDependency.injectTestDependency(ShadeController::class.java, shadeController)          whenever(dockManager.isDocked).thenReturn(false) -        whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition) +        whenever(keyguardTransitionInteractor.transition(LOCKSCREEN, DREAMING))              .thenReturn(emptyFlow())          val featureFlags = FakeFeatureFlags() diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt index f2abb909e004..7c33648e08a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt @@ -1,15 +1,14 @@  package com.android.systemui.shade.transition -import android.platform.test.annotations.DisableFlags  import android.testing.AndroidTestingRunner  import androidx.test.filters.SmallTest -import com.android.systemui.Flags  import com.android.systemui.SysuiTestCase  import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository  import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository  import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor  import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor  import com.android.systemui.dump.DumpManager +import com.android.systemui.flags.DisableSceneContainer  import com.android.systemui.kosmos.applicationCoroutineScope  import com.android.systemui.kosmos.testScope  import com.android.systemui.scene.domain.interactor.SceneInteractor @@ -70,7 +69,7 @@ class ScrimShadeTransitionControllerTest : SysuiTestCase() {      }      @Test -    @DisableFlags(Flags.FLAG_SCENE_CONTAINER) +    @DisableSceneContainer      fun onPanelExpansionChanged_setsFractionEqualToEventFraction() {          underTest.onPanelExpansionChanged(DEFAULT_EXPANSION_EVENT) @@ -78,7 +77,7 @@ class ScrimShadeTransitionControllerTest : SysuiTestCase() {      }      @Test -    @DisableFlags(Flags.FLAG_SCENE_CONTAINER) +    @DisableSceneContainer      fun onPanelStateChanged_forwardsToScrimTransitionController() {          startLegacyPanelExpansion() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt index de6108632153..d2fc087e44bd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt @@ -19,12 +19,10 @@  package com.android.systemui.statusbar  import android.animation.ObjectAnimator -import android.platform.test.annotations.DisableFlags  import android.testing.AndroidTestingRunner  import android.testing.TestableLooper  import androidx.test.filters.SmallTest  import com.android.internal.logging.testing.UiEventLoggerFake -import com.android.systemui.Flags.FLAG_SCENE_CONTAINER  import com.android.systemui.SysuiTestCase  import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository  import com.android.systemui.authentication.shared.model.AuthenticationMethodModel @@ -35,6 +33,7 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor  import com.android.systemui.coroutines.collectLastValue  import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor  import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor +import com.android.systemui.flags.DisableSceneContainer  import com.android.systemui.flags.EnableSceneContainer  import com.android.systemui.flags.FakeFeatureFlagsClassic  import com.android.systemui.jank.interactionJankMonitor @@ -187,7 +186,7 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) +    @DisableSceneContainer      fun testChangeState_logged() {          TestableLooper.get(this).runWithLooper {              underTest.state = StatusBarState.KEYGUARD @@ -214,7 +213,7 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) +    @DisableSceneContainer      fun testSetState_appliesState_sameStateButDifferentUpcomingState() {          underTest.state = StatusBarState.SHADE          underTest.setUpcomingState(StatusBarState.KEYGUARD) @@ -227,7 +226,7 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) +    @DisableSceneContainer      fun testSetState_appliesState_differentStateEqualToUpcomingState() {          underTest.state = StatusBarState.SHADE          underTest.setUpcomingState(StatusBarState.KEYGUARD) @@ -239,7 +238,7 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) +    @DisableSceneContainer      fun testSetState_doesNotApplyState_currentAndUpcomingStatesSame() {          underTest.state = StatusBarState.SHADE          underTest.setUpcomingState(StatusBarState.SHADE) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt index 4eb7daa1eac7..894e02e80997 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt @@ -188,6 +188,9 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {      @Test      fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =          testComponent.runTest { +            val animationsEnabled by collectLastValue(underTest.areContainerChangesAnimated) +            assertThat(animationsEnabled).isTrue() +              powerRepository.updateWakefulness(                  rawState = WakefulnessState.STARTING_TO_SLEEP,                  lastWakeReason = WakeSleepReason.POWER_BUTTON, @@ -201,8 +204,6 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {                  )              )              whenever(dozeParams.shouldControlScreenOff()).thenReturn(true) -            val animationsEnabled by collectLastValue(underTest.areContainerChangesAnimated) -            runCurrent()              assertThat(animationsEnabled).isTrue()          } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt index 35b84939b05d..78b76151e7e6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt @@ -195,6 +195,9 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {      @Test      fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =          testComponent.runTest { +            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +            assertThat(animationsEnabled).isTrue() +              powerRepository.updateWakefulness(                  rawState = WakefulnessState.STARTING_TO_SLEEP,                  lastWakeReason = WakeSleepReason.POWER_BUTTON, @@ -208,7 +211,7 @@ class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {                  )              )              whenever(dozeParams.shouldControlScreenOff()).thenReturn(true) -            val animationsEnabled by collectLastValue(underTest.animationsEnabled) +              runCurrent()              assertThat(animationsEnabled).isTrue()          } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt index 54108642385f..edab9d9f7fdf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt @@ -50,7 +50,8 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro              systemClock,              uiEventLogger,              userTracker, -            avalancheProvider +            avalancheProvider, +            systemSettings          )      } @@ -82,7 +83,7 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro      fun testAvalancheFilter_duringAvalanche_allowConversationFromAfterEvent() {          avalancheProvider.startTime = whenAgo(10) -        withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) { +        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {              ensurePeekState()              assertShouldHeadsUp(buildEntry {                  importance = NotificationManager.IMPORTANCE_HIGH @@ -97,7 +98,7 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro      fun testAvalancheFilter_duringAvalanche_suppressConversationFromBeforeEvent() {          avalancheProvider.startTime = whenAgo(10) -        withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) { +        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {              ensurePeekState()              assertShouldNotHeadsUp(buildEntry {                  importance = NotificationManager.IMPORTANCE_DEFAULT @@ -112,7 +113,7 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro      fun testAvalancheFilter_duringAvalanche_allowHighPriorityConversation() {          avalancheProvider.startTime = whenAgo(10) -        withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) { +        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {              ensurePeekState()              assertShouldHeadsUp(buildEntry {                  importance = NotificationManager.IMPORTANCE_HIGH @@ -125,7 +126,7 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro      fun testAvalancheFilter_duringAvalanche_allowCall() {          avalancheProvider.startTime = whenAgo(10) -        withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) { +        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {              ensurePeekState()              assertShouldHeadsUp(buildEntry {                  importance = NotificationManager.IMPORTANCE_HIGH @@ -138,7 +139,7 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro      fun testAvalancheFilter_duringAvalanche_allowCategoryReminder() {          avalancheProvider.startTime = whenAgo(10) -        withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) { +        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {              ensurePeekState()              assertShouldHeadsUp(buildEntry {                  importance = NotificationManager.IMPORTANCE_HIGH @@ -151,7 +152,7 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro      fun testAvalancheFilter_duringAvalanche_allowCategoryEvent() {          avalancheProvider.startTime = whenAgo(10) -        withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) { +        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {              ensurePeekState()              assertShouldHeadsUp(buildEntry {                  importance = NotificationManager.IMPORTANCE_HIGH @@ -164,7 +165,7 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro      fun testAvalancheFilter_duringAvalanche_allowFsi() {          avalancheProvider.startTime = whenAgo(10) -        withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) { +        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {              assertFsiNotSuppressed()          }      } @@ -173,7 +174,7 @@ class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionPro      fun testAvalancheFilter_duringAvalanche_allowColorized() {          avalancheProvider.startTime = whenAgo(10) -        withFilter(AvalancheSuppressor(avalancheProvider, systemClock)) { +        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {              ensurePeekState()              assertShouldHeadsUp(buildEntry {                  importance = NotificationManager.IMPORTANCE_HIGH diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt index 24f670831193..3b979a7c1386 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt @@ -77,6 +77,8 @@ import com.android.systemui.util.FakeEventLog  import com.android.systemui.util.mockito.any  import com.android.systemui.util.mockito.mock  import com.android.systemui.util.settings.FakeGlobalSettings +import com.android.systemui.util.settings.FakeSettings +import com.android.systemui.util.settings.SystemSettings  import com.android.systemui.util.time.FakeSystemClock  import com.android.systemui.utils.leaks.FakeBatteryController  import com.android.systemui.utils.leaks.FakeKeyguardStateController @@ -126,6 +128,7 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() {      protected val uiEventLogger = UiEventLoggerFake()      protected val userTracker = FakeUserTracker()      protected val avalancheProvider: AvalancheProvider = mock() +    lateinit var systemSettings: SystemSettings      protected abstract val provider: VisualInterruptionDecisionProvider @@ -153,6 +156,7 @@ abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() {          deviceProvisionedController.currentUser = userId          userTracker.set(listOf(user), /* currentUserIndex = */ 0) +        systemSettings = FakeSettings()          provider.start()      } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt index 620ad9c19bfa..60aaa646fced 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt @@ -30,6 +30,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager  import com.android.systemui.statusbar.policy.KeyguardStateController  import com.android.systemui.util.EventLog  import com.android.systemui.util.settings.GlobalSettings +import com.android.systemui.util.settings.SystemSettings  import com.android.systemui.util.time.SystemClock  object VisualInterruptionDecisionProviderTestUtil { @@ -51,7 +52,8 @@ object VisualInterruptionDecisionProviderTestUtil {          systemClock: SystemClock,          uiEventLogger: UiEventLogger,          userTracker: UserTracker, -        avalancheProvider: AvalancheProvider +        avalancheProvider: AvalancheProvider, +        systemSettings: SystemSettings      ): VisualInterruptionDecisionProvider {          return if (VisualInterruptionRefactor.isEnabled) {              VisualInterruptionDecisionProviderImpl( @@ -70,7 +72,8 @@ object VisualInterruptionDecisionProviderTestUtil {                  systemClock,                  uiEventLogger,                  userTracker, -                avalancheProvider +                avalancheProvider, +                systemSettings              )          } else {              NotificationInterruptStateProviderWrapper( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java index 69e0db9c5e7a..54a6523d82a1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java @@ -138,7 +138,7 @@ public class NotificationLoggerTest extends SysuiTestCase {                  mHeadsUpManager,                  mPowerInteractor,                  mActiveNotificationsInteractor, -                mKosmos.getFakeSceneContainerFlags(), +                mKosmos.getSceneContainerFlags(),                  () -> mKosmos.getSceneInteractor());          mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index 06a4d0820386..01492f629fe8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -398,7 +398,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {      }      @Test -    public void testAboveShelfChangedListenerCalledHeadsUpGoingAway() throws Exception { +    public void testAboveShelfChangedListenerCalledHeadsUpAnimatingAway() throws Exception {          ExpandableNotificationRow row = mNotificationTestHelper.createRow();          AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class);          row.setAboveShelfChangedListener(listener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index fe0d9d06c8f4..db053d842bdb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -23,7 +23,6 @@ import static android.app.NotificationManager.IMPORTANCE_DEFAULT;  import static android.app.NotificationManager.IMPORTANCE_HIGH;  import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; -import static com.android.systemui.concurrency.FakeExecutorKosmosKt.getFakeExecutor;  import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;  import static junit.framework.Assert.assertNotNull; @@ -97,7 +96,6 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController;  import com.android.systemui.statusbar.policy.HeadsUpManager;  import com.android.systemui.util.concurrency.FakeExecutor;  import com.android.systemui.util.kotlin.JavaAdapter; -import com.android.systemui.util.time.FakeSystemClock;  import com.android.systemui.wmshell.BubblesManager;  import org.junit.Before; @@ -182,7 +180,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {                  mHeadsUpManager,                  PowerInteractorFactory.create().getPowerInteractor(),                  mActiveNotificationsInteractor, -                mKosmos.getFakeSceneContainerFlags(), +                mKosmos.getSceneContainerFlags(),                  () -> mKosmos.getSceneInteractor()          ); 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 abb9432425bc..1e058cac8001 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 @@ -20,7 +20,6 @@ import static android.view.View.GONE;  import static android.view.WindowInsets.Type.ime;  import static com.android.systemui.Flags.FLAG_NEW_AOD_TRANSITION; -import static com.android.systemui.Flags.FLAG_SCENE_CONTAINER;  import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;  import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;  import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.RUBBER_BAND_FACTOR_NORMAL; @@ -72,6 +71,7 @@ import com.android.keyguard.BouncerPanelExpansionCalculator;  import com.android.systemui.ExpandHelper;  import com.android.systemui.SysuiTestCase;  import com.android.systemui.dump.DumpManager; +import com.android.systemui.flags.DisableSceneContainer;  import com.android.systemui.flags.EnableSceneContainer;  import com.android.systemui.flags.FakeFeatureFlags;  import com.android.systemui.flags.FeatureFlags; @@ -227,7 +227,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) // TODO(b/312473478): address disabled test +    @DisableSceneContainer // TODO(b/312473478): address disabled test      public void testUpdateStackHeight_qsExpansionZero() {          final float expansionFraction = 0.2f;          final float overExpansion = 50f; @@ -726,7 +726,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) // TODO(b/312473478): address lack of QS Header +    @DisableSceneContainer // TODO(b/312473478): address lack of QS Header      public void testInsideQSHeader_noOffset() {          ViewGroup qsHeader = mock(ViewGroup.class);          Rect boundsOnScreen = new Rect(0, 0, 1000, 1000); @@ -743,7 +743,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) // TODO(b/312473478): address lack of QS Header +    @DisableSceneContainer // TODO(b/312473478): address lack of QS Header      public void testInsideQSHeader_Offset() {          ViewGroup qsHeader = mock(ViewGroup.class);          Rect boundsOnScreen = new Rect(100, 100, 1000, 1000); @@ -763,14 +763,14 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) // TODO(b/312473478): address disabled test +    @DisableSceneContainer // TODO(b/312473478): address disabled test      public void setFractionToShade_recomputesStackHeight() {          mStackScroller.setFractionToShade(1f);          verify(mNotificationStackSizeCalculator).computeHeight(any(), anyInt(), anyFloat());      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) // TODO(b/312473478): address disabled test +    @DisableSceneContainer // TODO(b/312473478): address disabled test      public void testSetOwnScrollY_shadeNotClosing_scrollYChanges() {          // Given: shade is not closing, scrollY is 0          mAmbientState.setScrollY(0); @@ -869,7 +869,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) // TODO(b/312473478): address disabled test +    @DisableSceneContainer // TODO(b/312473478): address disabled test      public void testSplitShade_hasTopOverscroll() {          mTestableResources                  .addOverride(R.bool.config_use_split_notification_shade, /* value= */ true); @@ -942,7 +942,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) // TODO(b/312473478): address disabled test +    @DisableSceneContainer // TODO(b/312473478): address disabled test      public void testSetMaxDisplayedNotifications_notifiesListeners() {          ExpandableView.OnHeightChangedListener listener =                  mock(ExpandableView.OnHeightChangedListener.class); @@ -957,7 +957,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {      }      @Test -    @DisableFlags(FLAG_SCENE_CONTAINER) +    @DisableSceneContainer      public void testDispatchTouchEvent_sceneContainerDisabled() {          MotionEvent event = MotionEvent.obtain(                  SystemClock.uptimeMillis(), 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 50f81ff13825..e9ec3236a06c 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 @@ -131,6 +131,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {      private SelectedUserInteractor mSelectedUserInteractor;      @Mock      private BiometricUnlockInteractor mBiometricUnlockInteractor; +    @Mock +    private KeyguardTransitionInteractor mKeyguardTransitionInteractor;      private final FakeSystemClock mSystemClock = new FakeSystemClock();      private BiometricUnlockController mBiometricUnlockController; @@ -167,7 +169,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {                  () -> mSelectedUserInteractor,                  mBiometricUnlockInteractor,                  mock(JavaAdapter.class), -                mock(KeyguardTransitionInteractor.class) +                mKeyguardTransitionInteractor          );          biometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);          biometricUnlockController.addListener(mBiometricUnlockEventsListener); @@ -374,6 +376,24 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {      }      @Test +    public void onBiometricAuthenticated_whenFaceOnAlternateBouncer_dismissBouncer() { +        when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); +        when(mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()).thenReturn(false); +        when(mKeyguardTransitionInteractor.getCurrentState()) +                .thenReturn(KeyguardState.ALTERNATE_BOUNCER); +        // the value of isStrongBiometric doesn't matter here since we only care about the returned +        // value of isUnlockingWithBiometricAllowed() +        mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, +                BiometricSourceType.FACE, true /* isStrongBiometric */); + +        verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false)); +        assertThat(mBiometricUnlockController.getMode()) +                .isEqualTo(BiometricUnlockController.MODE_DISMISS_BOUNCER); +        assertThat(mBiometricUnlockController.getBiometricType()) +                .isEqualTo(BiometricSourceType.FACE); +    } + +    @Test      public void onBiometricAuthenticated_whenBypassOnBouncer_dismissBouncer() {          reset(mKeyguardBypassController);          when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 2f153d8b7003..25e4728725e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -181,7 +181,9 @@ import com.android.systemui.util.concurrency.FakeExecutor;  import com.android.systemui.util.concurrency.MessageRouterImpl;  import com.android.systemui.util.kotlin.JavaAdapter;  import com.android.systemui.util.settings.FakeGlobalSettings; +import com.android.systemui.util.settings.FakeSettings;  import com.android.systemui.util.settings.GlobalSettings; +import com.android.systemui.util.settings.SystemSettings;  import com.android.systemui.util.time.FakeSystemClock;  import com.android.systemui.util.time.SystemClock;  import com.android.systemui.volume.VolumeComponent; @@ -325,6 +327,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase {      private ShadeController mShadeController;      private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();      private final FakeGlobalSettings mFakeGlobalSettings = new FakeGlobalSettings(); +    private final SystemSettings mSystemSettings = new FakeSettings();      private final FakeEventLog mFakeEventLog = new FakeEventLog();      private final FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);      private final FakeExecutor mUiBgExecutor = new FakeExecutor(mFakeSystemClock); @@ -375,7 +378,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase {                          mFakeSystemClock,                          mock(UiEventLogger.class),                          mUserTracker, -                        mAvalancheProvider); +                        mAvalancheProvider, +                        mSystemSettings);          mVisualInterruptionDecisionProvider.start();          mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java index 05fd63e96089..dc3db4c7fa19 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java @@ -172,7 +172,7 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {                  mKeyguardRepository,                  mCommandQueue,                  PowerInteractorFactory.create().getPowerInteractor(), -                mKosmos.getFakeSceneContainerFlags(), +                mKosmos.getSceneContainerFlags(),                  new FakeKeyguardBouncerRepository(),                  new ConfigurationInteractor(new FakeConfigurationRepository()),                  new FakeShadeRepository(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 34605fed7d28..f8c01e7c5275 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -76,8 +76,6 @@ import com.android.systemui.bouncer.ui.BouncerView;  import com.android.systemui.bouncer.ui.BouncerViewDelegate;  import com.android.systemui.dock.DockManager;  import com.android.systemui.dreams.DreamOverlayStateController; -import com.android.systemui.flags.FakeFeatureFlags; -import com.android.systemui.flags.Flags;  import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor;  import com.android.systemui.keyguard.domain.interactor.KeyguardSurfaceBehindInteractor;  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; @@ -145,7 +143,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {      @Mock private SysUIUnfoldComponent mSysUiUnfoldComponent;      @Mock private DreamOverlayStateController mDreamOverlayStateController;      @Mock private LatencyTracker mLatencyTracker; -    private FakeFeatureFlags mFeatureFlags;      @Mock private KeyguardSecurityModel mKeyguardSecurityModel;      @Mock private PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;      @Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor; @@ -188,11 +185,10 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {                  .thenReturn(mKeyguardMessageAreaController);          when(mBouncerView.getDelegate()).thenReturn(mBouncerViewDelegate);          when(mBouncerViewDelegate.getBackCallback()).thenReturn(mBouncerViewDelegateBackCallback); -        mFeatureFlags = new FakeFeatureFlags(); -        mFeatureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false);          mSetFlagsRule.disableFlags(                  com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR, -                com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR +                com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR, +                com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT          );          when(mNotificationShadeWindowController.getWindowRootView()) @@ -218,7 +214,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {                          () -> mShadeController,                          mLatencyTracker,                          mKeyguardSecurityModel, -                        mFeatureFlags,                          mPrimaryBouncerCallbackInteractor,                          mPrimaryBouncerInteractor,                          mBouncerView, @@ -728,7 +723,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {                          () -> mShadeController,                          mLatencyTracker,                          mKeyguardSecurityModel, -                        mFeatureFlags,                          mPrimaryBouncerCallbackInteractor,                          mPrimaryBouncerInteractor,                          mBouncerView, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt index 9b6940e14415..598b12ccdc38 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt @@ -137,6 +137,7 @@ class MobileRepositorySwitcherTest : SysuiTestCase() {                  wifiRepository,                  mock(),                  mock(), +                mock(),              )          demoRepo = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt index c13e830afac7..3c13906dbd43 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt @@ -17,6 +17,7 @@  package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod  import android.net.ConnectivityManager +import android.os.PersistableBundle  import android.telephony.ServiceState  import android.telephony.SignalStrength  import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET @@ -99,6 +100,9 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {              )          ) +    // Use a real config, with no overrides +    private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_ID, PersistableBundle()) +      private lateinit var mobileRepo: FakeMobileConnectionRepository      private lateinit var carrierMergedRepo: FakeMobileConnectionRepository @@ -680,10 +684,6 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {          telephonyManager: TelephonyManager,      ): MobileConnectionRepositoryImpl {          whenever(telephonyManager.subscriptionId).thenReturn(SUB_ID) -        val systemUiCarrierConfigMock: SystemUiCarrierConfig = mock() -        whenever(systemUiCarrierConfigMock.satelliteConnectionHysteresisSeconds) -            .thenReturn(MutableStateFlow(0)) -          val realRepo =              MobileConnectionRepositoryImpl(                  SUB_ID, @@ -693,7 +693,7 @@ class FullMobileConnectionRepositoryTest : SysuiTestCase() {                  SEP,                  connectivityManager,                  telephonyManager, -                systemUiCarrierConfig = systemUiCarrierConfigMock, +                systemUiCarrierConfig = systemUiCarrierConfig,                  fakeBroadcastDispatcher,                  mobileMappingsProxy = mock(),                  testDispatcher, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt index f761bcfe63d6..9d1411625a8f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt @@ -1030,6 +1030,26 @@ class MobileConnectionRepositoryTest : SysuiTestCase() {          }      @Test +    fun inflateSignalStrength_usesCarrierConfig() = +        testScope.runTest { +            val latest by collectLastValue(underTest.inflateSignalStrength) + +            assertThat(latest).isEqualTo(false) + +            systemUiCarrierConfig.processNewCarrierConfig( +                configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true) +            ) + +            assertThat(latest).isEqualTo(true) + +            systemUiCarrierConfig.processNewCarrierConfig( +                configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false) +            ) + +            assertThat(latest).isEqualTo(false) +        } + +    @Test      fun isAllowedDuringAirplaneMode_alwaysFalse() =          testScope.runTest {              val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt index 07abd275d1ce..b7a3b300a460 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt @@ -80,6 +80,7 @@ import kotlinx.coroutines.test.runCurrent  import kotlinx.coroutines.test.runTest  import org.junit.Assert.assertTrue  import org.junit.Before +import org.junit.Ignore  import org.junit.Test  import org.mockito.ArgumentMatchers.anyInt  import org.mockito.ArgumentMatchers.anyString @@ -229,6 +230,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {                  wifiRepository,                  fullConnectionFactory,                  updateMonitor, +                mock(),              )          testScope.runCurrent() @@ -529,6 +531,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {          }      @Test +    @Ignore("b/333912012")      fun testConnectionCache_clearsInvalidSubscriptions() =          testScope.runTest {              collectLastValue(underTest.subscriptions) @@ -553,6 +556,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {          }      @Test +    @Ignore("b/333912012")      fun testConnectionCache_clearsInvalidSubscriptions_includingCarrierMerged() =          testScope.runTest {              collectLastValue(underTest.subscriptions) @@ -581,6 +585,7 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {      /** Regression test for b/261706421 */      @Test +    @Ignore("b/333912012")      fun testConnectionsCache_clearMultipleSubscriptionsAtOnce_doesNotThrow() =          testScope.runTest {              collectLastValue(underTest.subscriptions) @@ -604,6 +609,54 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {          }      @Test +    fun testConnectionsCache_keepsReposCached() = +        testScope.runTest { +            // Collect subscriptions to start the job +            collectLastValue(underTest.subscriptions) + +            whenever(subscriptionManager.completeActiveSubscriptionInfoList) +                .thenReturn(listOf(SUB_1)) +            getSubscriptionCallback().onSubscriptionsChanged() + +            val repo1_1 = underTest.getRepoForSubId(SUB_1_ID) + +            // All subscriptions disappear +            whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf()) +            getSubscriptionCallback().onSubscriptionsChanged() + +            // Sub1 comes back +            whenever(subscriptionManager.completeActiveSubscriptionInfoList) +                .thenReturn(listOf(SUB_1)) +            getSubscriptionCallback().onSubscriptionsChanged() + +            val repo1_2 = underTest.getRepoForSubId(SUB_1_ID) + +            assertThat(repo1_1).isSameInstanceAs(repo1_2) +        } + +    @Test +    fun testConnectionsCache_doesNotDropReferencesThatHaveBeenRealized() = +        testScope.runTest { +            // Collect subscriptions to start the job +            collectLastValue(underTest.subscriptions) + +            whenever(subscriptionManager.completeActiveSubscriptionInfoList) +                .thenReturn(listOf(SUB_1)) +            getSubscriptionCallback().onSubscriptionsChanged() + +            // Client grabs a reference to a repository, but doesn't keep it around +            underTest.getRepoForSubId(SUB_1_ID) + +            // All subscriptions disappear +            whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf()) +            getSubscriptionCallback().onSubscriptionsChanged() + +            val repo1 = underTest.getRepoForSubId(SUB_1_ID) + +            assertThat(repo1).isNotNull() +        } + +    @Test      fun testConnectionRepository_invalidSubId_doesNotThrow() =          testScope.runTest {              underTest.getRepoForSubId(SUB_1_ID) @@ -1063,7 +1116,8 @@ class MobileConnectionsRepositoryTest : SysuiTestCase() {                      airplaneModeRepository,                      wifiRepository,                      fullConnectionFactory, -                    updateMonitor +                    updateMonitor, +                    mock(),                  )              val latest by collectLastValue(underTest.defaultDataSubRatConfig) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt index c49fcf88ecaa..dfe80233918a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt @@ -43,15 +43,12 @@ import com.android.systemui.util.mockito.any  import com.android.systemui.util.mockito.mock  import com.android.systemui.util.mockito.whenever  import com.google.common.truth.Truth.assertThat -import kotlin.time.Duration.Companion.seconds -import kotlin.time.DurationUnit  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.flow.launchIn  import kotlinx.coroutines.flow.onEach  import kotlinx.coroutines.test.TestScope  import kotlinx.coroutines.test.UnconfinedTestDispatcher -import kotlinx.coroutines.test.advanceTimeBy  import kotlinx.coroutines.test.runTest  import org.junit.Before  import org.junit.Test @@ -181,6 +178,22 @@ class MobileIconInteractorTest : SysuiTestCase() {          }      @Test +    fun inflateSignalStrength_arbitrarilyAddsOneToTheReportedLevel() = +        testScope.runTest { +            connectionRepository.inflateSignalStrength.value = false +            val latest by collectLastValue(underTest.signalLevelIcon) + +            connectionRepository.primaryLevel.value = 4 +            assertThat(latest!!.level).isEqualTo(4) + +            connectionRepository.inflateSignalStrength.value = true +            connectionRepository.primaryLevel.value = 4 + +            // when INFLATE_SIGNAL_STRENGTH is true, we add 1 to the reported signal level +            assertThat(latest!!.level).isEqualTo(5) +        } + +    @Test      fun iconGroup_three_g() =          testScope.runTest {              connectionRepository.resolvedNetworkType.value = @@ -678,32 +691,6 @@ class MobileIconInteractorTest : SysuiTestCase() {              assertThat(latest).isInstanceOf(SignalIconModel.Satellite::class.java)          } -    @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) -    @Test -    fun satBasedIcon_hasHysteresisWhenDisabled() = -        testScope.runTest { -            val latest by collectLastValue(underTest.signalLevelIcon) - -            val hysteresisDuration = 5.seconds -            connectionRepository.satelliteConnectionHysteresisSeconds.value = -                hysteresisDuration.toInt(DurationUnit.SECONDS) - -            connectionRepository.isNonTerrestrial.value = true - -            assertThat(latest).isInstanceOf(SignalIconModel.Satellite::class.java) - -            // Disable satellite -            connectionRepository.isNonTerrestrial.value = false - -            // Satellite icon should still be visible -            assertThat(latest).isInstanceOf(SignalIconModel.Satellite::class.java) - -            // Wait for the icon to change -            advanceTimeBy(hysteresisDuration) - -            assertThat(latest).isInstanceOf(SignalIconModel.Cellular::class.java) -        } -      private fun createInteractor(          overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl()      ) = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt index 83d0fe8f9c4b..cec41557f344 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt @@ -54,6 +54,7 @@ import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupReposi  import com.android.systemui.util.CarrierConfigTracker  import com.android.systemui.util.mockito.whenever  import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage  import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.filterIsInstance  import kotlinx.coroutines.flow.launchIn @@ -279,6 +280,76 @@ class MobileIconViewModelTest : SysuiTestCase() {          }      @Test +    fun contentDescription_nonInflated_invalidLevelIsNull() = +        testScope.runTest { +            val latest by collectLastValue(underTest.contentDescription) + +            repository.inflateSignalStrength.value = false +            repository.setAllLevels(-1) +            assertThat(latest).isNull() + +            repository.setAllLevels(100) +            assertThat(latest).isNull() +        } + +    @Test +    fun contentDescription_inflated_invalidLevelIsNull() = +        testScope.runTest { +            val latest by collectLastValue(underTest.contentDescription) + +            repository.inflateSignalStrength.value = true +            repository.numberOfLevels.value = 6 +            repository.setAllLevels(-2) +            assertThat(latest).isNull() + +            repository.setAllLevels(100) +            assertThat(latest).isNull() +        } + +    @Test +    fun contentDescription_nonInflated_testABunchOfLevelsForNull() = +        testScope.runTest { +            val latest by collectLastValue(underTest.contentDescription) + +            repository.inflateSignalStrength.value = false +            repository.numberOfLevels.value = 5 + +            // -1 and 5 are out of the bounds for non-inflated content descriptions +            for (i in -1..5) { +                repository.setAllLevels(i) +                when (i) { +                    -1, +                    5 -> assertWithMessage("Level $i is expected to be null").that(latest).isNull() +                    else -> +                        assertWithMessage("Level $i is expected not to be null") +                            .that(latest) +                            .isNotNull() +                } +            } +        } + +    @Test +    fun contentDescription_inflated_testABunchOfLevelsForNull() = +        testScope.runTest { +            val latest by collectLastValue(underTest.contentDescription) +            repository.inflateSignalStrength.value = true +            repository.numberOfLevels.value = 6 +            // -1 and 6 are out of the bounds for inflated content descriptions +            // Note that the interactor adds 1 to the reported level, hence the -2 to 5 range +            for (i in -2..5) { +                repository.setAllLevels(i) +                when (i) { +                    -2, +                    5 -> assertWithMessage("Level $i is expected to be null").that(latest).isNull() +                    else -> +                        assertWithMessage("Level $i is not expected to be null") +                            .that(latest) +                            .isNotNull() +                } +            } +        } + +    @Test      fun networkType_dataEnabled_groupIsRepresented() =          testScope.runTest {              val expected = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt index ae3425678abd..69536c5e9c0a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ui/viewmodel/KeyguardStatusBarViewModelTest.kt @@ -30,7 +30,7 @@ import com.android.systemui.keyguard.shared.model.StatusBarState  import com.android.systemui.kosmos.testScope  import com.android.systemui.power.domain.interactor.PowerInteractorFactory  import com.android.systemui.scene.domain.interactor.sceneInteractor -import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags +import com.android.systemui.scene.shared.flag.sceneContainerFlags  import com.android.systemui.shade.data.repository.FakeShadeRepository  import com.android.systemui.statusbar.CommandQueue  import com.android.systemui.statusbar.data.repository.FakeKeyguardStatusBarRepository @@ -60,7 +60,7 @@ class KeyguardStatusBarViewModelTest : SysuiTestCase() {              keyguardRepository,              mock<CommandQueue>(),              PowerInteractorFactory.create().powerInteractor, -            kosmos.fakeSceneContainerFlags, +            kosmos.sceneContainerFlags,              FakeKeyguardBouncerRepository(),              ConfigurationInteractor(FakeConfigurationRepository()),              FakeShadeRepository(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt index 7a83cfe852d6..6f589418cf1e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/loadingeffect/LoadingEffectTest.kt @@ -23,14 +23,8 @@ import android.testing.TestableLooper  import androidx.test.filters.SmallTest  import com.android.systemui.animation.AnimatorTestRule  import com.android.systemui.model.SysUiStateTest -import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState -import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.EASE_IN -import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.EASE_OUT -import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.MAIN -import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.NOT_PLAYING -import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationStateChangedCallback -import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.PaintDrawCallback -import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.RenderEffectDrawCallback +import com.android.systemui.surfaceeffects.PaintDrawCallback +import com.android.systemui.surfaceeffects.RenderEffectDrawCallback  import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseAnimationConfig  import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseShader  import com.google.common.truth.Truth.assertThat @@ -50,8 +44,8 @@ class LoadingEffectTest : SysUiStateTest() {          var paintFromCallback: Paint? = null          val drawCallback =              object : PaintDrawCallback { -                override fun onDraw(loadingPaint: Paint) { -                    paintFromCallback = loadingPaint +                override fun onDraw(paint: Paint) { +                    paintFromCallback = paint                  }              }          val loadingEffect = @@ -75,8 +69,8 @@ class LoadingEffectTest : SysUiStateTest() {          var renderEffectFromCallback: RenderEffect? = null          val drawCallback =              object : RenderEffectDrawCallback { -                override fun onDraw(loadingRenderEffect: RenderEffect) { -                    renderEffectFromCallback = loadingRenderEffect +                override fun onDraw(renderEffect: RenderEffect) { +                    renderEffectFromCallback = renderEffect                  }              }          val loadingEffect = @@ -98,16 +92,19 @@ class LoadingEffectTest : SysUiStateTest() {      @Test      fun play_animationStateChangesInOrder() {          val config = TurbulenceNoiseAnimationConfig() -        val states = mutableListOf(NOT_PLAYING) +        val states = mutableListOf(LoadingEffect.AnimationState.NOT_PLAYING)          val stateChangedCallback = -            object : AnimationStateChangedCallback { -                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) { +            object : LoadingEffect.AnimationStateChangedCallback { +                override fun onStateChanged( +                    oldState: LoadingEffect.AnimationState, +                    newState: LoadingEffect.AnimationState +                ) {                      states.add(newState)                  }              }          val drawCallback =              object : PaintDrawCallback { -                override fun onDraw(loadingPaint: Paint) {} +                override fun onDraw(paint: Paint) {}              }          val loadingEffect =              LoadingEffect( @@ -125,7 +122,14 @@ class LoadingEffectTest : SysUiStateTest() {          animatorTestRule.advanceTimeBy(config.easeOutDuration.toLong())          animatorTestRule.advanceTimeBy(500) -        assertThat(states).containsExactly(NOT_PLAYING, EASE_IN, MAIN, EASE_OUT, NOT_PLAYING) +        assertThat(states) +            .containsExactly( +                LoadingEffect.AnimationState.NOT_PLAYING, +                LoadingEffect.AnimationState.EASE_IN, +                LoadingEffect.AnimationState.MAIN, +                LoadingEffect.AnimationState.EASE_OUT, +                LoadingEffect.AnimationState.NOT_PLAYING +            )      }      @Test @@ -133,16 +137,22 @@ class LoadingEffectTest : SysUiStateTest() {          val config = TurbulenceNoiseAnimationConfig()          var numPlay = 0          val stateChangedCallback = -            object : AnimationStateChangedCallback { -                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) { -                    if (oldState == NOT_PLAYING && newState == EASE_IN) { +            object : LoadingEffect.AnimationStateChangedCallback { +                override fun onStateChanged( +                    oldState: LoadingEffect.AnimationState, +                    newState: LoadingEffect.AnimationState +                ) { +                    if ( +                        oldState == LoadingEffect.AnimationState.NOT_PLAYING && +                            newState == LoadingEffect.AnimationState.EASE_IN +                    ) {                          numPlay++                      }                  }              }          val drawCallback =              object : PaintDrawCallback { -                override fun onDraw(loadingPaint: Paint) {} +                override fun onDraw(paint: Paint) {}              }          val loadingEffect =              LoadingEffect( @@ -172,9 +182,15 @@ class LoadingEffectTest : SysUiStateTest() {              }          var isFinished = false          val stateChangedCallback = -            object : AnimationStateChangedCallback { -                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) { -                    if (oldState == EASE_OUT && newState == NOT_PLAYING) { +            object : LoadingEffect.AnimationStateChangedCallback { +                override fun onStateChanged( +                    oldState: LoadingEffect.AnimationState, +                    newState: LoadingEffect.AnimationState +                ) { +                    if ( +                        oldState == LoadingEffect.AnimationState.EASE_OUT && +                            newState == LoadingEffect.AnimationState.NOT_PLAYING +                    ) {                          isFinished = true                      }                  } @@ -205,13 +221,19 @@ class LoadingEffectTest : SysUiStateTest() {          val config = TurbulenceNoiseAnimationConfig(maxDuration = 1000f)          val drawCallback =              object : PaintDrawCallback { -                override fun onDraw(loadingPaint: Paint) {} +                override fun onDraw(paint: Paint) {}              }          var isFinished = false          val stateChangedCallback = -            object : AnimationStateChangedCallback { -                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) { -                    if (oldState == MAIN && newState == NOT_PLAYING) { +            object : LoadingEffect.AnimationStateChangedCallback { +                override fun onStateChanged( +                    oldState: LoadingEffect.AnimationState, +                    newState: LoadingEffect.AnimationState +                ) { +                    if ( +                        oldState == LoadingEffect.AnimationState.MAIN && +                            newState == LoadingEffect.AnimationState.NOT_PLAYING +                    ) {                          isFinished = true                      }                  } @@ -242,7 +264,7 @@ class LoadingEffectTest : SysUiStateTest() {              )          val drawCallback =              object : PaintDrawCallback { -                override fun onDraw(loadingPaint: Paint) {} +                override fun onDraw(paint: Paint) {}              }          val loadingEffect =              LoadingEffect( diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index 11a53f753b2a..ed2fb2c0cfc9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -65,6 +65,7 @@ import android.widget.ImageButton;  import android.widget.SeekBar;  import androidx.test.core.view.MotionEventBuilder; +import androidx.test.filters.FlakyTest;  import androidx.test.filters.SmallTest;  import com.android.internal.jank.InteractionJankMonitor; @@ -293,7 +294,7 @@ public class VolumeDialogImplTest extends SysuiTestCase {          mTestableLooper.processAllMessages();      } -    @Test +    @Test @FlakyTest(bugId = 329099861)      @EnableFlags(FLAG_HAPTIC_VOLUME_SLIDER)      public void testVolumeChange_withSliderHaptics_deliversOnProgressChangedHapticsEagerly() {          // create haptic plugins on the rows with the flag enabled diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index aabd4e9e79be..c24c86c8cb2a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -174,6 +174,7 @@ import com.android.systemui.user.domain.interactor.SelectedUserInteractor;  import com.android.systemui.user.domain.interactor.UserSwitcherInteractor;  import com.android.systemui.util.FakeEventLog;  import com.android.systemui.util.settings.FakeGlobalSettings; +import com.android.systemui.util.settings.SystemSettings;  import com.android.systemui.util.time.SystemClock;  import com.android.wm.shell.ShellTaskOrganizer;  import com.android.wm.shell.WindowManagerShellWrapper; @@ -554,7 +555,8 @@ public class BubblesTest extends SysuiTestCase {                          mock(SystemClock.class),                          mock(UiEventLogger.class),                          mock(UserTracker.class), -                        mock(AvalancheProvider.class) +                        mock(AvalancheProvider.class), +                        mock(SystemSettings.class)                          );          interruptionDecisionProvider.start(); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/ActivityIntentHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/ActivityIntentHelperKosmos.kt index 7185b7cd0ac6..96c4c45dbb91 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/ActivityIntentHelperKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/ActivityIntentHelperKosmos.kt @@ -18,5 +18,7 @@ package com.android.systemui  import android.content.applicationContext  import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock -val Kosmos.activityIntentHelper by Kosmos.Fixture { ActivityIntentHelper(applicationContext) } +val Kosmos.mockActivityIntentHelper by Kosmos.Fixture { mock<ActivityIntentHelper>() } +var Kosmos.activityIntentHelper by Kosmos.Fixture { ActivityIntentHelper(applicationContext) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt index a6dd3cd7d30a..219794f3ad18 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt @@ -32,6 +32,8 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi  import kotlinx.coroutines.flow.MutableStateFlow  import kotlinx.coroutines.flow.StateFlow  import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock  import kotlinx.coroutines.test.TestScope  import kotlinx.coroutines.test.currentTime @@ -68,6 +70,8 @@ class FakeAuthenticationRepository(      var lockoutStartedReportCount = 0 +    private val credentialCheckingMutex = Mutex(locked = false) +      override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {          return authenticationMethod.value      } @@ -124,30 +128,32 @@ class FakeAuthenticationRepository(      override suspend fun checkCredential(          credential: LockscreenCredential      ): AuthenticationResultModel { -        val expectedCredential = credentialOverride ?: getExpectedCredential(securityMode) -        val isSuccessful = -            when { -                credential.type != getCurrentCredentialType(securityMode) -> false -                credential.type == LockPatternUtils.CREDENTIAL_TYPE_PIN -> -                    credential.isPin && credential.matches(expectedCredential) -                credential.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD -> -                    credential.isPassword && credential.matches(expectedCredential) -                credential.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN -> -                    credential.isPattern && credential.matches(expectedCredential) -                else -> error("Unexpected credential type ${credential.type}!") +        return credentialCheckingMutex.withLock { +            val expectedCredential = credentialOverride ?: getExpectedCredential(securityMode) +            val isSuccessful = +                when { +                    credential.type != getCurrentCredentialType(securityMode) -> false +                    credential.type == LockPatternUtils.CREDENTIAL_TYPE_PIN -> +                        credential.isPin && credential.matches(expectedCredential) +                    credential.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD -> +                        credential.isPassword && credential.matches(expectedCredential) +                    credential.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN -> +                        credential.isPattern && credential.matches(expectedCredential) +                    else -> error("Unexpected credential type ${credential.type}!") +                } + +            val failedAttempts = _failedAuthenticationAttempts.value +            if (isSuccessful || failedAttempts < MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT - 1) { +                AuthenticationResultModel( +                    isSuccessful = isSuccessful, +                    lockoutDurationMs = 0, +                ) +            } else { +                AuthenticationResultModel( +                    isSuccessful = false, +                    lockoutDurationMs = LOCKOUT_DURATION_MS, +                )              } - -        val failedAttempts = _failedAuthenticationAttempts.value -        return if (isSuccessful || failedAttempts < MAX_FAILED_AUTH_TRIES_BEFORE_LOCKOUT - 1) { -            AuthenticationResultModel( -                isSuccessful = isSuccessful, -                lockoutDurationMs = 0, -            ) -        } else { -            AuthenticationResultModel( -                isSuccessful = false, -                lockoutDurationMs = LOCKOUT_DURATION_MS, -            )          }      } @@ -155,6 +161,23 @@ class FakeAuthenticationRepository(          _isPinEnhancedPrivacyEnabled.value = isEnabled      } +    /** +     * Pauses any future credential checking. The test must call [unpauseCredentialChecking] to +     * flush the accumulated credential checks. +     */ +    suspend fun pauseCredentialChecking() { +        credentialCheckingMutex.lock() +    } + +    /** +     * Unpauses future credential checking, if it was paused using [pauseCredentialChecking]. This +     * doesn't flush any pending coroutine jobs; the test code may still choose to do that using +     * `runCurrent`. +     */ +    fun unpauseCredentialChecking() { +        credentialCheckingMutex.unlock() +    } +      private fun getExpectedCredential(securityMode: SecurityMode): List<Any> {          return when (val credentialType = getCurrentCredentialType(securityMode)) {              LockPatternUtils.CREDENTIAL_TYPE_PIN -> credentialOverride ?: DEFAULT_PIN diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt index 9cbe6337befe..2ae6f542ac3e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt @@ -17,6 +17,7 @@  package com.android.systemui.biometrics.ui.viewmodel  import android.content.applicationContext +import com.android.systemui.biometrics.domain.interactor.biometricStatusInteractor  import com.android.systemui.biometrics.domain.interactor.displayStateInteractor  import com.android.systemui.biometrics.domain.interactor.promptSelectorInteractor  import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor @@ -30,6 +31,7 @@ val Kosmos.promptViewModel by Fixture {          promptSelectorInteractor = promptSelectorInteractor,          context = applicationContext,          udfpsOverlayInteractor = udfpsOverlayInteractor, +        biometricStatusInteractor = biometricStatusInteractor,          udfpsUtils = udfpsUtils      )  } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/BroadcastDialogControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/BroadcastDialogControllerKosmos.kt new file mode 100644 index 000000000000..e9d72664c6b0 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/BroadcastDialogControllerKosmos.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.bluetooth + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock + +val Kosmos.mockBroadcastDialogController by Kosmos.Fixture { mock<BroadcastDialogController>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt index c06554573bd7..9ce9ff2faf21 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorKosmos.kt @@ -24,6 +24,7 @@ import com.android.systemui.kosmos.Kosmos  import com.android.systemui.kosmos.Kosmos.Fixture  import com.android.systemui.kosmos.testScope  import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.scene.domain.interactor.sceneInteractor  val Kosmos.bouncerInteractor by Fixture {      BouncerInteractor( @@ -33,5 +34,6 @@ val Kosmos.bouncerInteractor by Fixture {          deviceEntryFaceAuthInteractor = deviceEntryFaceAuthInteractor,          falsingInteractor = falsingInteractor,          powerInteractor = powerInteractor, +        sceneInteractor = sceneInteractor,      )  } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt index 0f6c7cf13211..c3dad748064d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt @@ -18,6 +18,7 @@  package com.android.systemui.bouncer.ui.viewmodel +import android.app.admin.devicePolicyManager  import android.content.applicationContext  import com.android.systemui.authentication.domain.interactor.authenticationInteractor  import com.android.systemui.bouncer.domain.interactor.bouncerActionButtonInteractor @@ -31,7 +32,6 @@ import com.android.systemui.kosmos.testDispatcher  import com.android.systemui.kosmos.testScope  import com.android.systemui.user.domain.interactor.selectedUserInteractor  import com.android.systemui.user.ui.viewmodel.userSwitcherViewModel -import com.android.systemui.util.mockito.mock  import kotlinx.coroutines.ExperimentalCoroutinesApi  val Kosmos.bouncerViewModel by Fixture { @@ -44,12 +44,12 @@ val Kosmos.bouncerViewModel by Fixture {          simBouncerInteractor = simBouncerInteractor,          authenticationInteractor = authenticationInteractor,          selectedUserInteractor = selectedUserInteractor, +        devicePolicyManager = devicePolicyManager, +        bouncerMessageViewModel = bouncerMessageViewModel,          flags = composeBouncerFlags,          selectedUser = userSwitcherViewModel.selectedUser,          users = userSwitcherViewModel.users,          userSwitcherMenu = userSwitcherViewModel.menu,          actionButton = bouncerActionButtonInteractor.actionButton, -        devicePolicyManager = mock(), -        bouncerMessageViewModel = bouncerMessageViewModel,      )  } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt index 8866fd31faac..4b6ef373a7ee 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt @@ -23,6 +23,7 @@ import com.android.systemui.communal.data.repository.communalPrefsRepository  import com.android.systemui.communal.data.repository.communalRepository  import com.android.systemui.communal.data.repository.communalWidgetRepository  import com.android.systemui.communal.widgets.EditWidgetsActivityStarter +import com.android.systemui.dock.fakeDockManager  import com.android.systemui.flags.Flags  import com.android.systemui.flags.fakeFeatureFlagsClassic  import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository @@ -33,7 +34,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope  import com.android.systemui.log.logcatLogBuffer  import com.android.systemui.plugins.activityStarter  import com.android.systemui.scene.domain.interactor.sceneInteractor -import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags +import com.android.systemui.scene.shared.flag.sceneContainerFlags  import com.android.systemui.settings.userTracker  import com.android.systemui.smartspace.data.repository.smartspaceRepository  import com.android.systemui.user.data.repository.fakeUserRepository @@ -54,11 +55,12 @@ val Kosmos.communalInteractor by Fixture {          userTracker = userTracker,          activityStarter = activityStarter,          userManager = userManager, +        dockManager = fakeDockManager,          logBuffer = logcatLogBuffer("CommunalInteractor"),          tableLogBuffer = mock(),          communalSettingsInteractor = communalSettingsInteractor,          sceneInteractor = sceneInteractor, -        sceneContainerFlags = fakeSceneContainerFlags, +        sceneContainerFlags = sceneContainerFlags,      )  } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt index b4773f69f1c5..cd2710ef8757 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorKosmos.kt @@ -17,17 +17,21 @@  package com.android.systemui.communal.domain.interactor  import com.android.systemui.communal.data.repository.communalSettingsRepository +import com.android.systemui.concurrency.fakeExecutor  import com.android.systemui.kosmos.Kosmos  import com.android.systemui.kosmos.Kosmos.Fixture  import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.settings.userTracker  import com.android.systemui.user.domain.interactor.selectedUserInteractor  import com.android.systemui.util.mockito.mock  val Kosmos.communalSettingsInteractor by Fixture {      CommunalSettingsInteractor(          bgScope = applicationCoroutineScope, +        bgExecutor = fakeExecutor,          repository = communalSettingsRepository,          userInteractor = selectedUserInteractor, +        userTracker = userTracker,          tableLogBuffer = mock(),      )  } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt index 23967224e43a..e36ddc17e5a8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt @@ -16,6 +16,8 @@  package com.android.systemui.communal.ui.viewmodel +import com.android.systemui.communal.domain.interactor.communalInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor  import com.android.systemui.keyguard.ui.viewmodel.dreamingToGlanceableHubTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToDreamingTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTransitionViewModel @@ -27,9 +29,13 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi  val Kosmos.communalTransitionViewModel by      Kosmos.Fixture {          CommunalTransitionViewModel( -            glanceableHubToLockscreenTransitionViewModel, -            lockscreenToGlanceableHubTransitionViewModel, -            dreamingToGlanceableHubTransitionViewModel, -            glanceableHubToDreamingTransitionViewModel, +            glanceableHubToLockscreenTransitionViewModel = +                glanceableHubToLockscreenTransitionViewModel, +            lockscreenToGlanceableHubTransitionViewModel = +                lockscreenToGlanceableHubTransitionViewModel, +            dreamToGlanceableHubTransitionViewModel = dreamingToGlanceableHubTransitionViewModel, +            glanceableHubToDreamTransitionViewModel = glanceableHubToDreamingTransitionViewModel, +            communalInteractor = communalInteractor, +            keyguardTransitionInteractor = keyguardTransitionInteractor,          )      } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt index 0fc0a3c20f70..6c3cf91ec751 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt @@ -23,6 +23,8 @@ import dagger.Module  import javax.inject.Inject  import kotlinx.coroutines.flow.Flow  import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow  import org.mockito.Mockito.`when` as whenever  /** Creates a mock display. */ @@ -69,12 +71,20 @@ class FakeDisplayRepository @Inject constructor() : DisplayRepository {      override val pendingDisplay: Flow<DisplayRepository.PendingDisplay?>          get() = pendingDisplayFlow +    val _defaultDisplayOff: MutableStateFlow<Boolean> = MutableStateFlow(false) +    override val defaultDisplayOff: Flow<Boolean> +        get() = _defaultDisplayOff.asStateFlow() +      override val displayAdditionEvent: Flow<Display?>          get() = displayAdditionEventFlow      private val _displayChangeEvent = MutableSharedFlow<Int>(replay = 1)      override val displayChangeEvent: Flow<Int> = _displayChangeEvent      suspend fun emitDisplayChangeEvent(displayId: Int) = _displayChangeEvent.emit(displayId) + +    fun setDefaultDisplayOff(defaultDisplayOff: Boolean) { +        _defaultDisplayOff.value = defaultDisplayOff +    }  }  @Module diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.java index 37540621557f..b99310bcbe38 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFake.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFake.java @@ -49,6 +49,7 @@ public class DockManagerFake implements DockManager {          return mDocked;      } +    /** Sets the docked state */      public void setIsDocked(boolean docked) {          mDocked = docked;      } @@ -58,6 +59,7 @@ public class DockManagerFake implements DockManager {          return false;      } +    /** Notifies callbacks of dock state change */      public void setDockEvent(int event) {          mCallback.onEvent(event);      } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFakeKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFakeKosmos.kt index 06275fa226a5..06275fa226a5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dock/DockManagerFakeKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/dock/DockManagerFakeKosmos.kt diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/BrokenWithSceneContainer.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/BrokenWithSceneContainer.kt new file mode 100644 index 000000000000..29b088b0afc1 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/BrokenWithSceneContainer.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.flags + +import com.android.systemui.Flags.FLAG_SCENE_CONTAINER + +/** + * This is used by [SceneContainerRule] to assert that the test is broken when + * [FLAG_SCENE_CONTAINER] is enabled. + */ +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) +annotation class BrokenWithSceneContainer(val bugId: Int) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/DisableSceneContainer.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/DisableSceneContainer.kt new file mode 100644 index 000000000000..09f34308bdb9 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/DisableSceneContainer.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.flags + +import android.platform.test.annotations.DisableFlags +import com.android.systemui.Flags.FLAG_SCENE_CONTAINER + +/** + * This includes @[DisableFlags] to work with [SetFlagsRule] to disable all aconfig flags required + * by that feature. + */ +@DisableFlags( +    FLAG_SCENE_CONTAINER, +) +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) +annotation class DisableSceneContainer diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt index c1d2ad6e1be3..e83205c5a859 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt @@ -18,12 +18,14 @@ package com.android.systemui.flags  import android.platform.test.annotations.EnableFlags  import com.android.systemui.Flags.FLAG_COMPOSE_LOCKSCREEN +import com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR  import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR  import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR  import com.android.systemui.Flags.FLAG_MEDIA_IN_SCENE_CONTAINER  import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT  import com.android.systemui.Flags.FLAG_NOTIFICATIONS_HEADS_UP_REFACTOR  import com.android.systemui.Flags.FLAG_PREDICTIVE_BACK_SYSUI +import com.android.systemui.Flags.FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT  import com.android.systemui.Flags.FLAG_SCENE_CONTAINER  /** @@ -39,6 +41,8 @@ import com.android.systemui.Flags.FLAG_SCENE_CONTAINER      FLAG_NOTIFICATIONS_HEADS_UP_REFACTOR,      FLAG_PREDICTIVE_BACK_SYSUI,      FLAG_SCENE_CONTAINER, +    FLAG_DEVICE_ENTRY_UDFPS_REFACTOR, +    FLAG_REFACTOR_KEYGUARD_DISMISS_INTENT,  )  @Retention(AnnotationRetention.RUNTIME)  @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsClassicKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsClassicKosmos.kt index d6f2f77ca67a..45ea36464194 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsClassicKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FeatureFlagsClassicKosmos.kt @@ -34,8 +34,9 @@ val Kosmos.fakeFeatureFlagsClassic by      Kosmos.Fixture {          FakeFeatureFlagsClassic().apply {              set(Flags.FULL_SCREEN_USER_SWITCHER, false) -            set(Flags.NSSL_DEBUG_LINES, false)              set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, false) +            set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false) +            set(Flags.NSSL_DEBUG_LINES, false)          }      } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerFlagParameterization.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerFlagParameterization.kt new file mode 100644 index 000000000000..4e24233a6681 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerFlagParameterization.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.flags + +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.FlagsParameterization +import com.android.systemui.Flags.FLAG_SCENE_CONTAINER + +/** The name of the one flag to be disabled for OFF parameterization */ +private const val flagNameToDisable = FLAG_SCENE_CONTAINER + +/** Cache of the flags to be enabled for ON parameterization */ +private val flagNamesToEnable = +    EnableSceneContainer::class.java.getAnnotation(EnableFlags::class.java)!!.value.toList() + +/** + * Provides one or two copies of this [FlagsParameterization]; one which disabled + * [FLAG_SCENE_CONTAINER] and if none of the dependencies of it are disabled by this, a second copy + * which enables [FLAG_SCENE_CONTAINER] and all the dependencies (just like [EnableSceneContainer]). + */ +fun FlagsParameterization.andSceneContainer(): Sequence<FlagsParameterization> = sequence { +    check(flagNameToDisable !in mOverrides) { +        "Can't add $flagNameToDisable to FlagsParameterization: $this" +    } +    yield(FlagsParameterization(mOverrides + mapOf(flagNameToDisable to false))) +    if (flagNamesToEnable.all { mOverrides[it] != false }) { +        // Can't add the parameterization of enabling SceneContainerFlag to a parameterization that +        // explicitly disables one of the prerequisite flags. +        yield(FlagsParameterization(mOverrides + flagNamesToEnable.associateWith { true })) +    } +} + +/** + * Doubles (roughly; see below) the given list of [FlagsParameterization] for enabling and disabling + * SceneContainerFlag. + * + * The input parameterization may not define [FLAG_SCENE_CONTAINER]. + * + * Any [FlagsParameterization] which disables any flag that is a dependency of + * [FLAG_SCENE_CONTAINER], will not add a state for enabling, and the state will simply be converted + * to one which disables. Just like [EnableSceneContainer], enabling will also enable all the other + * dependencies. For any flag parameterization where a dependency is disabled, an "enabled" + * parameterization is inconsistent, so it will not be added. + */ +fun List<FlagsParameterization>.andSceneContainer(): List<FlagsParameterization> = +    flatMap { it.andSceneContainer() }.toList() diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt index 775ad14d4ad9..9ec1481355a5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/SceneContainerRule.kt @@ -18,6 +18,7 @@ package com.android.systemui.flags  import com.android.systemui.scene.shared.flag.SceneContainerFlag  import org.junit.Assert +import org.junit.AssumptionViolatedException  import org.junit.rules.TestRule  import org.junit.runner.Description  import org.junit.runners.model.Statement @@ -33,10 +34,7 @@ class SceneContainerRule : TestRule {          return object : Statement() {              @Throws(Throwable::class)              override fun evaluate() { -                val hasAnnotation = -                    description?.testClass?.getAnnotation(EnableSceneContainer::class.java) != -                        null || description?.getAnnotation(EnableSceneContainer::class.java) != null -                if (hasAnnotation) { +                if (description.hasAnnotation<EnableSceneContainer>()) {                      Assert.assertTrue(                          "SceneContainerFlag.isEnabled is false:" +                              "\n * Did you forget to add a new aconfig flag dependency in" + @@ -45,8 +43,31 @@ class SceneContainerRule : TestRule {                          SceneContainerFlag.isEnabled                      )                  } +                if ( +                    description.hasAnnotation<BrokenWithSceneContainer>() && +                        SceneContainerFlag.isEnabled +                ) { +                    runCatching { base?.evaluate() } +                        .onFailure { exception -> +                            if (exception is AssumptionViolatedException) { +                                throw AssertionError( +                                    "This is marked @BrokenWithSceneContainer, but was skipped.", +                                    exception +                                ) +                            } +                            throw AssumptionViolatedException("Test is still broken", exception) +                        } +                    throw AssertionError( +                        "HOORAY! You fixed a test that was marked @BrokenWithSceneContainer. " + +                            "Remove the obsolete annotation to fix this failure." +                    ) +                }                  base?.evaluate()              }          }      } + +    inline fun <reified T : Annotation> Description?.hasAnnotation(): Boolean = +        this?.testClass?.getAnnotation(T::class.java) != null || +            this?.getAnnotation(T::class.java) != null  } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt new file mode 100644 index 000000000000..636d509663a2 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/qs/QSLongPressEffectKosmos.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.haptics.qs + +import com.android.systemui.haptics.vibratorHelper +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope + +val Kosmos.qsLongPressEffect by +    Kosmos.Fixture { QSLongPressEffect(vibratorHelper, keyguardInteractor, testScope) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt index eba5a11cecdb..4f2310f9972d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardClockRepository.kt @@ -50,14 +50,25 @@ class FakeKeyguardClockRepository @Inject constructor() : KeyguardClockRepositor          get() = _previewClock      override val clockEventController: ClockEventController          get() = mock() +    override val shouldForceSmallClock: Boolean +        get() = _shouldForceSmallClock +    private var _shouldForceSmallClock: Boolean = false      override fun setClockSize(@ClockSize size: Int) {          _clockSize.value = size      } +    fun setSelectedClockSize(size: SettingsClockSize) { +        selectedClockSize.value = size +    } +      fun setCurrentClock(clockController: ClockController) {          _currentClock.value = clockController      } + +    fun setShouldForceSmallClock(shouldForceSmallClock: Boolean) { +        _shouldForceSmallClock = shouldForceSmallClock +    }  }  @Module diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt index 75489b617120..8954231a9731 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt @@ -17,8 +17,6 @@  package com.android.systemui.keyguard.data.repository  import android.os.fakeExecutorHandler -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID -import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID  import com.android.systemui.keyguard.shared.model.KeyguardBlueprint  import com.android.systemui.keyguard.shared.model.KeyguardSection  import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint.Companion.DEFAULT @@ -34,8 +32,6 @@ val Kosmos.keyguardBlueprintRepository by                  setOf(                      defaultBlueprint,                      splitShadeBlueprint, -                    weatherClockBlueprint, -                    splitShadeWeatherClockBlueprint,                  ),              handler = fakeExecutorHandler,              assert = mock<ThreadAssert>(), @@ -50,22 +46,6 @@ private val defaultBlueprint =              get() = listOf()      } -private val weatherClockBlueprint = -    object : KeyguardBlueprint { -        override val id: String -            get() = WEATHER_CLOCK_BLUEPRINT_ID -        override val sections: List<KeyguardSection> -            get() = listOf() -    } - -private val splitShadeWeatherClockBlueprint = -    object : KeyguardBlueprint { -        override val id: String -            get() = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID -        override val sections: List<KeyguardSection> -            get() = listOf() -    } -  private val splitShadeBlueprint =      object : KeyguardBlueprint {          override val id: String diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt index 12165cdc5658..d52883eb38af 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractorKosmos.kt @@ -18,6 +18,22 @@ package com.android.systemui.keyguard.domain.interactor  import com.android.systemui.keyguard.data.repository.keyguardClockRepository  import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor +import com.android.systemui.shade.domain.interactor.shadeInteractor +import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor +import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor  val Kosmos.keyguardClockInteractor by -    Kosmos.Fixture { KeyguardClockInteractor(keyguardClockRepository) } +    Kosmos.Fixture { +        KeyguardClockInteractor( +            keyguardClockRepository = keyguardClockRepository, +            applicationScope = applicationCoroutineScope, +            mediaCarouselInteractor = mediaCarouselInteractor, +            activeNotificationsInteractor = activeNotificationsInteractor, +            shadeInteractor = shadeInteractor, +            keyguardInteractor = keyguardInteractor, +            keyguardTransitionInteractor = keyguardTransitionInteractor, +            headsUpNotificationInteractor = headsUpNotificationInteractor, +        ) +    } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt new file mode 100644 index 000000000000..2c6d44f10152 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.keyguard.domain.interactor + +import com.android.systemui.keyguard.data.repository.keyguardRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@ExperimentalCoroutinesApi +val Kosmos.keyguardDismissActionInteractor by +    Kosmos.Fixture { +        KeyguardDismissActionInteractor( +            repository = keyguardRepository, +            transitionInteractor = keyguardTransitionInteractor, +            dismissInteractor = keyguardDismissInteractor, +            applicationScope = testScope.backgroundScope, +        ) +    } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt new file mode 100644 index 000000000000..f33ca95e488d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.keyguard.domain.interactor + +import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor +import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor +import com.android.systemui.keyguard.data.repository.keyguardRepository +import com.android.systemui.keyguard.data.repository.trustRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.user.domain.interactor.selectedUserInteractor +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@ExperimentalCoroutinesApi +val Kosmos.keyguardDismissInteractor by +    Kosmos.Fixture { +        KeyguardDismissInteractor( +            trustRepository = trustRepository, +            keyguardRepository = keyguardRepository, +            primaryBouncerInteractor = primaryBouncerInteractor, +            alternateBouncerInteractor = alternateBouncerInteractor, +            powerInteractor = powerInteractor, +            selectedUserInteractor = selectedUserInteractor, +        ) +    } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt index 185deda950c6..6cc1e8eba73d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorKosmos.kt @@ -20,13 +20,11 @@ import com.android.systemui.keyguard.data.repository.keyguardRepository  import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository  import com.android.systemui.kosmos.Kosmos  import com.android.systemui.kosmos.applicationCoroutineScope -import com.android.systemui.kosmos.testDispatcher  val Kosmos.keyguardTransitionInteractor: KeyguardTransitionInteractor by      Kosmos.Fixture {          KeyguardTransitionInteractor(              scope = applicationCoroutineScope, -            mainDispatcher = testDispatcher,              repository = keyguardTransitionRepository,              keyguardRepository = keyguardRepository,              fromLockscreenTransitionInteractor = { fromLockscreenTransitionInteractor }, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt index f7de5a4c20c7..1a05d21cc30a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt @@ -22,14 +22,10 @@ import com.android.keyguard.logging.keyguardTransitionAnimationLogger  import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor  import com.android.systemui.kosmos.Kosmos  import com.android.systemui.kosmos.Kosmos.Fixture -import com.android.systemui.kosmos.applicationCoroutineScope -import com.android.systemui.kosmos.testDispatcher  import kotlinx.coroutines.ExperimentalCoroutinesApi  val Kosmos.keyguardTransitionAnimationFlow by Fixture {      KeyguardTransitionAnimationFlow( -        scope = applicationCoroutineScope, -        mainDispatcher = testDispatcher,          transitionInteractor = keyguardTransitionInteractor,          logger = keyguardTransitionAnimationLogger,      ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt index ffa4133c7269..9774e4aa51a5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt @@ -19,21 +19,19 @@  package com.android.systemui.keyguard.ui.viewmodel  import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor -import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.domain.interactor.keyguardDismissActionInteractor  import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow  import com.android.systemui.kosmos.Kosmos  import com.android.systemui.kosmos.Kosmos.Fixture  import com.android.systemui.shade.domain.interactor.shadeInteractor  import com.android.systemui.statusbar.sysuiStatusBarStateController -import com.android.systemui.util.mockito.mock  import kotlinx.coroutines.ExperimentalCoroutinesApi  val Kosmos.bouncerToGoneFlows by Fixture {      BouncerToGoneFlows(          statusBarStateController = sysuiStatusBarStateController,          primaryBouncerInteractor = mockPrimaryBouncerInteractor, -        keyguardDismissActionInteractor = mock(), -        featureFlags = featureFlagsClassic, +        keyguardDismissActionInteractor = { keyguardDismissActionInteractor },          shadeInteractor = shadeInteractor,          animationFlow = keyguardTransitionAnimationFlow,      ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt index 60dd48aeaf61..a048d3cfffca 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt @@ -17,7 +17,6 @@  package com.android.systemui.keyguard.ui.viewmodel  import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardInteractor  import com.android.systemui.kosmos.Kosmos  import com.android.systemui.kosmos.applicationCoroutineScope  import com.android.systemui.shade.domain.interactor.shadeInteractor @@ -26,7 +25,6 @@ import com.android.systemui.statusbar.notification.stack.domain.interactor.notif  val Kosmos.keyguardClockViewModel by      Kosmos.Fixture {          KeyguardClockViewModel( -            keyguardInteractor = keyguardInteractor,              keyguardClockInteractor = keyguardClockInteractor,              applicationScope = applicationCoroutineScope,              notifsKeyguardInteractor = notificationsKeyguardInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..3b96912b53c6 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModelKosmos.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +var Kosmos.occludedToGoneTransitionViewModel by Fixture { +    OccludedToGoneTransitionViewModel( +        animationFlow = keyguardTransitionAnimationFlow, +    ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt index e6651a44236f..f86e9b7216ce 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt @@ -20,6 +20,8 @@ package com.android.systemui.keyguard.ui.viewmodel  import com.android.systemui.common.ui.domain.interactor.configurationInteractor  import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor  import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow  import com.android.systemui.kosmos.Kosmos  import com.android.systemui.kosmos.Kosmos.Fixture @@ -30,5 +32,7 @@ var Kosmos.occludedToLockscreenTransitionViewModel by Fixture {          deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,          configurationInteractor = configurationInteractor,          animationFlow = keyguardTransitionAnimationFlow, +        keyguardInteractor = keyguardInteractor, +        keyguardTransitionInteractor = keyguardTransitionInteractor,      )  } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt index 4ecff73f71ed..d6edea29d6f0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt @@ -19,20 +19,18 @@  package com.android.systemui.keyguard.ui.viewmodel  import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor -import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.keyguard.domain.interactor.keyguardDismissActionInteractor  import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow  import com.android.systemui.kosmos.Kosmos  import com.android.systemui.kosmos.Kosmos.Fixture  import com.android.systemui.statusbar.sysuiStatusBarStateController -import com.android.systemui.util.mockito.mock  import kotlinx.coroutines.ExperimentalCoroutinesApi  val Kosmos.primaryBouncerToGoneTransitionViewModel by Fixture {      PrimaryBouncerToGoneTransitionViewModel(          statusBarStateController = sysuiStatusBarStateController,          primaryBouncerInteractor = mockPrimaryBouncerInteractor, -        keyguardDismissActionInteractor = mock(), -        featureFlags = featureFlagsClassic, +        keyguardDismissActionInteractor = { keyguardDismissActionInteractor },          bouncerToGoneFlows = bouncerToGoneFlows,          animationFlow = keyguardTransitionAnimationFlow,      ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt index afc8f309f6d2..fdc3e0a22627 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt @@ -33,6 +33,7 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor  import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor  import com.android.systemui.flags.fakeFeatureFlagsClassic  import com.android.systemui.globalactions.domain.interactor.globalActionsInteractor +import com.android.systemui.haptics.qs.qsLongPressEffect  import com.android.systemui.jank.interactionJankMonitor  import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository  import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository @@ -48,6 +49,7 @@ import com.android.systemui.power.domain.interactor.powerInteractor  import com.android.systemui.scene.domain.interactor.sceneInteractor  import com.android.systemui.scene.sceneContainerConfig  import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags +import com.android.systemui.scene.shared.flag.sceneContainerFlags  import com.android.systemui.scene.shared.model.sceneDataSource  import com.android.systemui.settings.brightness.domain.interactor.brightnessMirrorShowingInteractor  import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor @@ -70,6 +72,7 @@ class KosmosJavaAdapter(      val testScope by lazy { kosmos.testScope }      val fakeFeatureFlags by lazy { kosmos.fakeFeatureFlagsClassic }      val fakeSceneContainerFlags by lazy { kosmos.fakeSceneContainerFlags } +    val sceneContainerFlags by lazy { kosmos.sceneContainerFlags }      val fakeExecutor by lazy { kosmos.fakeExecutor }      val fakeExecutorHandler by lazy { kosmos.fakeExecutorHandler }      val configurationRepository by lazy { kosmos.fakeConfigurationRepository } @@ -108,6 +111,7 @@ class KosmosJavaAdapter(          kosmos.sharedNotificationContainerInteractor      }      val brightnessMirrorShowingInteractor by lazy { kosmos.brightnessMirrorShowingInteractor } +    val qsLongPressEffect by lazy { kosmos.qsLongPressEffect }      init {          kosmos.applicationContext = testCase.context diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractorKosmos.kt index 29c5bd5dd1d4..81adefa11c9b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractorKosmos.kt @@ -16,16 +16,30 @@  package com.android.systemui.media.controls.domain.pipeline.interactor +import android.content.applicationContext +import com.android.systemui.activityIntentHelper +import com.android.systemui.bluetooth.mockBroadcastDialogController  import com.android.systemui.kosmos.Kosmos  import com.android.systemui.media.controls.data.repository.mediaFilterRepository  import com.android.systemui.media.controls.domain.pipeline.mediaDataProcessor  import com.android.systemui.media.controls.util.mediaInstanceId +import com.android.systemui.media.mediaOutputDialogManager +import com.android.systemui.plugins.activityStarter +import com.android.systemui.statusbar.notificationLockscreenUserManager +import com.android.systemui.statusbar.policy.keyguardStateController  val Kosmos.mediaControlInteractor by      Kosmos.Fixture {          MediaControlInteractor( +            applicationContext = applicationContext,              instanceId = mediaInstanceId,              repository = mediaFilterRepository,              mediaDataProcessor = mediaDataProcessor, +            keyguardStateController = keyguardStateController, +            activityStarter = activityStarter, +            activityIntentHelper = activityIntentHelper, +            lockscreenUserManager = notificationLockscreenUserManager, +            mediaOutputDialogManager = mediaOutputDialogManager, +            broadcastDialogController = mockBroadcastDialogController,          )      } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelKosmos.kt new file mode 100644 index 000000000000..da2170c85fe7 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelKosmos.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.controls.ui.viewmodel + +import android.content.applicationContext +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.media.controls.domain.pipeline.interactor.mediaControlInteractor +import com.android.systemui.media.controls.util.mediaUiEventLogger + +val Kosmos.mediaControlViewModel by +    Kosmos.Fixture { +        MediaControlViewModel( +            applicationContext = applicationContext, +            backgroundDispatcher = testDispatcher, +            interactor = mediaControlInteractor, +            logger = mediaUiEventLogger, +        ) +    } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt index bae5257a98bd..ded725683e59 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt @@ -21,7 +21,7 @@ import dagger.Module  import dagger.Provides  class FakeSceneContainerFlags( -    var enabled: Boolean = false, +    var enabled: Boolean = SceneContainerFlag.isEnabled,  ) : SceneContainerFlags {      override fun isEnabled(): Boolean { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/data/repository/HeadsUpNotificationRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/data/repository/HeadsUpNotificationRepositoryKosmos.kt index 165c9429c917..dc1b9feea88f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/data/repository/HeadsUpNotificationRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/data/repository/HeadsUpNotificationRepositoryKosmos.kt @@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.MutableStateFlow  val Kosmos.headsUpNotificationRepository by Fixture { FakeHeadsUpNotificationRepository() }  class FakeHeadsUpNotificationRepository : HeadsUpRepository { -    override val headsUpAnimatingAway: MutableStateFlow<Boolean> = MutableStateFlow(false) +    override val isHeadsUpAnimatingAway: MutableStateFlow<Boolean> = MutableStateFlow(false)      override val topHeadsUpRow: Flow<HeadsUpRowRepository?> = MutableStateFlow(null)      override val activeHeadsUpRows: MutableStateFlow<Set<HeadsUpRowRepository>> =          MutableStateFlow(emptySet()) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt index d2de835ad954..45b28b1d8842 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt @@ -36,6 +36,7 @@ import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGoneTransitionView  import com.android.systemui.keyguard.ui.viewmodel.lockscreenToOccludedTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.lockscreenToPrimaryBouncerTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.occludedToAodTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.occludedToGoneTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.occludedToLockscreenTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.primaryBouncerToGoneTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.primaryBouncerToLockscreenTransitionViewModel @@ -74,6 +75,7 @@ val Kosmos.sharedNotificationContainerViewModel by Fixture {          lockscreenToPrimaryBouncerTransitionViewModel =              lockscreenToPrimaryBouncerTransitionViewModel,          occludedToAodTransitionViewModel = occludedToAodTransitionViewModel, +        occludedToGoneTransitionViewModel = occludedToGoneTransitionViewModel,          occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,          primaryBouncerToGoneTransitionViewModel = primaryBouncerToGoneTransitionViewModel,          primaryBouncerToLockscreenTransitionViewModel = diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt index 2d5a3612ff6a..eb2d6c0f5405 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt @@ -31,6 +31,7 @@ class FakeMobileConnectionRepository(      override val tableLogBuffer: TableLogBuffer,  ) : MobileConnectionRepository {      override val carrierId = MutableStateFlow(UNKNOWN_CARRIER_ID) +    override val inflateSignalStrength: MutableStateFlow<Boolean> = MutableStateFlow(false)      override val isEmergencyOnly = MutableStateFlow(false)      override val isRoaming = MutableStateFlow(false)      override val operatorAlphaShort: MutableStateFlow<String?> = MutableStateFlow(null) @@ -63,8 +64,6 @@ class FakeMobileConnectionRepository(      override val hasPrioritizedNetworkCapabilities = MutableStateFlow(false) -    override val satelliteConnectionHysteresisSeconds = MutableStateFlow(0) -      private var isInEcmMode: Boolean = false      override suspend fun isInEcmMode(): Boolean = isInEcmMode diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/truth/TruthUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/truth/TruthUtils.kt new file mode 100644 index 000000000000..64fed689d7a9 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/truth/TruthUtils.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.truth + +import com.google.common.truth.MapSubject +import com.google.common.truth.Ordered + +fun MapSubject.containsEntriesExactly(entry: Pair<*, *>, vararg entries: Pair<*, *>): Ordered = +    containsExactly( +        entry.first, +        entry.second, +        *entries +            .asSequence() +            .flatMap { (key, value) -> sequenceOf(key, value) } +            .toList() +            .toTypedArray() +    ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt index d3410737a432..348a02e1da04 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt @@ -24,6 +24,7 @@ import com.android.systemui.util.mockito.mock  import com.android.systemui.volume.panel.dagger.factory.KosmosVolumePanelComponentFactory  import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria  import com.android.systemui.volume.panel.domain.TestComponentAvailabilityCriteria +import com.android.systemui.volume.panel.domain.VolumePanelStartable  import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractor  import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractorImpl  import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey @@ -44,6 +45,8 @@ val Kosmos.componentsFactory: ComponentsFactory by  var Kosmos.componentsLayoutManager: ComponentsLayoutManager by Kosmos.Fixture()  var Kosmos.enabledComponents: Collection<VolumePanelComponentKey> by      Kosmos.Fixture { componentByKey.keys } +var Kosmos.volumePanelStartables: Set<VolumePanelStartable> by +    Kosmos.Fixture { emptySet<VolumePanelStartable>() }  val Kosmos.unavailableCriteria: Provider<ComponentAvailabilityCriteria> by      Kosmos.Fixture { Provider { TestComponentAvailabilityCriteria(false) } }  val Kosmos.availableCriteria: Provider<ComponentAvailabilityCriteria> by diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt index b66d7f974eca..d4a72b437fd8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt @@ -24,8 +24,9 @@ class FakeAncSliceRepository : AncSliceRepository {      private val sliceByWidth = mutableMapOf<Int, MutableStateFlow<Slice?>>() -    override fun ancSlice(width: Int): Flow<Slice?> = -        sliceByWidth.getOrPut(width) { MutableStateFlow(null) } +    override fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> { +        return sliceByWidth.getOrPut(width) { MutableStateFlow(null) } +    }      fun putSlice(width: Int, slice: Slice?) {          sliceByWidth.getOrPut(width) { MutableStateFlow(null) }.value = slice diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt index 49041ed0d652..e5f5d4e389f1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt @@ -22,10 +22,12 @@ import com.android.systemui.volume.panel.componentsFactory  import com.android.systemui.volume.panel.componentsInteractor  import com.android.systemui.volume.panel.componentsLayoutManager  import com.android.systemui.volume.panel.dagger.VolumePanelComponent +import com.android.systemui.volume.panel.domain.VolumePanelStartable  import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractor  import com.android.systemui.volume.panel.ui.composable.ComponentsFactory  import com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager  import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel +import com.android.systemui.volume.panel.volumePanelStartables  import kotlinx.coroutines.CoroutineScope  class KosmosVolumePanelComponentFactory(private val kosmos: Kosmos) : VolumePanelComponentFactory { @@ -41,5 +43,8 @@ class KosmosVolumePanelComponentFactory(private val kosmos: Kosmos) : VolumePane              override fun componentsLayoutManager(): ComponentsLayoutManager =                  kosmos.componentsLayoutManager + +            override fun volumePanelStartables(): Set<VolumePanelStartable> = +                kosmos.volumePanelStartables          }  } diff --git a/packages/overlays/NoCutoutOverlay/res/values-ne/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ne/strings.xml index ff920b290dbb..97559b4feda8 100644 --- a/packages/overlays/NoCutoutOverlay/res/values-ne/strings.xml +++ b/packages/overlays/NoCutoutOverlay/res/values-ne/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="display_cutout_emulation_overlay" msgid="9031691255599853162">"लुकाइयोस्"</string> +    <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"लुकाउनुहोस्"</string>  </resources> diff --git a/proto/src/am_capabilities.proto b/proto/src/am_capabilities.proto index d97bf816b150..fc9f7a4590bd 100644 --- a/proto/src/am_capabilities.proto +++ b/proto/src/am_capabilities.proto @@ -7,6 +7,16 @@ message Capability {    string name = 1;  } +message VMCapability { +  string name  = 1; +} + +message FrameworkCapability { +  string name  = 1; +} +  message Capabilities {    repeated Capability values = 1; +  repeated VMCapability vm_capabilities = 2; +  repeated FrameworkCapability framework_capabilities = 3;  } diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java index 741411095f53..0f65544f8b66 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java +++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/LongArrayMultiStateCounter_host.java @@ -100,6 +100,16 @@ public class LongArrayMultiStateCounter_host {              mLastStateChangeTimestampMs = timestampMs;          } +        public void copyStatesFrom(LongArrayMultiStateCounterRavenwood source) { +            for (int i = 0; i < mStateCount; i++) { +                mStates[i].mTimeInStateSinceUpdate = source.mStates[i].mTimeInStateSinceUpdate; +                Arrays.fill(mStates[i].mCounter, 0); +            } +            mCurrentState = source.mCurrentState; +            mLastStateChangeTimestampMs = source.mLastStateChangeTimestampMs; +            mLastUpdateTimestampMs = source.mLastUpdateTimestampMs; +        } +          public void setValue(int state, long[] values) {              System.arraycopy(values, 0, mStates[state].mCounter, 0, mArrayLength);          } @@ -335,6 +345,10 @@ public class LongArrayMultiStateCounter_host {          getInstance(instanceId).setState(state, timestampMs);      } +    public static void native_copyStatesFrom(long targetInstanceId, long sourceInstanceId) { +        getInstance(targetInstanceId).copyStatesFrom(getInstance(sourceInstanceId)); +    } +      public static void native_incrementValues(long instanceId, long containerInstanceId,              long timestampMs) {          getInstance(instanceId).incrementValues( diff --git a/ravenwood/test-authors.md b/ravenwood/test-authors.md index 7c0cee812996..2ab43bbeaad0 100644 --- a/ravenwood/test-authors.md +++ b/ravenwood/test-authors.md @@ -17,6 +17,7 @@ android_ravenwood_test {      name: "MyTestsRavenwood",      static_libs: [          "androidx.annotation_annotation", +        "androidx.test.ext.junit",          "androidx.test.rules",      ],      srcs: [ @@ -34,7 +35,7 @@ android_ravenwood_test {  import android.platform.test.annotations.IgnoreUnderRavenwood;  import android.platform.test.ravenwood.RavenwoodRule; -import androidx.test.runner.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4;  import org.junit.Test;  import org.junit.runner.RunWith; diff --git a/services/Android.bp b/services/Android.bp index 623519521a5a..cd974c5f562d 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -324,34 +324,34 @@ non_updatable_exportable_droidstubs {              baseline_file: "api/lint-baseline.txt",          },      }, -    dists: [ -        { -            targets: ["sdk"], -            dir: "apistubs/android/system-server/api", -            dest: "android-non-updatable.txt", -        }, -        { -            targets: ["sdk"], -            dir: "apistubs/android/system-server/api", -            dest: "android-non-updatable-removed.txt", -        }, -    ],      soong_config_variables: {          release_hidden_api_exportable_stubs: {              dists: [                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/system-server/api", +                    dest: "android-non-updatable.txt",                      tag: ".exportable.api.txt",                  },                  { +                    targets: ["sdk"], +                    dir: "apistubs/android/system-server/api", +                    dest: "android-non-updatable-removed.txt",                      tag: ".exportable.removed-api.txt",                  },              ],              conditions_default: {                  dists: [                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/system-server/api", +                        dest: "android-non-updatable.txt",                          tag: ".api.txt",                      },                      { +                        targets: ["sdk"], +                        dir: "apistubs/android/system-server/api", +                        dest: "android-non-updatable-removed.txt",                          tag: ".removed-api.txt",                      },                  ], diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig index bfa1c7bb99d0..8ab2e0fa6379 100644 --- a/services/accessibility/accessibility.aconfig +++ b/services/accessibility/accessibility.aconfig @@ -56,6 +56,13 @@ flag {  }  flag { +  name: "enable_hardware_shortcut_disables_warning" +  namespace: "accessibility" +  description: "When the user purposely enables the hardware shortcut, preemptively disables the first-time warning message." +  bug: "287065325" +} + +flag {      name: "enable_magnification_joystick"      namespace: "accessibility"      description: "Whether to enable joystick controls for magnification" diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 73584154df3a..8a699ef39280 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -1617,9 +1617,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ              final int displayId = displays[i].getDisplayId();              onDisplayRemoved(displayId);          } -        if (com.android.server.accessibility.Flags.cleanupA11yOverlays()) {              detachAllOverlays(); -        }      }      /** diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index bbbc4aef55f3..ccf9a90b5964 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -4175,8 +4175,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub      public void enableShortcutsForTargets(              boolean enable, @UserShortcutType int shortcutTypes,              @NonNull List<String> shortcutTargets, @UserIdInt int userId) { -        mContext.enforceCallingPermission( -                Manifest.permission.MANAGE_ACCESSIBILITY, "enableShortcutsForTargets"); +        if (android.view.accessibility.Flags.migrateEnableShortcuts()) { +            mContext.enforceCallingOrSelfPermission( +                    Manifest.permission.MANAGE_ACCESSIBILITY, "enableShortcutsForTargets"); +        } else { +            mContext.enforceCallingPermission( +                    Manifest.permission.MANAGE_ACCESSIBILITY, "enableShortcutsForTargets"); +        }          for (int shortcutType : USER_SHORTCUT_TYPES) {              if ((shortcutTypes & shortcutType) == shortcutType) {                  enableShortcutForTargets(enable, shortcutType, shortcutTargets, userId); @@ -4268,6 +4273,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub          }          if (shortcutType == UserShortcutType.HARDWARE) {              skipVolumeShortcutDialogTimeoutRestriction(userId); +            if (com.android.server.accessibility.Flags.enableHardwareShortcutDisablesWarning()) { +                persistIntToSetting( +                        userId, +                        Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, +                        AccessibilityShortcutController.DialogStatus.SHOWN +                ); +            }          } else if (shortcutType == UserShortcutType.SOFTWARE) {              // Update the A11y FAB size to large when the Magnification shortcut is              // enabled and the user hasn't changed the floating button size diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index ce9cdc2aeab5..0353d5a962c7 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -1510,46 +1510,74 @@ public class BackupManagerService extends IBackupManager.Stub {          if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) {              return;          } -        dumpWithoutCheckingPermission(fd, pw, args); -    } -    @VisibleForTesting -    void dumpWithoutCheckingPermission(FileDescriptor fd, PrintWriter pw, String[] args) { -        int userId = binderGetCallingUserId(); -        if (!isUserReadyForBackup(userId)) { -            pw.println("Inactive"); +        int argIndex = 0; + +        String op = nextArg(args, argIndex); +        argIndex++; + +        if ("--help".equals(op)) { +            showDumpUsage(pw);              return;          } - -        if (args != null) { -            for (String arg : args) { -                if ("-h".equals(arg)) { -                    pw.println("'dumpsys backup' optional arguments:"); -                    pw.println("  -h       : this help text"); -                    pw.println("  a[gents] : dump information about defined backup agents"); -                    pw.println("  transportclients : dump information about transport clients"); -                    pw.println("  transportstats : dump transport statts"); -                    pw.println("  users    : dump the list of users for which backup service " -                            + "is running"); -                    return; -                } else if ("users".equals(arg.toLowerCase())) { -                    pw.print(DUMP_RUNNING_USERS_MESSAGE); -                    for (int i = 0; i < mUserServices.size(); i++) { -                        pw.print(" " + mUserServices.keyAt(i)); -                    } -                    pw.println(); -                    return; +        if ("users".equals(op)) { +            pw.print(DUMP_RUNNING_USERS_MESSAGE); +            for (int i = 0; i < mUserServices.size(); i++) { +                UserBackupManagerService userBackupManagerService = +                        getServiceForUserIfCallerHasPermission(mUserServices.keyAt(i), +                                "dump()"); +                if (userBackupManagerService != null) { +                    pw.print(" " + userBackupManagerService.getUserId());                  }              } +            pw.println(); +            return;          } - -        for (int i = 0; i < mUserServices.size(); i++) { +        if ("--user".equals(op)) { +            String userArg = nextArg(args, argIndex); +            argIndex++; +            if (userArg == null) { +                showDumpUsage(pw); +                return; +            } +            int userId = UserHandle.parseUserArg(userArg);              UserBackupManagerService userBackupManagerService = -                    getServiceForUserIfCallerHasPermission(mUserServices.keyAt(i), "dump()"); +                    getServiceForUserIfCallerHasPermission(userId, "dump()");              if (userBackupManagerService != null) {                  userBackupManagerService.dump(fd, pw, args);              } +            return;          } +        if (op == null || "agents".startsWith(op) || "transportclients".equals(op) +                || "transportstats".equals(op)) { +            for (int i = 0; i < mUserServices.size(); i++) { +                UserBackupManagerService userBackupManagerService = +                        getServiceForUserIfCallerHasPermission(mUserServices.keyAt(i), "dump()"); +                if (userBackupManagerService != null) { +                    userBackupManagerService.dump(fd, pw, args); +                } +            } +            return; +        } + +        showDumpUsage(pw); +    } + +    private String nextArg(String[] args, int argIndex) { +        if (argIndex >= args.length) { +            return null; +        } +        return args[argIndex]; +    } + +    private static void showDumpUsage(PrintWriter pw) { +        pw.println("'dumpsys backup' optional arguments:"); +        pw.println("  --help    : this help text"); +        pw.println("  a[gents] : dump information about defined backup agents"); +        pw.println("  transportclients : dump information about transport clients"); +        pw.println("  transportstats : dump transport stats"); +        pw.println("  users    : dump the list of users for which backup service is running"); +        pw.println("  --user <userId> : dump information for user userId");      }      /** @@ -1661,7 +1689,7 @@ public class BackupManagerService extends IBackupManager.Stub {       * @param message A message to include in the exception if it is thrown.       */      void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) { -        if (Binder.getCallingUserHandle().getIdentifier() != userId) { +        if (binderGetCallingUserId() != userId) {              mContext.enforceCallingOrSelfPermission(                      Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);          } diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index 23373f1df63c..afeafa4b6373 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -302,7 +302,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController          if (Flags.interceptIntentsBeforeApplyingPolicy()) {              if (mIntentListenerCallback != null && intent != null                      && mIntentListenerCallback.shouldInterceptIntent(intent)) { -                Slog.d(TAG, "Virtual device intercepting intent"); +                logActivityLaunchBlocked("Virtual device intercepting intent");                  return false;              }              if (!canContainActivity(activityInfo, windowingMode, launchingFromDisplayId, @@ -318,7 +318,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController              }              if (mIntentListenerCallback != null && intent != null                      && mIntentListenerCallback.shouldInterceptIntent(intent)) { -                Slog.d(TAG, "Virtual device intercepting intent"); +                logActivityLaunchBlocked("Virtual device intercepting intent");                  return false;              }          } @@ -331,15 +331,17 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController              boolean isNewTask) {          // Mirror displays cannot contain activities.          if (waitAndGetIsMirrorDisplay()) { -            Slog.d(TAG, "Mirror virtual displays cannot contain activities."); +            logActivityLaunchBlocked("Mirror virtual displays cannot contain activities.");              return false;          }          if (!isWindowingModeSupported(windowingMode)) { -            Slog.d(TAG, "Virtual device doesn't support windowing mode " + windowingMode); +            logActivityLaunchBlocked( +                    "Virtual device doesn't support windowing mode " + windowingMode);              return false;          }          if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) { -            Slog.d(TAG, "Virtual device requires android:canDisplayOnRemoteDevices=true"); +            logActivityLaunchBlocked( +                    "Activity requires android:canDisplayOnRemoteDevices=true");              return false;          }          final UserHandle activityUser = @@ -350,11 +352,11 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController              return true;          }          if (!activityUser.isSystem() && !mAllowedUsers.contains(activityUser)) { -            Slog.d(TAG, "Virtual device launch disallowed from user " + activityUser); +            logActivityLaunchBlocked("Activity launch disallowed from user " + activityUser);              return false;          }          if (!activityMatchesDisplayCategory(activityInfo)) { -            Slog.d(TAG, "The activity's required display category '" +            logActivityLaunchBlocked("The activity's required display category '"                      + activityInfo.requiredDisplayCategory                      + "' not found on virtual display with the following categories: "                      + mDisplayCategories); @@ -363,7 +365,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController          synchronized (mGenericWindowPolicyControllerLock) {              if (!isAllowedByPolicy(mActivityLaunchAllowedByDefault, mActivityPolicyExemptions,                      activityComponent)) { -                Slog.d(TAG, "Virtual device launch disallowed by policy: " +                logActivityLaunchBlocked("Activity launch disallowed by policy: "                          + activityComponent);                  return false;              } @@ -371,7 +373,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController          if (isNewTask && launchingFromDisplayId != DEFAULT_DISPLAY                  && !isAllowedByPolicy(mCrossTaskNavigationAllowedByDefault,                          mCrossTaskNavigationExemptions, activityComponent)) { -            Slog.d(TAG, "Virtual device cross task navigation disallowed by policy: " +            logActivityLaunchBlocked("Cross task navigation disallowed by policy: "                      + activityComponent);              return false;          } @@ -380,12 +382,18 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController          // based on FLAG_STREAM_PERMISSIONS          if (mPermissionDialogComponent != null                  && mPermissionDialogComponent.equals(activityComponent)) { +            logActivityLaunchBlocked("Permission dialog not allowed on virtual device");              return false;          }          return true;      } +    private void logActivityLaunchBlocked(String reason) { +        Slog.d(TAG, "Virtual device activity launch disallowed on display " +                + waitAndGetDisplayId() + ", reason: " + reason); +    } +      @Override      @SuppressWarnings("AndroidFrameworkRequiresPermission")      public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags, diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java index 1741593ba671..ccc44a41759b 100644 --- a/services/core/java/com/android/server/GestureLauncherService.java +++ b/services/core/java/com/android/server/GestureLauncherService.java @@ -16,6 +16,8 @@  package com.android.server; +import static com.android.internal.R.integer.config_defaultMinEmergencyGestureTapDurationMillis; +  import android.app.ActivityManager;  import android.app.StatusBarManager;  import android.content.BroadcastReceiver; @@ -70,12 +72,6 @@ public class GestureLauncherService extends SystemService {       */      @VisibleForTesting static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300; -    /** -     * Min time in milliseconds to complete the emergency gesture for it count. If the gesture is -     * completed faster than this, we assume it's not performed by human and the -     * event gets ignored. -     */ -    @VisibleForTesting static final int EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS = 200;      /**       * Interval in milliseconds in which the power button must be depressed in succession to be @@ -570,7 +566,8 @@ public class GestureLauncherService extends SystemService {                      long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(                              mContext.getContentResolver(),                              Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS, -                            EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS); +                            mContext.getResources().getInteger( +                                    config_defaultMinEmergencyGestureTapDurationMillis));                      if (emergencyGestureSpentTime <= emergencyGestureTapDetectionMinTimeMs) {                          Slog.i(TAG, "Emergency gesture detected but it's too fast. Gesture time: "                                  + emergencyGestureSpentTime + " ms"); diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java index 20816a1b22c8..32c7dde7a555 100644 --- a/services/core/java/com/android/server/SystemServiceManager.java +++ b/services/core/java/com/android/server/SystemServiceManager.java @@ -44,6 +44,9 @@ import com.android.server.am.EventLogTags;  import com.android.server.pm.ApexManager;  import com.android.server.pm.UserManagerInternal;  import com.android.server.utils.TimingsTraceAndSlog; +import com.android.tools.r8.keepanno.annotations.KeepTarget; +import com.android.tools.r8.keepanno.annotations.TypePattern; +import com.android.tools.r8.keepanno.annotations.UsesReflection;  import dalvik.system.PathClassLoader; @@ -135,7 +138,13 @@ public final class SystemServiceManager implements Dumpable {      }      /** -     * Starts a service by class name. +     * Starts a service by class name from the current {@code SYSTEMSERVERCLASSPATH}. +     * +     * In general, this should only be used for services in the classpath that cannot +     * be resolved by {@code services.jar} at build time, e.g., those defined in an apex jar from +     * {@code PRODUCT_APEX_SYSTEM_SERVER_JARS} or a downstream jar in +     * {@code PRODUCT_SYSTEM_SERVER_JARS}. Otherwise prefer the explicit type variant +     * {@link #startService(Class)}.       *       * @return The service instance.       */ @@ -147,7 +156,11 @@ public final class SystemServiceManager implements Dumpable {      }      /** -     * Starts a service by class name and a path that specifies the jar where the service lives. +     * Starts a service by class name and standalone jar path where the service lives. +     * +     * In general, this should only be used for services in {@code STANDALONE_SYSTEMSERVER_JARS}, +     * which in turn derives from {@code PRODUCT_STANDALONE_SYSTEM_SERVER_JARS} and +     * {@code PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS}.       *       * @return The service instance.       */ @@ -207,6 +220,11 @@ public final class SystemServiceManager implements Dumpable {       * @throws RuntimeException if the service fails to start.       */      @android.ravenwood.annotation.RavenwoodKeep +    @UsesReflection( +            @KeepTarget( +                    instanceOfClassConstantExclusive = SystemService.class, +                    methodName = "<init>", +                    methodParameterTypePatterns = {@TypePattern(constant = Context.class)}))      public <T extends SystemService> T startService(Class<T> serviceClass) {          try {              final String name = serviceClass.getName(); diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 603a95c31e5b..1015ad9fe1da 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -880,6 +880,14 @@ public class AccountManagerService                      packagesToVisibility = Collections.emptyMap();                      accountRemovedReceivers = Collections.emptyList();                  } +                if (notify) { +                    Integer oldVisibility = +                            accounts.accountsDb.findAccountVisibility(account, packageName); +                    if (oldVisibility != null && oldVisibility == newVisibility) { +                        // Database will not be updated - skip LOGIN_ACCOUNTS_CHANGED broadcast. +                        notify = false; +                    } +                }                  if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {                      return false; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ad15ea90c45c..4aae7d1bfede 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -497,6 +497,8 @@ import java.io.FileOutputStream;  import java.io.IOException;  import java.io.InputStreamReader;  import java.io.PrintWriter; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter;  import java.util.ArrayList;  import java.util.Arrays;  import java.util.Collections; @@ -629,6 +631,9 @@ public class ActivityManagerService extends IActivityManager.Stub      private static final int MAX_BUGREPORT_TITLE_SIZE = 100;      private static final int MAX_BUGREPORT_DESCRIPTION_SIZE = 150; +    private static final DateTimeFormatter DROPBOX_TIME_FORMATTER = +            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSZ"); +      OomAdjuster mOomAdjuster;      static final String EXTRA_TITLE = "android.intent.extra.TITLE"; @@ -2167,22 +2172,25 @@ public class ActivityManagerService extends IActivityManager.Stub       */      static class VolatileDropboxEntryStates {          private final Boolean mIsProcessFrozen; +        private final ZonedDateTime mTimestamp; -        private VolatileDropboxEntryStates(Boolean frozenState) { +        private VolatileDropboxEntryStates(Boolean frozenState, ZonedDateTime timestamp) {              this.mIsProcessFrozen = frozenState; +            this.mTimestamp = timestamp;          } -        public static VolatileDropboxEntryStates withProcessFrozenState(boolean frozenState) { -            return new VolatileDropboxEntryStates(frozenState); -        } - -        public static VolatileDropboxEntryStates emptyVolatileDropboxEnytyStates() { -            return new VolatileDropboxEntryStates(null); +        public static VolatileDropboxEntryStates withProcessFrozenStateAndTimestamp( +                boolean frozenState, ZonedDateTime timestamp) { +            return new VolatileDropboxEntryStates(frozenState, timestamp);          }          public Boolean isProcessFrozen() {              return mIsProcessFrozen;          } + +        public ZonedDateTime getTimestamp() { +            return mTimestamp; +        }      }      static class MemBinder extends Binder { @@ -4429,8 +4437,16 @@ public class ActivityManagerService extends IActivityManager.Stub          final boolean clearPendingIntentsForStoppedApp = (android.content.pm.Flags.stayStopped()                  && packageStateStopped);          if (packageName == null || uninstalling || clearPendingIntentsForStoppedApp) { +            final int cancelReason; +            if (packageName == null) { +                cancelReason = PendingIntentRecord.CANCEL_REASON_USER_STOPPED; +            } else if (uninstalling) { +                cancelReason = PendingIntentRecord.CANCEL_REASON_OWNER_UNINSTALLED; +            } else { +                cancelReason = PendingIntentRecord.CANCEL_REASON_OWNER_FORCE_STOPPED; +            }              didSomething |= mPendingIntentController.removePendingIntentsForPackage( -                    packageName, userId, appId, doit); +                    packageName, userId, appId, doit, cancelReason);          }          if (doit) { @@ -9678,6 +9694,11 @@ public class ActivityManagerService extends IActivityManager.Stub                      ? volatileStates.isProcessFrozen() : process.mOptRecord.isFrozen()                  ).append("\n");              } +            if (volatileStates != null && volatileStates.getTimestamp() != null) { +                String formattedTime = DROPBOX_TIME_FORMATTER.format( +                    volatileStates.getTimestamp()); +                sb.append("Timestamp: ").append(formattedTime).append("\n"); +            }              int flags = process.info.flags;              final IPackageManager pm = AppGlobals.getPackageManager();              sb.append("Flags: 0x").append(Integer.toHexString(flags)).append("\n"); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index e70722ca6579..372ec45763bf 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -97,6 +97,7 @@ import android.opengl.GLES10;  import android.os.Binder;  import android.os.Build;  import android.os.Bundle; +import android.os.Debug;  import android.os.IProgressListener;  import android.os.ParcelFileDescriptor;  import android.os.RemoteCallback; @@ -125,6 +126,8 @@ import com.android.server.LocalServices;  import com.android.server.am.LowMemDetector.MemFactor;  import com.android.server.am.nano.Capabilities;  import com.android.server.am.nano.Capability; +import com.android.server.am.nano.FrameworkCapability; +import com.android.server.am.nano.VMCapability;  import com.android.server.compat.PlatformCompat;  import com.android.server.pm.UserManagerInternal;  import com.android.server.utils.Slogf; @@ -443,6 +446,22 @@ final class ActivityManagerShellCommand extends ShellCommand {                  capabilities.values[i] = cap;              } +            String[] vmCapabilities = Debug.getVmFeatureList(); +            capabilities.vmCapabilities = new VMCapability[vmCapabilities.length]; +            for (int i = 0; i < vmCapabilities.length; i++) { +                VMCapability cap = new VMCapability(); +                cap.name = vmCapabilities[i]; +                capabilities.vmCapabilities[i] = cap; +            } + +            String[] fmCapabilities = Debug.getFeatureList(); +            capabilities.frameworkCapabilities = new FrameworkCapability[fmCapabilities.length]; +            for (int i = 0; i < fmCapabilities.length; i++) { +                FrameworkCapability cap = new FrameworkCapability(); +                cap.name = fmCapabilities[i]; +                capabilities.frameworkCapabilities[i] = cap; +            } +              try {                  getRawOutputStream().write(Capabilities.toByteArray(capabilities));              } catch (IOException e) { @@ -452,10 +471,16 @@ final class ActivityManagerShellCommand extends ShellCommand {          } else {              // Unfortunately we don't have protobuf text format capabilities here.              // Fallback to line separated list instead for text parser. -            pw.println("Format: 1"); +            pw.println("Format: 2");              for (String capability : CAPABILITIES) {                  pw.println(capability);              } +            for (String capability : Debug.getVmFeatureList()) { +                pw.println("vm:" + capability); +            } +            for (String capability : Debug.getFeatureList()) { +                pw.println("framework:" + capability); +            }          }          return 0;      } diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java index 8b1300b641a9..ef015ee9d743 100644 --- a/services/core/java/com/android/server/am/AppRestrictionController.java +++ b/services/core/java/com/android/server/am/AppRestrictionController.java @@ -2153,9 +2153,12 @@ public final class AppRestrictionController {              mRestrictionSettings.update(pkgName, uid, level, reason, subReason);          } -        if (!allowUpdateBucket || curBucket == STANDBY_BUCKET_EXEMPTED) { +        if (!android.app.Flags.appRestrictionsApi() +                && (!allowUpdateBucket || curBucket == STANDBY_BUCKET_EXEMPTED)) {              return;          } + +        boolean doItNow = true;          if (level >= RESTRICTION_LEVEL_RESTRICTED_BUCKET                  && curLevel < RESTRICTION_LEVEL_RESTRICTED_BUCKET) {              // Moving the app standby bucket to restricted in the meanwhile. @@ -2168,7 +2171,6 @@ public final class AppRestrictionController {                      && (mConstantsObserver.mBgAutoRestrictedBucket                      || level == RESTRICTION_LEVEL_RESTRICTED_BUCKET)) {                  // restrict the app if it hasn't done so. -                boolean doIt = true;                  synchronized (mSettingsLock) {                      final int index = mActiveUids.indexOfKey(uid, pkgName);                      if (index >= 0) { @@ -2182,14 +2184,16 @@ public final class AppRestrictionController {                              logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level,                                      localTrackerInfo, localReason);                          }); -                        doIt = false; +                        doItNow = false;                      }                  } -                if (doIt) { +                if (doItNow) {                      appStandbyInternal.restrictApp(pkgName, UserHandle.getUserId(uid),                              reason, subReason); -                    logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level, trackerInfo, -                            reason); +                    if (!android.app.Flags.appRestrictionsApi()) { +                        logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level, trackerInfo, +                                reason); +                    }                  }              }          } else if (curLevel >= RESTRICTION_LEVEL_RESTRICTED_BUCKET @@ -2204,6 +2208,13 @@ public final class AppRestrictionController {              appStandbyInternal.maybeUnrestrictApp(pkgName, UserHandle.getUserId(uid),                      prevReason & REASON_MAIN_MASK, prevReason & REASON_SUB_MASK,                      reason, subReason); +            if (!android.app.Flags.appRestrictionsApi()) { +                logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level, trackerInfo, +                        reason); +            } +        } + +        if (doItNow && android.app.Flags.appRestrictionsApi()) {              logAppBackgroundRestrictionInfo(pkgName, uid, curLevel, level, trackerInfo,                      reason);          } diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 4f46ecdb9228..f98799dd3723 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -124,7 +124,9 @@ import com.android.server.power.stats.BatteryExternalStatsWorker;  import com.android.server.power.stats.BatteryStatsDumpHelperImpl;  import com.android.server.power.stats.BatteryStatsImpl;  import com.android.server.power.stats.BatteryUsageStatsProvider; -import com.android.server.power.stats.CpuAggregatedPowerStatsProcessor; +import com.android.server.power.stats.CpuPowerStatsProcessor; +import com.android.server.power.stats.MobileRadioPowerStatsProcessor; +import com.android.server.power.stats.PhoneCallPowerStatsProcessor;  import com.android.server.power.stats.PowerStatsAggregator;  import com.android.server.power.stats.PowerStatsExporter;  import com.android.server.power.stats.PowerStatsScheduler; @@ -408,11 +410,18 @@ public final class BatteryStatsService extends IBatteryStats.Stub                  com.android.internal.R.bool.config_batteryStatsResetOnUnplugAfterSignificantCharge);          final long powerStatsThrottlePeriodCpu = context.getResources().getInteger(                  com.android.internal.R.integer.config_defaultPowerStatsThrottlePeriodCpu); +        final long powerStatsThrottlePeriodMobileRadio = context.getResources().getInteger( +                com.android.internal.R.integer.config_defaultPowerStatsThrottlePeriodMobileRadio);          mBatteryStatsConfig =                  new BatteryStatsImpl.BatteryStatsConfig.Builder()                          .setResetOnUnplugHighBatteryLevel(resetOnUnplugHighBatteryLevel)                          .setResetOnUnplugAfterSignificantCharge(resetOnUnplugAfterSignificantCharge) -                        .setPowerStatsThrottlePeriodCpu(powerStatsThrottlePeriodCpu) +                        .setPowerStatsThrottlePeriodMillis( +                                BatteryConsumer.POWER_COMPONENT_CPU, +                                powerStatsThrottlePeriodCpu) +                        .setPowerStatsThrottlePeriodMillis( +                                BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, +                                powerStatsThrottlePeriodMobileRadio)                          .build();          mPowerStatsUidResolver = new PowerStatsUidResolver();          mStats = new BatteryStatsImpl(mBatteryStatsConfig, Clock.SYSTEM_CLOCK, mMonotonicClock, @@ -470,7 +479,20 @@ public final class BatteryStatsService extends IBatteryStats.Stub                          AggregatedPowerStatsConfig.STATE_SCREEN,                          AggregatedPowerStatsConfig.STATE_PROCESS_STATE)                  .setProcessor( -                        new CpuAggregatedPowerStatsProcessor(mPowerProfile, mCpuScalingPolicies)); +                        new CpuPowerStatsProcessor(mPowerProfile, mCpuScalingPolicies)); +        config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO) +                .trackDeviceStates( +                        AggregatedPowerStatsConfig.STATE_POWER, +                        AggregatedPowerStatsConfig.STATE_SCREEN) +                .trackUidStates( +                        AggregatedPowerStatsConfig.STATE_POWER, +                        AggregatedPowerStatsConfig.STATE_SCREEN, +                        AggregatedPowerStatsConfig.STATE_PROCESS_STATE) +                .setProcessor( +                        new MobileRadioPowerStatsProcessor(mPowerProfile)); +        config.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_PHONE, +                        BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO) +                .setProcessor(new PhoneCallPowerStatsProcessor());          return config;      } @@ -494,8 +516,16 @@ public final class BatteryStatsService extends IBatteryStats.Stub      }      public void systemServicesReady() { -        mStats.setPowerStatsCollectorEnabled(Flags.streamlinedBatteryStats()); -        mBatteryUsageStatsProvider.setPowerStatsExporterEnabled(Flags.streamlinedBatteryStats()); +        mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_CPU, +                Flags.streamlinedBatteryStats()); +        mStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, +                Flags.streamlinedConnectivityBatteryStats()); +        mBatteryUsageStatsProvider.setPowerStatsExporterEnabled( +                BatteryConsumer.POWER_COMPONENT_CPU, +                Flags.streamlinedBatteryStats()); +        mBatteryUsageStatsProvider.setPowerStatsExporterEnabled( +                BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, +                Flags.streamlinedConnectivityBatteryStats());          mWorker.systemServicesReady();          mStats.systemServicesReady(mContext);          mCpuWakeupStats.systemServicesReady(); @@ -536,7 +566,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub       * Notifies BatteryStatsService that the system server is ready.       */      public void onSystemReady() { -        mStats.onSystemReady(); +        mStats.onSystemReady(mContext);          mPowerStatsScheduler.start(Flags.streamlinedBatteryStats());      } @@ -1591,19 +1621,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub              final long elapsedRealtime = SystemClock.elapsedRealtime();              final long uptime = SystemClock.uptimeMillis();              mHandler.post(() -> { -                final boolean update;                  synchronized (mStats) {                      // Ignore if no power state change.                      if (mLastPowerStateFromRadio == powerState) return;                      mLastPowerStateFromRadio = powerState; -                    update = mStats.noteMobileRadioPowerStateLocked(powerState, timestampNs, uid, +                    mStats.noteMobileRadioPowerStateLocked(powerState, timestampNs, uid,                              elapsedRealtime, uptime);                  } - -                if (update) { -                    mWorker.scheduleSync("modem-data", BatteryExternalStatsWorker.UPDATE_RADIO); -                }              });          }          FrameworkStatsLog.write_non_chained( diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java index fb0d6957129a..f3361203c44a 100644 --- a/services/core/java/com/android/server/am/PendingIntentController.java +++ b/services/core/java/com/android/server/am/PendingIntentController.java @@ -22,6 +22,8 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;  import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;  import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;  import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_OWNER_CANCELED; +import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_SUPERSEDED;  import android.annotation.Nullable;  import android.app.Activity; @@ -54,6 +56,7 @@ import com.android.internal.util.RingBuffer;  import com.android.internal.util.function.pooled.PooledLambda;  import com.android.server.AlarmManagerInternal;  import com.android.server.LocalServices; +import com.android.server.am.PendingIntentRecord.CancellationReason;  import com.android.server.wm.ActivityTaskManagerInternal;  import com.android.server.wm.SafeActivityOptions; @@ -191,7 +194,7 @@ public class PendingIntentController {                      }                      return rec;                  } -                makeIntentSenderCanceled(rec); +                makeIntentSenderCanceled(rec, CANCEL_REASON_SUPERSEDED);                  mIntentSenderRecords.remove(key);                  decrementUidStatLocked(rec);              } @@ -206,7 +209,7 @@ public class PendingIntentController {      }      boolean removePendingIntentsForPackage(String packageName, int userId, int appId, -            boolean doIt) { +            boolean doIt, @CancellationReason int cancelReason) {          boolean didSomething = false;          synchronized (mLock) { @@ -256,7 +259,7 @@ public class PendingIntentController {                  }                  didSomething = true;                  it.remove(); -                makeIntentSenderCanceled(pir); +                makeIntentSenderCanceled(pir, cancelReason);                  decrementUidStatLocked(pir);                  if (pir.key.activity != null) {                      final Message m = PooledLambda.obtainMessage( @@ -289,13 +292,14 @@ public class PendingIntentController {              } catch (RemoteException e) {                  throw new SecurityException(e);              } -            cancelIntentSender(rec, true); +            cancelIntentSender(rec, true, CANCEL_REASON_OWNER_CANCELED);          }      } -    public void cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity) { +    public void cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity, +            @CancellationReason int cancelReason) {          synchronized (mLock) { -            makeIntentSenderCanceled(rec); +            makeIntentSenderCanceled(rec, cancelReason);              mIntentSenderRecords.remove(rec.key);              decrementUidStatLocked(rec);              if (cleanActivity && rec.key.activity != null) { @@ -359,8 +363,10 @@ public class PendingIntentController {          }      } -    private void makeIntentSenderCanceled(PendingIntentRecord rec) { +    private void makeIntentSenderCanceled(PendingIntentRecord rec, +            @CancellationReason int cancelReason) {          rec.canceled = true; +        rec.cancelReason = cancelReason;          final RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked();          if (callbacks != null) {              final Message m = PooledLambda.obtainMessage( diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index 95e130ed1194..da45a7727faf 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -16,11 +16,13 @@  package com.android.server.am; +import static android.app.ActivityManager.PROCESS_STATE_TOP;  import static android.app.ActivityManager.START_SUCCESS;  import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;  import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import android.annotation.IntDef;  import android.annotation.Nullable;  import android.annotation.RequiresPermission;  import android.app.ActivityManager; @@ -51,11 +53,15 @@ import android.util.ArraySet;  import android.util.Slog;  import android.util.TimeUtils; +import com.android.internal.annotations.VisibleForTesting;  import com.android.internal.os.IResultReceiver;  import com.android.internal.util.function.pooled.PooledLambda; +import com.android.modules.expresslog.Counter;  import com.android.server.wm.SafeActivityOptions;  import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy;  import java.lang.ref.WeakReference;  import java.util.Objects; @@ -71,12 +77,35 @@ public final class PendingIntentRecord extends IIntentSender.Stub {      public static final int FLAG_BROADCAST_SENDER = 1 << 1;      public static final int FLAG_SERVICE_SENDER = 1 << 2; +    public static final int CANCEL_REASON_NULL = 0; +    public static final int CANCEL_REASON_USER_STOPPED = 1 << 0; +    public static final int CANCEL_REASON_OWNER_UNINSTALLED = 1 << 1; +    public static final int CANCEL_REASON_OWNER_FORCE_STOPPED = 1 << 2; +    public static final int CANCEL_REASON_OWNER_CANCELED = 1 << 3; +    public static final int CANCEL_REASON_HOSTING_ACTIVITY_DESTROYED = 1 << 4; +    public static final int CANCEL_REASON_SUPERSEDED = 1 << 5; +    public static final int CANCEL_REASON_ONE_SHOT_SENT = 1 << 6; + +    @IntDef({ +            CANCEL_REASON_NULL, +            CANCEL_REASON_USER_STOPPED, +            CANCEL_REASON_OWNER_UNINSTALLED, +            CANCEL_REASON_OWNER_FORCE_STOPPED, +            CANCEL_REASON_OWNER_CANCELED, +            CANCEL_REASON_HOSTING_ACTIVITY_DESTROYED, +            CANCEL_REASON_SUPERSEDED, +            CANCEL_REASON_ONE_SHOT_SENT +    }) +    @Retention(RetentionPolicy.SOURCE) +    public @interface CancellationReason {} +      final PendingIntentController controller;      final Key key;      final int uid;      public final WeakReference<PendingIntentRecord> ref;      boolean sent = false;      boolean canceled = false; +    @CancellationReason int cancelReason = CANCEL_REASON_NULL;      /**       * Map IBinder to duration specified as Pair<Long, Integer>, Long is allowlist duration in       * milliseconds, Integer is allowlist type defined at @@ -419,12 +448,22 @@ public final class PendingIntentRecord extends IIntentSender.Stub {          SafeActivityOptions mergedOptions = null;          synchronized (controller.mLock) {              if (canceled) { +                if (cancelReason == CANCEL_REASON_OWNER_FORCE_STOPPED +                        && controller.mAmInternal.getUidProcessState(callingUid) +                                == PROCESS_STATE_TOP) { +                    Counter.logIncrementWithUid( +                            "app.value_force_stop_cancelled_pi_sent_from_top_per_caller", +                            callingUid); +                    Counter.logIncrementWithUid( +                            "app.value_force_stop_cancelled_pi_sent_from_top_per_owner", +                            uid); +                }                  return ActivityManager.START_CANCELED;              }              sent = true;              if ((key.flags & PendingIntent.FLAG_ONE_SHOT) != 0) { -                controller.cancelIntentSender(this, true); +                controller.cancelIntentSender(this, true, CANCEL_REASON_ONE_SHOT_SENT);              }              finalIntent = key.requestIntent != null ? new Intent(key.requestIntent) : new Intent(); @@ -687,6 +726,21 @@ public final class PendingIntentRecord extends IIntentSender.Stub {          }      } +    @VisibleForTesting +    static String cancelReasonToString(@CancellationReason int cancelReason) { +        return switch (cancelReason) { +            case CANCEL_REASON_NULL -> "NULL"; +            case CANCEL_REASON_USER_STOPPED -> "USER_STOPPED"; +            case CANCEL_REASON_OWNER_UNINSTALLED -> "OWNER_UNINSTALLED"; +            case CANCEL_REASON_OWNER_FORCE_STOPPED -> "OWNER_FORCE_STOPPED"; +            case CANCEL_REASON_OWNER_CANCELED -> "OWNER_CANCELED"; +            case CANCEL_REASON_HOSTING_ACTIVITY_DESTROYED -> "HOSTING_ACTIVITY_DESTROYED"; +            case CANCEL_REASON_SUPERSEDED -> "SUPERSEDED"; +            case CANCEL_REASON_ONE_SHOT_SENT -> "ONE_SHOT_SENT"; +            default -> "UNKNOWN"; +        }; +    } +      public void dump(PrintWriter pw, String prefix) {          pw.print(prefix); pw.print("uid="); pw.print(uid);                  pw.print(" packageName="); pw.print(key.packageName); @@ -707,7 +761,8 @@ public final class PendingIntentRecord extends IIntentSender.Stub {          }          if (sent || canceled) {              pw.print(prefix); pw.print("sent="); pw.print(sent); -                    pw.print(" canceled="); pw.println(canceled); +                    pw.print(" canceled="); pw.print(canceled); +                    pw.print(" cancelReason="); pw.println(cancelReasonToString(cancelReason));          }          if (mAllowlistDuration != null) {              pw.print(prefix); diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java index 0aa1a69334d7..76c59520d4ea 100644 --- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java @@ -66,7 +66,7 @@ import java.io.PrintWriter;  import java.io.StringWriter;  import java.time.Instant;  import java.time.ZoneId; -import java.time.format.DateTimeFormatter; +import java.time.ZonedDateTime;  import java.util.ArrayList;  import java.util.UUID;  import java.util.concurrent.ExecutionException; @@ -79,9 +79,6 @@ import java.util.concurrent.atomic.AtomicLong;   * The error state of the process, such as if it's crashing/ANR etc.   */  class ProcessErrorStateRecord { -    private static final DateTimeFormatter DROPBOX_TIME_FORMATTER = -            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSZ"); -      final ProcessRecord mApp;      private final ActivityManagerService mService; @@ -355,9 +352,18 @@ class ProcessErrorStateRecord {              synchronized (mProcLock) {                  latencyTracker.waitingOnProcLockEnded();                  setNotResponding(true); + +                ZonedDateTime timestamp = null; +                if (timeoutRecord != null && timeoutRecord.mEndUptimeMillis > 0) { +                    long millisSinceEndUptimeMs = anrTime - timeoutRecord.mEndUptimeMillis; +                    timestamp = Instant.now().minusMillis(millisSinceEndUptimeMs) +                                    .atZone(ZoneId.systemDefault()); +                } +                  volatileDropboxEntriyStates =                          ActivityManagerService.VolatileDropboxEntryStates -                                .withProcessFrozenState(mApp.mOptRecord.isFrozen()); +                                .withProcessFrozenStateAndTimestamp( +                                        mApp.mOptRecord.isFrozen(), timestamp);              }              // Log the ANR to the event log. @@ -450,13 +456,6 @@ class ProcessErrorStateRecord {              info.append("ErrorId: ").append(errorId.toString()).append("\n");          }          info.append("Frozen: ").append(mApp.mOptRecord.isFrozen()).append("\n"); -        if (timeoutRecord != null && timeoutRecord.mEndUptimeMillis > 0) { -            long millisSinceEndUptimeMs = anrTime - timeoutRecord.mEndUptimeMillis; -            String formattedTime = DROPBOX_TIME_FORMATTER.format( -                    Instant.now().minusMillis(millisSinceEndUptimeMs) -                            .atZone(ZoneId.systemDefault())); -            info.append("Timestamp: ").append(formattedTime).append("\n"); -        }          // Retrieve controller with max ANR delay from AnrControllers          // Note that we retrieve the controller before dumping stacks because dumping stacks can diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 390dca30ac96..1f89ca70ce8d 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -145,6 +145,7 @@ public class SettingsToPropertiesMapper {          "core_experiments_team_internal",          "core_graphics",          "core_libraries", +        "crumpet",          "dck_framework",          "devoptions_settings",          "game", @@ -169,6 +170,7 @@ public class SettingsToPropertiesMapper {          "pixel_biometrics_face",          "pixel_bluetooth",          "pixel_connectivity_gps", +        "pixel_continuity",          "pixel_sensors",          "pixel_system_sw_video",          "pixel_watch", diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index debd9d0f0c83..83fa34490f32 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -248,6 +248,7 @@ public class AppOpsService extends IAppOpsService.Stub {              Process.ROOT_UID,              Process.PHONE_UID,              Process.BLUETOOTH_UID, +            Process.AUDIOSERVER_UID,              Process.NFC_UID,              Process.NETWORK_STACK_UID,              Process.SHELL_UID}; @@ -1364,6 +1365,9 @@ public class AppOpsService extends IAppOpsService.Stub {      @GuardedBy("this")      private void packageRemovedLocked(int uid, String packageName) { +        mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::clearHistory, +                mHistoricalRegistry, uid, packageName)); +          UidState uidState = mUidStates.get(uid);          if (uidState == null) {              return; @@ -1398,9 +1402,6 @@ public class AppOpsService extends IAppOpsService.Stub {                  }              }          } - -        mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::clearHistory, -                    mHistoricalRegistry, uid, packageName));      }      public void uidRemoved(int uid) { diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index 6f3526fb07e9..dbd47d00718f 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -54,13 +54,13 @@ import android.util.Xml;  import com.android.internal.annotations.GuardedBy;  import com.android.internal.os.AtomicDirectory; -import com.android.internal.os.BackgroundThread;  import com.android.internal.util.ArrayUtils;  import com.android.internal.util.XmlUtils;  import com.android.internal.util.function.pooled.PooledLambda;  import com.android.modules.utils.TypedXmlPullParser;  import com.android.modules.utils.TypedXmlSerializer;  import com.android.server.FgThread; +import com.android.server.IoThread;  import org.xmlpull.v1.XmlPullParserException; @@ -669,7 +669,7 @@ final class HistoricalRegistry {      }      private void clearHistoryOnDiskDLocked() { -        BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY); +        IoThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY);          synchronized (mInMemoryLock) {              mCurrentHistoricalOps = null;              mNextPersistDueTimeMillis = System.currentTimeMillis(); @@ -745,7 +745,7 @@ final class HistoricalRegistry {      private void persistPendingHistory(@NonNull List<HistoricalOps> pendingWrites) {          synchronized (mOnDiskLock) { -            BackgroundThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY); +            IoThread.getHandler().removeMessages(MSG_WRITE_PENDING_HISTORY);              if (pendingWrites.isEmpty()) {                  return;              } @@ -767,7 +767,7 @@ final class HistoricalRegistry {          final Message message = PooledLambda.obtainMessage(                  HistoricalRegistry::persistPendingHistory, HistoricalRegistry.this);          message.what = MSG_WRITE_PENDING_HISTORY; -        BackgroundThread.getHandler().sendMessage(message); +        IoThread.getHandler().sendMessage(message);          mPendingWrites.offerFirst(ops);      } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 5ba0af402e4d..0e22ef1eb741 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -4674,6 +4674,12 @@ public class AudioService extends IAudioService.Stub          int streamTypeAlias = mStreamVolumeAlias[streamType];          VolumeStreamState streamState = mStreamStates[streamTypeAlias]; +        if ((streamType == AudioManager.STREAM_VOICE_CALL) +                && isInCommunication() && mDeviceBroker.isBluetoothScoActive()) { +            Log.i(TAG, "setStreamVolume for STREAM_VOICE_CALL, switching to STREAM_BLUETOOTH_SCO"); +            streamType = AudioManager.STREAM_BLUETOOTH_SCO; +        } +          final int device = (ada == null)                  ? getDeviceForStream(streamType)                  : ada.getInternalType(); @@ -5464,19 +5470,19 @@ public class AudioService extends IAudioService.Stub      /** @see AudioManager#setMicrophoneMuteFromSwitch(boolean) */      public void setMicrophoneMuteFromSwitch(boolean on) { -        int userId = Binder.getCallingUid(); -        if (userId != android.os.Process.SYSTEM_UID) { +        int callingUid = Binder.getCallingUid(); +        if (callingUid != android.os.Process.SYSTEM_UID) {              Log.e(TAG, "setMicrophoneMuteFromSwitch() called from non system user!");              return;          }          mMicMuteFromSwitch = on;          new MediaMetrics.Item(MediaMetrics.Name.AUDIO_MIC) -                .setUid(userId) +                .setUid(callingUid)                  .set(MediaMetrics.Property.EVENT, "setMicrophoneMuteFromSwitch")                  .set(MediaMetrics.Property.REQUEST, on                          ? MediaMetrics.Value.MUTE : MediaMetrics.Value.UNMUTE)                  .record(); -        setMicrophoneMuteNoCallerCheck(userId); +        setMicrophoneMuteNoCallerCheck(UserHandle.getCallingUserId());      }      private void setMicMuteFromSwitchInput() { @@ -5507,9 +5513,10 @@ public class AudioService extends IAudioService.Stub          if (DEBUG_VOL) {              Log.d(TAG, String.format("Mic mute %b, user=%d", muted, userId));          } -        // only mute for the current user -        if (getCurrentUserId() == userId || userId == android.os.Process.SYSTEM_UID) { +        // only mute for the current user or for the system user. +        if (getCurrentUserId() == userId || userId == UserHandle.USER_SYSTEM) {              final boolean currentMute = mAudioSystem.isMicrophoneMuted(); +            int callingUid = Binder.getCallingUid();              final long identity = Binder.clearCallingIdentity();              try {                  final int ret = mAudioSystem.muteMicrophone(muted); @@ -5522,7 +5529,7 @@ public class AudioService extends IAudioService.Stub                  }                  new MediaMetrics.Item(MediaMetrics.Name.AUDIO_MIC) -                        .setUid(userId) +                        .setUid(callingUid)                          .set(MediaMetrics.Property.EVENT, "setMicrophoneMuteNoCallerCheck")                          .set(MediaMetrics.Property.MUTE, mMicMuteFromSystemCached                                  ? MediaMetrics.Value.ON : MediaMetrics.Value.OFF) diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index c03b3b86ad03..0be893c4b932 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -576,7 +576,8 @@ public final class AuthSession implements IBinder.DeathRecipient {      }      void onDialogAnimatedIn(boolean startFingerprintNow) { -        if (mState != STATE_AUTH_STARTED && mState != STATE_ERROR_PENDING_SYSUI) { +        if (mState != STATE_AUTH_STARTED && mState != STATE_ERROR_PENDING_SYSUI +                && mState != STATE_AUTH_PAUSED) {              Slog.e(TAG, "onDialogAnimatedIn, unexpected state: " + mState);              return;          } diff --git a/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java b/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java index 16514fa813dc..e6de14bcf9aa 100644 --- a/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java +++ b/services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java @@ -29,7 +29,6 @@ import android.os.Binder;  import android.os.IBinder;  import android.os.RemoteException;  import android.os.ServiceManager; -import android.util.IndentingPrintWriter;  import android.util.Log;  import com.android.internal.annotations.VisibleForTesting; @@ -122,7 +121,8 @@ final class IRadioServiceAidlImpl extends IRadioService.Stub {                      + " without permission " + Manifest.permission.DUMP);              return;          } -        IndentingPrintWriter radioPrintWriter = new IndentingPrintWriter(printWriter); +        android.util.IndentingPrintWriter radioPrintWriter = +                new android.util.IndentingPrintWriter(printWriter);          radioPrintWriter.printf("BroadcastRadioService\n");          radioPrintWriter.increaseIndent(); diff --git a/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java b/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java index ab083429a200..93fb7b2525fb 100644 --- a/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java +++ b/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java @@ -26,7 +26,6 @@ import android.hardware.radio.ITunerCallback;  import android.hardware.radio.RadioManager;  import android.os.Binder;  import android.os.RemoteException; -import android.util.IndentingPrintWriter;  import android.util.Log;  import android.util.Slog; @@ -139,7 +138,7 @@ final class IRadioServiceHidlImpl extends IRadioService.Stub {                      + " without permission " + Manifest.permission.DUMP);              return;          } -        IndentingPrintWriter radioPw = new IndentingPrintWriter(pw); +        android.util.IndentingPrintWriter radioPw = new android.util.IndentingPrintWriter(pw);          radioPw.printf("BroadcastRadioService\n");          radioPw.increaseIndent(); diff --git a/services/core/java/com/android/server/broadcastradio/aidl/RadioLogger.java b/services/core/java/com/android/server/broadcastradio/RadioEventLogger.java index cca351bc0d73..2c8f499c619b 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/RadioLogger.java +++ b/services/core/java/com/android/server/broadcastradio/RadioEventLogger.java @@ -14,31 +14,35 @@   * limitations under the License.   */ -package com.android.server.broadcastradio.aidl; +package com.android.server.broadcastradio;  import android.text.TextUtils; -import android.util.IndentingPrintWriter;  import android.util.LocalLog;  import android.util.Log;  import com.android.server.utils.Slogf;  /** - * Event logger to log and dump events of radio module and tuner session - * for AIDL broadcast radio HAL + * Event logger to log and dump events of broadcast radio service client for HIDL and AIDL + * broadcast HAL.   */ -final class RadioLogger { +public final class RadioEventLogger {      private final String mTag;      private final boolean mDebug;      private final LocalLog mEventLogger; -    RadioLogger(String tag, int loggerQueueSize) { +    public RadioEventLogger(String tag, int loggerQueueSize) {          mTag = tag;          mDebug = Log.isLoggable(mTag, Log.DEBUG);          mEventLogger = new LocalLog(loggerQueueSize);      } -    void logRadioEvent(String logFormat, Object... args) { +    /** +     * Log broadcast radio service event +     * @param logFormat String format of log message +     * @param args Arguments of log message +     */ +    public void logRadioEvent(String logFormat, Object... args) {          String log = TextUtils.formatSimple(logFormat, args);          mEventLogger.log(log);          if (mDebug) { @@ -46,7 +50,11 @@ final class RadioLogger {          }      } -    void dump(IndentingPrintWriter pw) { +    /** +     * Dump broadcast radio service event +     * @param pw Indenting print writer for dump +     */ +    public void dump(android.util.IndentingPrintWriter pw) {          mEventLogger.dump(pw);      }  } diff --git a/services/core/java/com/android/server/broadcastradio/aidl/AnnouncementAggregator.java b/services/core/java/com/android/server/broadcastradio/aidl/AnnouncementAggregator.java index b618aa3d65dc..9654a93d2036 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/AnnouncementAggregator.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/AnnouncementAggregator.java @@ -22,7 +22,6 @@ import android.hardware.radio.IAnnouncementListener;  import android.hardware.radio.ICloseHandle;  import android.os.IBinder;  import android.os.RemoteException; -import android.util.IndentingPrintWriter;  import android.util.Log;  import com.android.internal.annotations.GuardedBy; @@ -94,7 +93,7 @@ public final class AnnouncementAggregator extends ICloseHandle.Stub {              if (mCloseHandle != null) mCloseHandle.close();          } -        public void dumpInfo(IndentingPrintWriter pw) { +        public void dumpInfo(android.util.IndentingPrintWriter pw) {              pw.printf("ModuleWatcher:\n");              pw.increaseIndent(); @@ -192,7 +191,8 @@ public final class AnnouncementAggregator extends ICloseHandle.Stub {      @Override      protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { -        IndentingPrintWriter announcementPrintWriter = new IndentingPrintWriter(printWriter); +        android.util.IndentingPrintWriter announcementPrintWriter = +                new android.util.IndentingPrintWriter(printWriter);          announcementPrintWriter.printf("AnnouncementAggregator\n");          announcementPrintWriter.increaseIndent(); diff --git a/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java b/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java index 086f3aa8ad65..1c421614599d 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java @@ -29,7 +29,6 @@ import android.os.IServiceCallback;  import android.os.RemoteException;  import android.os.ServiceManager;  import android.util.ArrayMap; -import android.util.IndentingPrintWriter;  import android.util.Log;  import android.util.SparseArray; @@ -261,7 +260,7 @@ public final class BroadcastRadioServiceImpl {       *       * @param pw The file to which {@link BroadcastRadioServiceImpl} state is dumped.       */ -    public void dumpInfo(IndentingPrintWriter pw) { +    public void dumpInfo(android.util.IndentingPrintWriter pw) {          synchronized (mLock) {              pw.printf("Next module id available: %d\n", mNextModuleId);              pw.printf("ServiceName to module id map:\n"); diff --git a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java index cd865105c48e..0cac35641ed0 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java @@ -38,10 +38,10 @@ import android.os.Looper;  import android.os.RemoteException;  import android.os.UserHandle;  import android.util.ArraySet; -import android.util.IndentingPrintWriter;  import com.android.internal.annotations.GuardedBy;  import com.android.internal.annotations.VisibleForTesting; +import com.android.server.broadcastradio.RadioEventLogger;  import com.android.server.broadcastradio.RadioServiceUserController;  import com.android.server.utils.Slogf; @@ -59,7 +59,7 @@ final class RadioModule {      private final Object mLock = new Object();      private final Handler mHandler; -    private final RadioLogger mLogger; +    private final RadioEventLogger mLogger;      private final RadioManager.ModuleProperties mProperties;      /** @@ -197,7 +197,7 @@ final class RadioModule {          mProperties = Objects.requireNonNull(properties, "properties cannot be null");          mService = Objects.requireNonNull(service, "service cannot be null");          mHandler = new Handler(Looper.getMainLooper()); -        mLogger = new RadioLogger(TAG, RADIO_EVENT_LOGGER_QUEUE_SIZE); +        mLogger = new RadioEventLogger(TAG, RADIO_EVENT_LOGGER_QUEUE_SIZE);      }      @Nullable @@ -524,7 +524,7 @@ final class RadioModule {          return BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);      } -    void dumpInfo(IndentingPrintWriter pw) { +    void dumpInfo(android.util.IndentingPrintWriter pw) {          pw.printf("RadioModule\n");          pw.increaseIndent(); diff --git a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java index 4ed36ec9878c..925f149b12cf 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java @@ -29,9 +29,9 @@ import android.os.Binder;  import android.os.RemoteException;  import android.util.ArrayMap;  import android.util.ArraySet; -import android.util.IndentingPrintWriter;  import com.android.internal.annotations.GuardedBy; +import com.android.server.broadcastradio.RadioEventLogger;  import com.android.server.broadcastradio.RadioServiceUserController;  import com.android.server.utils.Slogf; @@ -45,7 +45,7 @@ final class TunerSession extends ITuner.Stub {      private final Object mLock = new Object(); -    private final RadioLogger mLogger; +    private final RadioEventLogger mLogger;      private final RadioModule mModule;      final int mUserId;      final android.hardware.radio.ITunerCallback mCallback; @@ -70,7 +70,7 @@ final class TunerSession extends ITuner.Stub {          mUserId = Binder.getCallingUserHandle().getIdentifier();          mCallback = Objects.requireNonNull(callback, "callback cannot be null");          mUid = Binder.getCallingUid(); -        mLogger = new RadioLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE); +        mLogger = new RadioEventLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE);      }      @Override @@ -434,7 +434,7 @@ final class TunerSession extends ITuner.Stub {          }      } -    void dumpInfo(IndentingPrintWriter pw) { +    void dumpInfo(android.util.IndentingPrintWriter pw) {          pw.printf("TunerSession\n");          pw.increaseIndent(); diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java index 3198842c1ff3..e1650c227266 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java @@ -30,7 +30,6 @@ import android.hidl.manager.V1_0.IServiceNotification;  import android.os.IHwBinder.DeathRecipient;  import android.os.RemoteException;  import android.util.ArrayMap; -import android.util.IndentingPrintWriter;  import com.android.internal.annotations.GuardedBy;  import com.android.internal.annotations.VisibleForTesting; @@ -222,7 +221,7 @@ public final class BroadcastRadioService {       *       * @param pw The file to which BroadcastRadioService state is dumped.       */ -    public void dumpInfo(IndentingPrintWriter pw) { +    public void dumpInfo(android.util.IndentingPrintWriter pw) {          synchronized (mLock) {              pw.printf("Next module id available: %d\n", mNextModuleId);              pw.printf("ServiceName to module id map:\n"); diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioEventLogger.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioEventLogger.java deleted file mode 100644 index b8d12280ac05..000000000000 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioEventLogger.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - *      http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.broadcastradio.hal2; - -import android.util.IndentingPrintWriter; -import android.util.LocalLog; -import android.util.Log; - -import com.android.server.utils.Slogf; - -final class RadioEventLogger { -    private final String mTag; -    private final LocalLog mEventLogger; - -    RadioEventLogger(String tag, int loggerQueueSize) { -        mTag = tag; -        mEventLogger = new LocalLog(loggerQueueSize); -    } - -    @SuppressWarnings("AnnotateFormatMethod") -    void logRadioEvent(String logFormat, Object... args) { -        String log = String.format(logFormat, args); -        mEventLogger.log(log); -        if (Log.isLoggable(mTag, Log.DEBUG)) { -            Slogf.d(mTag, log); -        } -    } - -    void dump(IndentingPrintWriter pw) { -        mEventLogger.dump(pw); -    } -} diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java index 0e11df8282a7..7269f24fc4b1 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java @@ -40,11 +40,11 @@ import android.os.Looper;  import android.os.RemoteException;  import android.os.UserHandle;  import android.util.ArraySet; -import android.util.IndentingPrintWriter;  import android.util.MutableInt;  import com.android.internal.annotations.GuardedBy;  import com.android.internal.annotations.VisibleForTesting; +import com.android.server.broadcastradio.RadioEventLogger;  import com.android.server.broadcastradio.RadioServiceUserController;  import com.android.server.utils.Slogf; @@ -453,7 +453,7 @@ final class RadioModule {          return BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);      } -    void dumpInfo(IndentingPrintWriter pw) { +    void dumpInfo(android.util.IndentingPrintWriter pw) {          pw.printf("RadioModule\n");          pw.increaseIndent();          pw.printf("BroadcastRadioService: %s\n", mService); diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java index 6d435e38117f..b1b5d3488a5b 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java @@ -31,11 +31,11 @@ import android.os.Binder;  import android.os.RemoteException;  import android.util.ArrayMap;  import android.util.ArraySet; -import android.util.IndentingPrintWriter;  import android.util.MutableBoolean;  import android.util.MutableInt;  import com.android.internal.annotations.GuardedBy; +import com.android.server.broadcastradio.RadioEventLogger;  import com.android.server.broadcastradio.RadioServiceUserController;  import com.android.server.utils.Slogf; @@ -389,7 +389,7 @@ final class TunerSession extends ITuner.Stub {          }      } -    void dumpInfo(IndentingPrintWriter pw) { +    void dumpInfo(android.util.IndentingPrintWriter pw) {          pw.printf("TunerSession\n");          pw.increaseIndent();          pw.printf("HIDL HAL Session: %s\n", mHwSession); diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 85a231fafb0a..1c169a055078 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -585,7 +585,7 @@ import javax.xml.datatype.DatatypeConfigurationException;   *              </point>   *          </luxThresholds>   *     </idleScreenRefreshRateTimeout> - * + *     <supportsVrr>true</supportsVrr>   *   *    </displayConfiguration>   *  } @@ -872,6 +872,8 @@ public class DisplayDeviceConfig {       */      private float mBrightnessCapForWearBedtimeMode; +    private boolean mVrrSupportEnabled; +      private final DisplayManagerFlags mFlags;      @VisibleForTesting @@ -1606,6 +1608,13 @@ public class DisplayDeviceConfig {          return mBrightnessCapForWearBedtimeMode;      } +    /** +     * @return true if display supports dvrr +     */ +    public boolean isVrrSupportEnabled() { +        return mVrrSupportEnabled; +    } +      @Override      public String toString() {          return "DisplayDeviceConfig{" @@ -1705,6 +1714,8 @@ public class DisplayDeviceConfig {                  + "\n"                  + "mEvenDimmerBrightnessData:" + (mEvenDimmerBrightnessData != null                  ? mEvenDimmerBrightnessData.toString() : "null") +                + "\n" +                + "mVrrSupported= " + mVrrSupportEnabled + "\n"                  + "}";      } @@ -1779,6 +1790,7 @@ public class DisplayDeviceConfig {                  mHdrBrightnessData = HdrBrightnessData.loadConfig(config);                  loadBrightnessCapForWearBedtimeMode(config);                  loadIdleScreenRefreshRateTimeoutConfigs(config); +                mVrrSupportEnabled = config.getSupportsVrr();              } else {                  Slog.w(TAG, "DisplayDeviceConfig file is null");              } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 31092f27c838..8f1277bfe507 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -2764,6 +2764,7 @@ public final class DisplayManagerService extends SystemService {                              + requestedRefreshRate + " on Display: " + displayId);                  }              } +              mDisplayModeDirector.getAppRequestObserver().setAppRequest(                      displayId, requestedModeId, requestedMinRefreshRate, requestedMaxRefreshRate); @@ -4939,6 +4940,18 @@ public final class DisplayManagerService extends SystemService {          }          @Override +        public boolean isVrrSupportEnabled(int displayId) { +            DisplayDevice device; +            synchronized (mSyncRoot) { +                device = getDeviceForDisplayLocked(displayId); +            } +            if (device == null) { +                return false; +            } +            return device.getDisplayDeviceConfig().isVrrSupportEnabled(); +        } + +        @Override          public void setWindowManagerMirroring(int displayId, boolean isMirroring) {              synchronized (mSyncRoot) {                  final DisplayDevice device = getDeviceForDisplayLocked(displayId); diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java index d084d1c26b1c..a862b6e8f8f4 100644 --- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java @@ -105,6 +105,7 @@ import java.util.function.IntSupplier;   * picked by the system based on system-wide and display-specific configuration.   */  public class DisplayModeDirector { +      public static final float SYNCHRONIZED_REFRESH_RATE_TARGET = DEFAULT_LOW_REFRESH_RATE;      public static final float SYNCHRONIZED_REFRESH_RATE_TOLERANCE = 1;      private static final String TAG = "DisplayModeDirector"; @@ -149,6 +150,9 @@ public class DisplayModeDirector {      // A map from the display ID to the default mode of that display.      private SparseArray<Display.Mode> mDefaultModeByDisplay; +    // a map from display id to vrr support +    private SparseBooleanArray mVrrSupportedByDisplay; +      private BrightnessObserver mBrightnessObserver;      private DesiredDisplayModeSpecsListener mDesiredDisplayModeSpecsListener; @@ -189,8 +193,6 @@ public class DisplayModeDirector {      private final DisplayManagerFlags mDisplayManagerFlags; -    private final boolean mDvrrSupported; -      public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,              @NonNull DisplayManagerFlags displayManagerFlags) { @@ -200,8 +202,6 @@ public class DisplayModeDirector {      public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,              @NonNull Injector injector,              @NonNull DisplayManagerFlags displayManagerFlags) { -        mDvrrSupported = context.getResources().getBoolean( -                com.android.internal.R.bool.config_supportsDvrr);          mIsDisplayResolutionRangeVotingEnabled = displayManagerFlags                  .isDisplayResolutionRangeVotingEnabled();          mIsUserPreferredModeVoteEnabled = displayManagerFlags.isUserPreferredModeVoteEnabled(); @@ -219,23 +219,23 @@ public class DisplayModeDirector {                  displayManagerFlags.isRefreshRateVotingTelemetryEnabled());          mSupportedModesByDisplay = new SparseArray<>();          mDefaultModeByDisplay = new SparseArray<>(); +        mVrrSupportedByDisplay = new SparseBooleanArray();          mAppRequestObserver = new AppRequestObserver();          mConfigParameterProvider = new DeviceConfigParameterProvider(injector.getDeviceConfig());          mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); -        mSettingsObserver = new SettingsObserver(context, handler, mDvrrSupported, -                displayManagerFlags); -        mBrightnessObserver = new BrightnessObserver(context, handler, injector, mDvrrSupported, +        mSettingsObserver = new SettingsObserver(context, handler, displayManagerFlags); +        mBrightnessObserver = new BrightnessObserver(context, handler, injector,                  displayManagerFlags);          mDefaultDisplayDeviceConfig = null;          mUdfpsObserver = new UdfpsObserver();          mVotesStorage = new VotesStorage(this::notifyDesiredDisplayModeSpecsChangedLocked,                  mVotesStatsReporter); -        mDisplayObserver = new DisplayObserver(context, handler, mVotesStorage); +        mDisplayObserver = new DisplayObserver(context, handler, mVotesStorage, injector);          mSensorObserver = new ProximitySensorObserver(mVotesStorage, injector);          mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, mVotesStorage);          mHbmObserver = new HbmObserver(injector, mVotesStorage, BackgroundThread.getHandler(),                  mDeviceConfigDisplaySettings); -        if (mDvrrSupported && displayManagerFlags.isRestrictDisplayModesEnabled()) { +        if (displayManagerFlags.isRestrictDisplayModesEnabled()) {              mSystemRequestObserver = new SystemRequestObserver(mVotesStorage);          } else {              mSystemRequestObserver = null; @@ -315,7 +315,8 @@ public class DisplayModeDirector {              List<Display.Mode> availableModes = new ArrayList<>();              availableModes.add(defaultMode);              VoteSummary primarySummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled, -                    mDvrrSupported, mLoggingEnabled, mSupportsFrameRateOverride); +                    mVrrSupportedByDisplay.get(displayId), +                    mLoggingEnabled, mSupportsFrameRateOverride);              int lowestConsideredPriority = Vote.MIN_PRIORITY;              int highestConsideredPriority = Vote.MAX_PRIORITY; @@ -355,7 +356,8 @@ public class DisplayModeDirector {              }              VoteSummary appRequestSummary = new VoteSummary(mIsDisplayResolutionRangeVotingEnabled, -                    mDvrrSupported, mLoggingEnabled, mSupportsFrameRateOverride); +                    mVrrSupportedByDisplay.get(displayId), +                    mLoggingEnabled, mSupportsFrameRateOverride);              appRequestSummary.applyVotes(votes,                      Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, @@ -442,6 +444,15 @@ public class DisplayModeDirector {          return mAppRequestObserver;      } +    private boolean isVrrSupportedByAnyDisplayLocked() { +        for (int i = 0; i < mVrrSupportedByDisplay.size(); i++) { +            if (mVrrSupportedByDisplay.valueAt(i)) { +                return true; +            } +        } +        return false; +    } +      /**       * Sets the desiredDisplayModeSpecsListener for changes to display mode and refresh rate ranges.       */ @@ -539,7 +550,13 @@ public class DisplayModeDirector {       */      public void requestDisplayModes(IBinder token, int displayId, int[] modeIds) {          if (mSystemRequestObserver != null) { -            mSystemRequestObserver.requestDisplayModes(token, displayId, modeIds); +            boolean vrrSupported; +            synchronized (mLock) { +                vrrSupported = mVrrSupportedByDisplay.get(displayId); +            } +            if (vrrSupported) { +                mSystemRequestObserver.requestDisplayModes(token, displayId, modeIds); +            }          }      } @@ -627,6 +644,11 @@ public class DisplayModeDirector {      }      @VisibleForTesting +    void injectVrrByDisplay(SparseBooleanArray vrrByDisplay) { +        mVrrSupportedByDisplay = vrrByDisplay; +    } + +    @VisibleForTesting      void injectVotesByDisplay(SparseArray<SparseArray<Vote>> votesByDisplay) {          mVotesStorage.injectVotesByDisplay(votesByDisplay);      } @@ -906,11 +928,11 @@ public class DisplayModeDirector {          private float mDefaultPeakRefreshRate;          private float mDefaultRefreshRate; -        SettingsObserver(@NonNull Context context, @NonNull Handler handler, boolean dvrrSupported, +        SettingsObserver(@NonNull Context context, @NonNull Handler handler,                  DisplayManagerFlags flags) {              super(handler);              mContext = context; -            mVsynLowPowerVoteEnabled = dvrrSupported && flags.isVsyncLowPowerVoteEnabled(); +            mVsynLowPowerVoteEnabled = flags.isVsyncLowPowerVoteEnabled();              // We don't want to load from the DeviceConfig while constructing since this leads to              // a spike in the latency of DisplayManagerService startup. This happens because              // reading from the DeviceConfig is an intensive IO operation and having it in the @@ -1020,7 +1042,7 @@ public class DisplayModeDirector {              boolean inLowPowerMode = Settings.Global.getInt(mContext.getContentResolver(),                      Settings.Global.LOW_POWER_MODE, 0 /*default*/) != 0;              final Vote vote; -            if (inLowPowerMode && mVsynLowPowerVoteEnabled) { +            if (inLowPowerMode && mVsynLowPowerVoteEnabled && isVrrSupportedByAnyDisplayLocked()) {                  vote = Vote.forSupportedRefreshRates(List.of(                          new SupportedRefreshRatesVote.RefreshRates(/* peakRefreshRate= */ 60f,                                  /* vsyncRate= */ 240f), @@ -1190,8 +1212,8 @@ public class DisplayModeDirector {          /**           * Sets refresh rates from app request           */ -        public void setAppRequest(int displayId, int modeId, float requestedMinRefreshRateRange, -                float requestedMaxRefreshRateRange) { +        public void setAppRequest(int displayId, int modeId, +                float requestedMinRefreshRateRange, float requestedMaxRefreshRateRange) {              synchronized (mLock) {                  setAppRequestedModeLocked(displayId, modeId);                  setAppPreferredRefreshRateRangeLocked(displayId, requestedMinRefreshRateRange, @@ -1204,7 +1226,6 @@ public class DisplayModeDirector {              if (Objects.equals(requestedMode, mAppRequestedModeByDisplay.get(displayId))) {                  return;              } -              final Vote baseModeRefreshRateVote;              final Vote sizeVote;              if (requestedMode != null) { @@ -1295,13 +1316,16 @@ public class DisplayModeDirector {          private final Context mContext;          private final Handler mHandler;          private final VotesStorage mVotesStorage; + +        private DisplayManagerInternal mDisplayManagerInternal;          private int mExternalDisplayPeakWidth;          private int mExternalDisplayPeakHeight;          private int mExternalDisplayPeakRefreshRate;          private final boolean mRefreshRateSynchronizationEnabled;          private final Set<Integer> mExternalDisplaysConnected = new HashSet<>(); -        DisplayObserver(Context context, Handler handler, VotesStorage votesStorage) { +        DisplayObserver(Context context, Handler handler, VotesStorage votesStorage, +                Injector injector) {              mContext = context;              mHandler = handler;              mVotesStorage = votesStorage; @@ -1330,6 +1354,7 @@ public class DisplayModeDirector {          }          public void observe() { +            mDisplayManagerInternal = mInjector.getDisplayManagerInternal();              mInjector.registerDisplayListener(this, mHandler);              // Populate existing displays @@ -1342,17 +1367,21 @@ public class DisplayModeDirector {                  modes.put(displayId, info.supportedModes);                  defaultModes.put(displayId, info.getDefaultMode());              } +            boolean vrrSupportedByDefaultDisplay = mDisplayManagerInternal +                    .isVrrSupportEnabled(Display.DEFAULT_DISPLAY);              synchronized (mLock) {                  final int size = modes.size();                  for (int i = 0; i < size; i++) {                      mSupportedModesByDisplay.put(modes.keyAt(i), modes.valueAt(i));                      mDefaultModeByDisplay.put(defaultModes.keyAt(i), defaultModes.valueAt(i));                  } +                mVrrSupportedByDisplay.put(Display.DEFAULT_DISPLAY, vrrSupportedByDefaultDisplay);              }          }          @Override          public void onDisplayAdded(int displayId) { +            updateVrrStatus(displayId);              DisplayInfo displayInfo = getDisplayInfo(displayId);              updateDisplayModes(displayId, displayInfo);              updateLayoutLimitedFrameRate(displayId, displayInfo); @@ -1366,6 +1395,7 @@ public class DisplayModeDirector {              synchronized (mLock) {                  mSupportedModesByDisplay.remove(displayId);                  mDefaultModeByDisplay.remove(displayId); +                mVrrSupportedByDisplay.delete(displayId);                  mSettingsObserver.removeRefreshRateSetting(displayId);              }              updateLayoutLimitedFrameRate(displayId, null); @@ -1376,6 +1406,7 @@ public class DisplayModeDirector {          @Override          public void onDisplayChanged(int displayId) { +            updateVrrStatus(displayId);              DisplayInfo displayInfo = getDisplayInfo(displayId);              updateDisplayModes(displayId, displayInfo);              updateLayoutLimitedFrameRate(displayId, displayInfo); @@ -1505,6 +1536,13 @@ public class DisplayModeDirector {              mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, null);          } +        private void updateVrrStatus(int displayId) { +            boolean isVrrSupported = mDisplayManagerInternal.isVrrSupportEnabled(displayId); +            synchronized (mLock) { +                mVrrSupportedByDisplay.put(displayId, isVrrSupported); +            } +        } +          private void updateDisplayModes(int displayId, @Nullable DisplayInfo info) {              if (info == null) {                  return; @@ -1631,7 +1669,7 @@ public class DisplayModeDirector {          private @Temperature.ThrottlingStatus int mThermalStatus = Temperature.THROTTLING_NONE;          BrightnessObserver(Context context, Handler handler, Injector injector, -                boolean dvrrSupported , DisplayManagerFlags flags) { +                DisplayManagerFlags flags) {              mContext = context;              mHandler = handler;              mInjector = injector; @@ -1639,7 +1677,7 @@ public class DisplayModeDirector {                  /* attemptReadFromFeatureParams= */ false);              mRefreshRateInHighZone = context.getResources().getInteger(                      R.integer.config_fixedRefreshRateInHighZone); -            mVsyncLowLightBlockingVoteEnabled = dvrrSupported && flags.isVsyncLowLightVoteEnabled(); +            mVsyncLowLightBlockingVoteEnabled = flags.isVsyncLowLightVoteEnabled();          }          /** @@ -2225,7 +2263,8 @@ public class DisplayModeDirector {                      }                  } -                if (mVsyncLowLightBlockingVoteEnabled) { +                if (mVsyncLowLightBlockingVoteEnabled +                        && mVrrSupportedByDisplay.get(Display.DEFAULT_DISPLAY)) {                      refreshRateSwitchingVote = Vote.forSupportedRefreshRatesAndDisableSwitching(                              List.of(                                      new SupportedRefreshRatesVote.RefreshRates( diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java index f3836794c32e..47f73f1b819a 100644 --- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java +++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java @@ -167,7 +167,8 @@ public final class FontManagerService extends IFontManager.Stub {          public void onBootPhase(int phase) {              final int latestFontLoadBootPhase =                      (Flags.completeFontLoadInSystemServicesReady()) -                            ? SystemService.PHASE_SYSTEM_SERVICES_READY +                            // Complete font load in the phase before PHASE_SYSTEM_SERVICES_READY +                            ? SystemService.PHASE_LOCK_SETTINGS_READY                              : SystemService.PHASE_ACTIVITY_MANAGER_READY;              if (phase == latestFontLoadBootPhase) {                  // Wait for FontManagerService to start since it will be needed after this point. diff --git a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java index c7b60da2fc51..dd6433d98553 100644 --- a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java +++ b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeMapRepository.java @@ -19,11 +19,13 @@ package com.android.server.inputmethod;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.UserIdInt; +import android.content.Context;  import android.content.pm.UserInfo;  import android.os.Handler;  import android.util.SparseArray;  import com.android.internal.annotations.GuardedBy; +import com.android.internal.inputmethod.DirectBootAwareness;  import com.android.server.LocalServices;  import com.android.server.pm.UserManagerInternal; @@ -67,7 +69,7 @@ final class AdditionalSubtypeMapRepository {          AdditionalSubtypeUtils.save(map, inputMethodMap, userId);      } -    static void initialize(@NonNull Handler handler) { +    static void initialize(@NonNull Handler handler, @NonNull Context context) {          final UserManagerInternal userManagerInternal =                  LocalServices.getService(UserManagerInternal.class);          handler.post(() -> { @@ -79,8 +81,16 @@ final class AdditionalSubtypeMapRepository {                              handler.post(() -> {                                  synchronized (ImfLock.class) {                                      if (!sPerUserMap.contains(userId)) { -                                        sPerUserMap.put(userId, -                                                AdditionalSubtypeUtils.load(userId)); +                                        final AdditionalSubtypeMap additionalSubtypeMap = +                                                AdditionalSubtypeUtils.load(userId); +                                        sPerUserMap.put(userId, additionalSubtypeMap); +                                        final InputMethodSettings settings = +                                                InputMethodManagerService +                                                        .queryInputMethodServicesInternal(context, +                                                                userId, +                                                                additionalSubtypeMap, +                                                                DirectBootAwareness.AUTO); +                                        InputMethodSettingsRepository.put(userId, settings);                                      }                                  }                              }); diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java b/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java new file mode 100644 index 000000000000..7890fe0ed461 --- /dev/null +++ b/services/core/java/com/android/server/inputmethod/IInputMethodManagerImpl.java @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.inputmethod; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.Manifest; +import android.annotation.BinderThread; +import android.annotation.EnforcePermission; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.os.Binder; +import android.os.IBinder; +import android.os.ResultReceiver; +import android.os.ShellCallback; +import android.view.MotionEvent; +import android.view.WindowManager; +import android.view.inputmethod.CursorAnchorInfo; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.ImeTracker; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; +import android.window.ImeOnBackInvokedDispatcher; + +import com.android.internal.inputmethod.DirectBootAwareness; +import com.android.internal.inputmethod.IBooleanListener; +import com.android.internal.inputmethod.IConnectionlessHandwritingCallback; +import com.android.internal.inputmethod.IImeTracker; +import com.android.internal.inputmethod.IInputMethodClient; +import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection; +import com.android.internal.inputmethod.IRemoteInputConnection; +import com.android.internal.inputmethod.InputBindResult; +import com.android.internal.inputmethod.SoftInputShowHideReason; +import com.android.internal.inputmethod.StartInputFlags; +import com.android.internal.inputmethod.StartInputReason; +import com.android.internal.view.IInputMethodManager; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.List; + +/** + * An actual implementation class of {@link IInputMethodManager.Stub} to allow other classes to + * focus on handling IPC callbacks. + */ +final class IInputMethodManagerImpl extends IInputMethodManager.Stub { + +    /** +     * Tells that the given permission is already verified before the annotated method gets called. +     */ +    @Retention(SOURCE) +    @Target({METHOD}) +    @interface PermissionVerified { +        String value() default ""; +    } + +    @BinderThread +    interface Callback { +        void addClient(IInputMethodClient client, IRemoteInputConnection inputConnection, +                int selfReportedDisplayId); + +        InputMethodInfo getCurrentInputMethodInfoAsUser(@UserIdInt int userId); + +        List<InputMethodInfo> getInputMethodList(@UserIdInt int userId, +                @DirectBootAwareness int directBootAwareness); + +        List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId); + +        List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId, +                boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId); + +        InputMethodSubtype getLastInputMethodSubtype(@UserIdInt int userId); + +        boolean showSoftInput(IInputMethodClient client, IBinder windowToken, +                @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, +                @MotionEvent.ToolType int lastClickToolType, ResultReceiver resultReceiver, +                @SoftInputShowHideReason int reason); + +        boolean hideSoftInput(IInputMethodClient client, IBinder windowToken, +                @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags, +                ResultReceiver resultReceiver, @SoftInputShowHideReason int reason); + +        @PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) +        void hideSoftInputFromServerForTest(); + +        void startInputOrWindowGainedFocusAsync( +                @StartInputReason int startInputReason, IInputMethodClient client, +                IBinder windowToken, @StartInputFlags int startInputFlags, +                @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags, +                @Nullable EditorInfo editorInfo, IRemoteInputConnection inputConnection, +                IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, +                int unverifiedTargetSdkVersion, @UserIdInt int userId, +                @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq); + +        InputBindResult startInputOrWindowGainedFocus( +                @StartInputReason int startInputReason, IInputMethodClient client, +                IBinder windowToken, @StartInputFlags int startInputFlags, +                @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, int windowFlags, +                @Nullable EditorInfo editorInfo, IRemoteInputConnection inputConnection, +                IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, +                int unverifiedTargetSdkVersion, @UserIdInt int userId, +                @NonNull ImeOnBackInvokedDispatcher imeDispatcher); + +        void showInputMethodPickerFromClient(IInputMethodClient client, int auxiliarySubtypeMode); + +        @PermissionVerified(Manifest.permission.WRITE_SECURE_SETTINGS) +        void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId); + +        @PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) +        boolean isInputMethodPickerShownForTest(); + +        InputMethodSubtype getCurrentInputMethodSubtype(@UserIdInt int userId); + +        void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes, +                @UserIdInt int userId); + +        void setExplicitlyEnabledInputMethodSubtypes(String imeId, +                @NonNull int[] subtypeHashCodes, @UserIdInt int userId); + +        int getInputMethodWindowVisibleHeight(IInputMethodClient client); + +        void reportPerceptibleAsync(IBinder windowToken, boolean perceptible); + +        @PermissionVerified(Manifest.permission.INTERNAL_SYSTEM_WINDOW) +        void removeImeSurface(); + +        void removeImeSurfaceFromWindowAsync(IBinder windowToken); + +        void startProtoDump(byte[] bytes, int i, String s); + +        boolean isImeTraceEnabled(); + +        @PermissionVerified(Manifest.permission.CONTROL_UI_TRACING) +        void startImeTrace(); + +        @PermissionVerified(Manifest.permission.CONTROL_UI_TRACING) +        void stopImeTrace(); + +        void startStylusHandwriting(IInputMethodClient client); + +        void startConnectionlessStylusHandwriting(IInputMethodClient client, @UserIdInt int userId, +                @Nullable CursorAnchorInfo cursorAnchorInfo, @Nullable String delegatePackageName, +                @Nullable String delegatorPackageName, +                @NonNull IConnectionlessHandwritingCallback callback); + +        boolean acceptStylusHandwritingDelegation(@NonNull IInputMethodClient client, +                @UserIdInt int userId, @NonNull String delegatePackageName, +                @NonNull String delegatorPackageName, +                @InputMethodManager.HandwritingDelegateFlags int flags); + +        void acceptStylusHandwritingDelegationAsync(@NonNull IInputMethodClient client, +                @UserIdInt int userId, @NonNull String delegatePackageName, +                @NonNull String delegatorPackageName, +                @InputMethodManager.HandwritingDelegateFlags int flags, IBooleanListener callback); + +        void prepareStylusHandwritingDelegation(@NonNull IInputMethodClient client, +                @UserIdInt int userId, @NonNull String delegatePackageName, +                @NonNull String delegatorPackageName); + +        boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId, boolean connectionless); + +        @PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) +        void addVirtualStylusIdForTestSession(IInputMethodClient client); + +        @PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) +        void setStylusWindowIdleTimeoutForTest(IInputMethodClient client, long timeout); + +        IImeTracker getImeTrackerService(); + +        void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, +                @Nullable FileDescriptor err, @NonNull String[] args, +                @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver, +                @NonNull Binder self); + +        void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args); +    } + +    @NonNull +    private final Callback mCallback; + +    private IInputMethodManagerImpl(@NonNull Callback callback) { +        mCallback = callback; +    } + +    static IInputMethodManagerImpl create(@NonNull Callback callback) { +        return new IInputMethodManagerImpl(callback); +    } + +    @Override +    public void addClient(IInputMethodClient client, IRemoteInputConnection inputmethod, +            int untrustedDisplayId) { +        mCallback.addClient(client, inputmethod, untrustedDisplayId); +    } + +    @Override +    public InputMethodInfo getCurrentInputMethodInfoAsUser(@UserIdInt int userId) { +        return mCallback.getCurrentInputMethodInfoAsUser(userId); +    } + +    @Override +    public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId, +            int directBootAwareness) { +        return mCallback.getInputMethodList(userId, directBootAwareness); +    } + +    @Override +    public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) { +        return mCallback.getEnabledInputMethodList(userId); +    } + +    @Override +    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId, +            boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId) { +        return mCallback.getEnabledInputMethodSubtypeList(imiId, allowsImplicitlyEnabledSubtypes, +                userId); +    } + +    @Override +    public InputMethodSubtype getLastInputMethodSubtype(@UserIdInt int userId) { +        return mCallback.getLastInputMethodSubtype(userId); +    } + +    @Override +    public boolean showSoftInput(IInputMethodClient client, IBinder windowToken, +            @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, +            @MotionEvent.ToolType int lastClickToolType, ResultReceiver resultReceiver, +            @SoftInputShowHideReason int reason) { +        return mCallback.showSoftInput(client, windowToken, statsToken, flags, lastClickToolType, +                resultReceiver, reason); +    } + +    @Override +    public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken, +            @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags, +            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) { +        return mCallback.hideSoftInput(client, windowToken, statsToken, flags, resultReceiver, +                reason); +    } + +    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) +    @Override +    public void hideSoftInputFromServerForTest() { +        super.hideSoftInputFromServerForTest_enforcePermission(); + +        mCallback.hideSoftInputFromServerForTest(); +    } + +    @Override +    public InputBindResult startInputOrWindowGainedFocus( +            @StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken, +            @StartInputFlags int startInputFlags, +            @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, +            int windowFlags, @Nullable EditorInfo editorInfo, +            IRemoteInputConnection inputConnection, +            IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, +            int unverifiedTargetSdkVersion, @UserIdInt int userId, +            @NonNull ImeOnBackInvokedDispatcher imeDispatcher) { +        return mCallback.startInputOrWindowGainedFocus( +                startInputReason, client, windowToken, startInputFlags, softInputMode, +                windowFlags, editorInfo, inputConnection, remoteAccessibilityInputConnection, +                unverifiedTargetSdkVersion, userId, imeDispatcher); +    } + +    @Override +    public void startInputOrWindowGainedFocusAsync(@StartInputReason int startInputReason, +            IInputMethodClient client, IBinder windowToken, +            @StartInputFlags int startInputFlags, +            @WindowManager.LayoutParams.SoftInputModeFlags int softInputMode, +            int windowFlags, @Nullable EditorInfo editorInfo, +            IRemoteInputConnection inputConnection, +            IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, +            int unverifiedTargetSdkVersion, @UserIdInt int userId, +            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq) { +        mCallback.startInputOrWindowGainedFocusAsync( +                startInputReason, client, windowToken, startInputFlags, softInputMode, +                windowFlags, editorInfo, inputConnection, remoteAccessibilityInputConnection, +                unverifiedTargetSdkVersion, userId, imeDispatcher, startInputSeq); +    } + +    @Override +    public void showInputMethodPickerFromClient(IInputMethodClient client, +            int auxiliarySubtypeMode) { +        mCallback.showInputMethodPickerFromClient(client, auxiliarySubtypeMode); +    } + +    @EnforcePermission(Manifest.permission.WRITE_SECURE_SETTINGS) +    @Override +    public void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId) { +        super.showInputMethodPickerFromSystem_enforcePermission(); + +        mCallback.showInputMethodPickerFromSystem(auxiliarySubtypeMode, displayId); + +    } + +    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) +    @Override +    public boolean isInputMethodPickerShownForTest() { +        super.isInputMethodPickerShownForTest_enforcePermission(); + +        return mCallback.isInputMethodPickerShownForTest(); +    } + +    @Override +    public InputMethodSubtype getCurrentInputMethodSubtype(@UserIdInt int userId) { +        return mCallback.getCurrentInputMethodSubtype(userId); +    } + +    @Override +    public void setAdditionalInputMethodSubtypes(String id, InputMethodSubtype[] subtypes, +            @UserIdInt int userId) { +        mCallback.setAdditionalInputMethodSubtypes(id, subtypes, userId); +    } + +    @Override +    public void setExplicitlyEnabledInputMethodSubtypes(String imeId, int[] subtypeHashCodes, +            @UserIdInt int userId) { +        mCallback.setExplicitlyEnabledInputMethodSubtypes(imeId, subtypeHashCodes, userId); +    } + +    @Override +    public int getInputMethodWindowVisibleHeight(IInputMethodClient client) { +        return mCallback.getInputMethodWindowVisibleHeight(client); +    } + +    @Override +    public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) { +        mCallback.reportPerceptibleAsync(windowToken, perceptible); +    } + +    @EnforcePermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW) +    @Override +    public void removeImeSurface() { +        super.removeImeSurface_enforcePermission(); + +        mCallback.removeImeSurface(); +    } + +    @Override +    public void removeImeSurfaceFromWindowAsync(IBinder windowToken) { +        mCallback.removeImeSurfaceFromWindowAsync(windowToken); +    } + +    @Override +    public void startProtoDump(byte[] protoDump, int source, String where) { +        mCallback.startProtoDump(protoDump, source, where); +    } + +    @Override +    public boolean isImeTraceEnabled() { +        return mCallback.isImeTraceEnabled(); +    } + +    @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) +    @Override +    public void startImeTrace() { +        super.startImeTrace_enforcePermission(); + +        mCallback.startImeTrace(); +    } + +    @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) +    @Override +    public void stopImeTrace() { +        super.stopImeTrace_enforcePermission(); + +        mCallback.stopImeTrace(); +    } + +    @Override +    public void startStylusHandwriting(IInputMethodClient client) { +        mCallback.startStylusHandwriting(client); +    } + +    @Override +    public void startConnectionlessStylusHandwriting(IInputMethodClient client, +            @UserIdInt int userId, CursorAnchorInfo cursorAnchorInfo, +            String delegatePackageName, String delegatorPackageName, +            IConnectionlessHandwritingCallback callback) { +        mCallback.startConnectionlessStylusHandwriting(client, userId, cursorAnchorInfo, +                delegatePackageName, delegatorPackageName, callback); +    } + +    @Override +    public void prepareStylusHandwritingDelegation(IInputMethodClient client, @UserIdInt int userId, +            String delegatePackageName, String delegatorPackageName) { +        mCallback.prepareStylusHandwritingDelegation(client, userId, +                delegatePackageName, delegatorPackageName); +    } + +    @Override +    public boolean acceptStylusHandwritingDelegation(IInputMethodClient client, +            @UserIdInt int userId, String delegatePackageName, String delegatorPackageName, +            @InputMethodManager.HandwritingDelegateFlags int flags) { +        return mCallback.acceptStylusHandwritingDelegation(client, userId, +                delegatePackageName, delegatorPackageName, flags); +    } + +    @Override +    public void acceptStylusHandwritingDelegationAsync(IInputMethodClient client, +            @UserIdInt int userId, String delegatePackageName, String delegatorPackageName, +            @InputMethodManager.HandwritingDelegateFlags int flags, +            IBooleanListener callback) { +        mCallback.acceptStylusHandwritingDelegationAsync(client, userId, +                delegatePackageName, delegatorPackageName, flags, callback); +    } + +    @Override +    public boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId, +            boolean connectionless) { +        return mCallback.isStylusHandwritingAvailableAsUser(userId, connectionless); +    } + +    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) +    @Override +    public void addVirtualStylusIdForTestSession(IInputMethodClient client) { +        super.addVirtualStylusIdForTestSession_enforcePermission(); + +        mCallback.addVirtualStylusIdForTestSession(client); +    } + +    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) +    @Override +    public void setStylusWindowIdleTimeoutForTest(IInputMethodClient client, long timeout) { +        super.setStylusWindowIdleTimeoutForTest_enforcePermission(); + +        mCallback.setStylusWindowIdleTimeoutForTest(client, timeout); +    } + +    @Override +    public IImeTracker getImeTrackerService() { +        return mCallback.getImeTrackerService(); +    } + +    @Override +    public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, +            @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, +            @NonNull ResultReceiver resultReceiver) { +        mCallback.onShellCommand(in, out, err, args, callback, resultReceiver, this); +    } + +    @Override +    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { +        mCallback.dump(fd, pw, args); +    } +} diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index a100fe06c407..3e23f972bd45 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -16,10 +16,12 @@  package com.android.server.inputmethod; +import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;  import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;  import android.annotation.NonNull;  import android.annotation.Nullable; +import android.app.ActivityOptions;  import android.app.PendingIntent;  import android.content.ComponentName;  import android.content.Context; @@ -410,7 +412,7 @@ final class InputMethodBindingController {              Slog.v(TAG,                      "Removing window token: " + mCurToken + " for display: " + curTokenDisplayId);          } -        mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */, +        mWindowManagerInternal.removeWindowToken(mCurToken, true /* removeWindows */,                  false /* animateExit */, curTokenDisplayId);          mCurToken = null;      } @@ -452,9 +454,12 @@ final class InputMethodBindingController {          intent.setComponent(component);          intent.putExtra(Intent.EXTRA_CLIENT_LABEL,                  com.android.internal.R.string.input_method_binding_label); +        var options = ActivityOptions.makeBasic() +                .setPendingIntentCreatorBackgroundActivityStartMode( +                        MODE_BACKGROUND_ACTIVITY_START_DENIED);          intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(                  mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), -                PendingIntent.FLAG_IMMUTABLE)); +                PendingIntent.FLAG_IMMUTABLE, options.toBundle()));          return intent;      } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index c6a48ec9018e..e41b47f8f00e 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -61,7 +61,6 @@ import android.annotation.AnyThread;  import android.annotation.BinderThread;  import android.annotation.DrawableRes;  import android.annotation.DurationMillisLong; -import android.annotation.EnforcePermission;  import android.annotation.IntDef;  import android.annotation.NonNull;  import android.annotation.Nullable; @@ -172,7 +171,6 @@ import com.android.internal.util.ArrayUtils;  import com.android.internal.util.ConcurrentUtils;  import com.android.internal.util.DumpUtils;  import com.android.internal.util.Preconditions; -import com.android.internal.view.IInputMethodManager;  import com.android.server.AccessibilityManagerInternal;  import com.android.server.EventLogTags;  import com.android.server.LocalServices; @@ -211,8 +209,9 @@ import java.util.function.IntConsumer;  /**   * This class provides a system service that manages input methods.   */ -public final class InputMethodManagerService extends IInputMethodManager.Stub -        implements Handler.Callback { +public final class InputMethodManagerService implements IInputMethodManagerImpl.Callback, +        ZeroJankProxy.Callback, Handler.Callback { +      // Virtual device id for test.      private static final Integer VIRTUAL_STYLUS_ID_FOR_TEST = 999999;      static final boolean DEBUG = false; @@ -870,9 +869,17 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub              if (!mSystemReady) {                  return;              } -            mSettings = queryInputMethodServicesInternal(mContext, mSettings.getUserId(), -                    AdditionalSubtypeMapRepository.get(mSettings.getUserId()), -                    DirectBootAwareness.AUTO); +            for (int userId : mUserManagerInternal.getUserIds()) { +                final InputMethodSettings settings = queryInputMethodServicesInternal( +                                mContext, +                                userId, +                                AdditionalSubtypeMapRepository.get(userId), +                                DirectBootAwareness.AUTO); +                InputMethodSettingsRepository.put(userId, settings); +                if (userId == mSettings.getUserId()) { +                    mSettings = settings; +                } +            }              postInputMethodSettingUpdatedLocked(true /* resetDefaultEnabledIme */);              // If the locale is changed, needs to reset the default ime              resetDefaultImeLocked(mContext); @@ -1119,12 +1126,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub                      AdditionalSubtypeMapRepository.putAndSave(userId, newAdditionalSubtypeMap,                              settings.getMethodMap());                  } - -                if (!isCurrentUser) { +                if (isCurrentUser +                        && !(additionalSubtypeChanged || shouldRebuildInputMethodListLocked())) {                      return;                  } -                if (!(additionalSubtypeChanged || shouldRebuildInputMethodListLocked())) { +                final InputMethodSettings newSettings = queryInputMethodServicesInternal(mContext, +                        userId, newAdditionalSubtypeMap, DirectBootAwareness.AUTO); +                InputMethodSettingsRepository.put(userId, newSettings); +                if (!isCurrentUser) {                      return;                  }                  mSettings = queryInputMethodServicesInternal(mContext, userId, @@ -1236,21 +1246,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub          @Override          public void onStart() {              mService.publishLocalService(); -            IInputMethodManager.Stub service; +            IInputMethodManagerImpl.Callback service;              if (Flags.useZeroJankProxy()) { -                service = -                        new ZeroJankProxy( -                                mService.mHandler::post, -                                mService, -                                () -> { -                                    synchronized (ImfLock.class) { -                                        return mService.isInputShown(); -                                    } -                                }); +                service = new ZeroJankProxy(mService.mHandler::post, mService);              } else {                  service = mService;              } -            publishBinderService(Context.INPUT_METHOD_SERVICE, service, false /*allowIsolated*/, +            publishBinderService(Context.INPUT_METHOD_SERVICE, +                    IInputMethodManagerImpl.create(service), false /*allowIsolated*/,                      DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);          } @@ -1289,21 +1292,22 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub      void onUnlockUser(@UserIdInt int userId) {          synchronized (ImfLock.class) { -            final int currentUserId = mSettings.getUserId();              if (DEBUG) { -                Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId); -            } -            if (userId != currentUserId) { -                return; +                Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" +                        + mSettings.getUserId());              }              if (!mSystemReady) {                  return;              } -            mSettings = queryInputMethodServicesInternal(mContext, userId, -                    AdditionalSubtypeMapRepository.get(userId), DirectBootAwareness.AUTO); -            // We need to rebuild IMEs. -            postInputMethodSettingUpdatedLocked(false /* resetDefaultEnabledIme */); -            updateInputMethodsFromSettingsLocked(true /* enabledChanged */); +            final InputMethodSettings newSettings = queryInputMethodServicesInternal(mContext, +                    userId, AdditionalSubtypeMapRepository.get(userId), DirectBootAwareness.AUTO); +            InputMethodSettingsRepository.put(userId, newSettings); +            if (mSettings.getUserId() == userId) { +                mSettings = newSettings; +                // We need to rebuild IMEs. +                postInputMethodSettingUpdatedLocked(false /* resetDefaultEnabledIme */); +                updateInputMethodsFromSettingsLocked(true /* enabledChanged */); +            }          }      } @@ -1336,77 +1340,79 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub              Context context,              @Nullable ServiceThread serviceThreadForTesting,              @Nullable InputMethodBindingController bindingControllerForTesting) { -        mContext = context; -        mRes = context.getResources(); -        SecureSettingsWrapper.onStart(mContext); -        // TODO(b/196206770): Disallow I/O on this thread. Currently it's needed for loading -        // additional subtypes in switchUserOnHandlerLocked(). -        final ServiceThread thread = -                serviceThreadForTesting != null -                        ? serviceThreadForTesting -                        : new ServiceThread( -                                HANDLER_THREAD_NAME, -                                Process.THREAD_PRIORITY_FOREGROUND, -                                true /* allowIo */); -        thread.start(); -        mHandler = Handler.createAsync(thread.getLooper(), this); -        SystemLocaleWrapper.onStart(context, this::onActionLocaleChanged, mHandler); -        mImeTrackerService = new ImeTrackerService(serviceThreadForTesting != null -                ? serviceThreadForTesting.getLooper() : Looper.getMainLooper()); -        // Note: SettingsObserver doesn't register observers in its constructor. -        mSettingsObserver = new SettingsObserver(mHandler); -        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); -        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); -        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); -        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); -        mImePlatformCompatUtils = new ImePlatformCompatUtils(); -        mInputMethodDeviceConfigs = new InputMethodDeviceConfigs(); -        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); - -        mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime); - -        mShowOngoingImeSwitcherForPhones = false; - -        AdditionalSubtypeMapRepository.initialize(mHandler); - -        final int userId = mActivityManagerInternal.getCurrentUserId(); - -        // mSettings should be created before buildInputMethodListLocked -        mSettings = InputMethodSettings.createEmptyMap(userId); - -        mSwitchingController = -                InputMethodSubtypeSwitchingController.createInstanceLocked(context, -                        mSettings.getMethodMap(), userId); -        mHardwareKeyboardShortcutController = -                new HardwareKeyboardShortcutController(mSettings.getMethodMap(), -                        mSettings.getUserId()); -        mMenuController = new InputMethodMenuController(this); -        mBindingController = -                bindingControllerForTesting != null -                        ? bindingControllerForTesting -                        : new InputMethodBindingController(this); -        mAutofillController = new AutofillSuggestionsController(this); - -        mVisibilityStateComputer = new ImeVisibilityStateComputer(this); -        mVisibilityApplier = new DefaultImeVisibilityApplier(this); - -        mClientController = new ClientController(mPackageManagerInternal);          synchronized (ImfLock.class) { +            mContext = context; +            mRes = context.getResources(); +            SecureSettingsWrapper.onStart(mContext); + +            // TODO(b/196206770): Disallow I/O on this thread. Currently it's needed for loading +            // additional subtypes in switchUserOnHandlerLocked(). +            final ServiceThread thread = +                    serviceThreadForTesting != null +                            ? serviceThreadForTesting +                            : new ServiceThread( +                                    HANDLER_THREAD_NAME, +                                    Process.THREAD_PRIORITY_FOREGROUND, +                                    true /* allowIo */); +            thread.start(); +            mHandler = Handler.createAsync(thread.getLooper(), this); +            SystemLocaleWrapper.onStart(context, this::onActionLocaleChanged, mHandler); +            mImeTrackerService = new ImeTrackerService(serviceThreadForTesting != null +                    ? serviceThreadForTesting.getLooper() : Looper.getMainLooper()); +            // Note: SettingsObserver doesn't register observers in its constructor. +            mSettingsObserver = new SettingsObserver(mHandler); +            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); +            mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); +            mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); +            mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); +            mImePlatformCompatUtils = new ImePlatformCompatUtils(); +            mInputMethodDeviceConfigs = new InputMethodDeviceConfigs(); +            mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); + +            mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime); + +            mShowOngoingImeSwitcherForPhones = false; + +            // InputMethodSettingsRepository should be initialized before buildInputMethodListLocked +            InputMethodSettingsRepository.initialize(mHandler, mContext); +            AdditionalSubtypeMapRepository.initialize(mHandler, mContext); + +            final int userId = mActivityManagerInternal.getCurrentUserId(); + +            mSettings = InputMethodSettingsRepository.get(userId); + +            mSwitchingController = +                    InputMethodSubtypeSwitchingController.createInstanceLocked(context, +                            mSettings.getMethodMap(), userId); +            mHardwareKeyboardShortcutController = +                    new HardwareKeyboardShortcutController(mSettings.getMethodMap(), +                            mSettings.getUserId()); +            mMenuController = new InputMethodMenuController(this); +            mBindingController = +                    bindingControllerForTesting != null +                            ? bindingControllerForTesting +                            : new InputMethodBindingController(this); +            mAutofillController = new AutofillSuggestionsController(this); + +            mVisibilityStateComputer = new ImeVisibilityStateComputer(this); +            mVisibilityApplier = new DefaultImeVisibilityApplier(this); + +            mClientController = new ClientController(mPackageManagerInternal);              mClientController.addClientControllerCallback(c -> onClientRemoved(c));              mImeBindingState = ImeBindingState.newEmptyState(); -        } -        mPreventImeStartupUnlessTextEditor = mRes.getBoolean( -                com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor); -        mNonPreemptibleInputMethods = mRes.getStringArray( -                com.android.internal.R.array.config_nonPreemptibleInputMethods); -        IntConsumer toolTypeConsumer = -                Flags.useHandwritingListenerForTooltype() -                        ? toolType -> onUpdateEditorToolType(toolType) : null; -        Runnable discardDelegationTextRunnable = () -> discardHandwritingDelegationText(); -        mHwController = new HandwritingModeController(mContext, thread.getLooper(), -                new InkWindowInitializer(), toolTypeConsumer, discardDelegationTextRunnable); -        registerDeviceListenerAndCheckStylusSupport(); +            mPreventImeStartupUnlessTextEditor = mRes.getBoolean( +                    com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor); +            mNonPreemptibleInputMethods = mRes.getStringArray( +                    com.android.internal.R.array.config_nonPreemptibleInputMethods); +            IntConsumer toolTypeConsumer = +                    Flags.useHandwritingListenerForTooltype() +                            ? toolType -> onUpdateEditorToolType(toolType) : null; +            Runnable discardDelegationTextRunnable = () -> discardHandwritingDelegationText(); +            mHwController = new HandwritingModeController(mContext, thread.getLooper(), +                    new InkWindowInitializer(), toolTypeConsumer, discardDelegationTextRunnable); +            registerDeviceListenerAndCheckStylusSupport(); +        }      }      @GuardedBy("ImfLock.class") @@ -1536,8 +1542,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub          // and user switch would not happen at that time.          resetCurrentMethodAndClientLocked(UnbindReason.SWITCH_USER); -        mSettings = queryInputMethodServicesInternal(mContext, newUserId, -                AdditionalSubtypeMapRepository.get(newUserId), DirectBootAwareness.AUTO); +        final InputMethodSettings newSettings = queryInputMethodServicesInternal(mContext, +                newUserId, AdditionalSubtypeMapRepository.get(newUserId), DirectBootAwareness.AUTO); +        InputMethodSettingsRepository.put(newUserId, newSettings); +        mSettings = newSettings;          postInputMethodSettingUpdatedLocked(initialUserSwitch /* resetDefaultEnabledIme */);          if (TextUtils.isEmpty(mSettings.getSelectedInputMethod())) {              // This is the first time of the user switch and @@ -1619,9 +1627,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub                  final String defaultImiId = mSettings.getSelectedInputMethod();                  final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId); -                mSettings = queryInputMethodServicesInternal(mContext, currentUserId, -                        AdditionalSubtypeMapRepository.get(mSettings.getUserId()), +                final InputMethodSettings newSettings = queryInputMethodServicesInternal(mContext, +                        currentUserId, AdditionalSubtypeMapRepository.get(currentUserId),                          DirectBootAwareness.AUTO); +                InputMethodSettingsRepository.put(currentUserId, newSettings); +                mSettings = newSettings;                  postInputMethodSettingUpdatedLocked(                          !imeSelectedOnBoot /* resetDefaultEnabledIme */);                  updateFromSettingsLocked(true); @@ -1934,10 +1944,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub      }      @Nullable -    ClientState getClientState(IInputMethodClient client) { -        synchronized (ImfLock.class) { -            return mClientController.getClient(client.asBinder()); -        } +    @GuardedBy("ImfLock.class") +    @Override +    public ClientState getClientStateLocked(IInputMethodClient client) { +        return mClientController.getClient(client.asBinder());      }      // TODO(b/314150112): Move this to ClientController. @@ -2016,7 +2026,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub      }      @GuardedBy("ImfLock.class") -    private boolean isInputShown() { +    @Override +    public boolean isInputShownLocked() {          return mVisibilityStateComputer.isInputShown();      } @@ -3132,11 +3143,16 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub      public void startConnectionlessStylusHandwriting(IInputMethodClient client, int userId,              @Nullable CursorAnchorInfo cursorAnchorInfo, @Nullable String delegatePackageName,              @Nullable String delegatorPackageName, -            @NonNull IConnectionlessHandwritingCallback callback) throws RemoteException { +            @NonNull IConnectionlessHandwritingCallback callback) {          synchronized (ImfLock.class) {              if (!mBindingController.supportsConnectionlessStylusHandwriting()) {                  Slog.w(TAG, "Connectionless stylus handwriting mode unsupported by IME."); -                callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED); +                try { +                    callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED); +                } catch (RemoteException e) { +                    Slog.e(TAG, "Failed to report CONNECTIONLESS_HANDWRITING_ERROR_UNSUPPORTED", e); +                    e.rethrowAsRuntimeException(); +                }                  return;              }          } @@ -3147,7 +3163,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub              synchronized (ImfLock.class) {                  if (!mClientController.verifyClientAndPackageMatch(client, delegatorPackageName)) {                      Slog.w(TAG, "startConnectionlessStylusHandwriting() fail"); -                    callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_OTHER); +                    try { +                        callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_OTHER); +                    } catch (RemoteException e) { +                        Slog.e(TAG, "Failed to report CONNECTIONLESS_HANDWRITING_ERROR_OTHER", e); +                        e.rethrowAsRuntimeException(); +                    }                      throw new IllegalArgumentException("Delegator doesn't match UID");                  }              } @@ -3171,7 +3192,12 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub          if (!startStylusHandwriting(                  client, false, immsCallback, cursorAnchorInfo, isForDelegation)) { -            callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_OTHER); +            try { +                callback.onError(CONNECTIONLESS_HANDWRITING_ERROR_OTHER); +            } catch (RemoteException e) { +                Slog.e(TAG, "Failed to report CONNECTIONLESS_HANDWRITING_ERROR_OTHER", e); +                e.rethrowAsRuntimeException(); +            }          }      } @@ -3271,11 +3297,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub              @UserIdInt int userId,              @NonNull String delegatePackageName,              @NonNull String delegatorPackageName, -            @InputMethodManager.HandwritingDelegateFlags int flags, IBooleanListener callback) -            throws RemoteException { +            @InputMethodManager.HandwritingDelegateFlags int flags, IBooleanListener callback) {          boolean result = acceptStylusHandwritingDelegation(                  client, userId, delegatePackageName, delegatorPackageName, flags); -        callback.onResult(result); +        try { +            callback.onResult(result); +        } catch (RemoteException e) { +            Slog.e(TAG, "Failed to report result=" + result, e); +            e.rethrowAsRuntimeException(); +        }      }      @Override @@ -3366,7 +3396,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub      @GuardedBy("ImfLock.class")      boolean showCurrentInputLocked(IBinder windowToken,              @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, -            int lastClickToolType, @Nullable ResultReceiver resultReceiver, +            @MotionEvent.ToolType int lastClickToolType, @Nullable ResultReceiver resultReceiver,              @SoftInputShowHideReason int reason) {          if (!mVisibilityStateComputer.onImeShowFlags(statsToken, flags)) {              return false; @@ -3412,7 +3442,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub                  "InputMethodManagerService#hideSoftInput");          synchronized (ImfLock.class) {              if (!canInteractWithImeLocked(uid, client, "hideSoftInput", statsToken)) { -                if (isInputShown()) { +                if (isInputShownLocked()) {                      ImeTracker.forLogging().onFailed(                              statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);                  } else { @@ -3435,10 +3465,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub      }      @Override -    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)      public void hideSoftInputFromServerForTest() { -        super.hideSoftInputFromServerForTest_enforcePermission(); -          synchronized (ImfLock.class) {              hideCurrentInputLocked(mImeBindingState.mFocusedWindow, 0 /* flags */,                      SoftInputShowHideReason.HIDE_SOFT_INPUT); @@ -3471,7 +3499,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub          // TODO(b/246309664): Clean up IMMS#mImeWindowVis          IInputMethodInvoker curMethod = getCurMethodLocked();          final boolean shouldHideSoftInput = curMethod != null -                && (isInputShown() || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0); +                && (isInputShownLocked() || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);          mVisibilityStateComputer.requestImeVisibility(windowToken, false);          if (shouldHideSoftInput) { @@ -3844,13 +3872,11 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub          }      } -    @EnforcePermission(Manifest.permission.WRITE_SECURE_SETTINGS) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.WRITE_SECURE_SETTINGS)      @Override      public void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId) {          // Always call subtype picker, because subtype picker is a superset of input method          // picker. -        super.showInputMethodPickerFromSystem_enforcePermission(); -          mHandler.obtainMessage(MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId)                  .sendToTarget();      } @@ -3858,10 +3884,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub      /**       * A test API for CTS to make sure that the input method menu is showing.       */ -    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)      public boolean isInputMethodPickerShownForTest() { -        super.isInputMethodPickerShownForTest_enforcePermission(); -          synchronized (ImfLock.class) {              return mMenuController.isisInputMethodPickerShownForTestLocked();          } @@ -4069,22 +4093,20 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub              final var additionalSubtypeMap = AdditionalSubtypeMapRepository.get(userId);              final boolean isCurrentUser = (mSettings.getUserId() == userId); -            final InputMethodSettings settings = isCurrentUser -                    ? mSettings -                    : queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, -                            DirectBootAwareness.AUTO); +            final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);              final var newAdditionalSubtypeMap = settings.getNewAdditionalSubtypeMap(                      imiId, toBeAdded, additionalSubtypeMap, mPackageManagerInternal, callingUid);              if (additionalSubtypeMap != newAdditionalSubtypeMap) {                  AdditionalSubtypeMapRepository.putAndSave(userId, newAdditionalSubtypeMap,                          settings.getMethodMap()); +                final InputMethodSettings newSettings = queryInputMethodServicesInternal(mContext, +                        userId, AdditionalSubtypeMapRepository.get(userId), +                        DirectBootAwareness.AUTO); +                InputMethodSettingsRepository.put(userId, newSettings);                  if (isCurrentUser) {                      final long ident = Binder.clearCallingIdentity();                      try { -                        mSettings = queryInputMethodServicesInternal(mContext, -                                mSettings.getUserId(), -                                AdditionalSubtypeMapRepository.get(mSettings.getUserId()), -                                DirectBootAwareness.AUTO); +                        mSettings = newSettings;                          postInputMethodSettingUpdatedLocked(false /* resetDefaultEnabledIme */);                      } finally {                          Binder.restoreCallingIdentity(ident); @@ -4161,11 +4183,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub          });      } -    @EnforcePermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.INTERNAL_SYSTEM_WINDOW)      @Override      public void removeImeSurface() { -        super.removeImeSurface_enforcePermission(); -          mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE).sendToTarget();      } @@ -4274,11 +4294,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub       * a stylus deviceId is not already registered on device.       */      @BinderThread -    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)      @Override      public void addVirtualStylusIdForTestSession(IInputMethodClient client) { -        super.addVirtualStylusIdForTestSession_enforcePermission(); -          int uid = Binder.getCallingUid();          synchronized (ImfLock.class) {              if (!canInteractWithImeLocked(uid, client, "addVirtualStylusIdForTestSession", @@ -4301,12 +4319,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub       * @param timeout to set in milliseconds. To reset to default, use a value <= zero.       */      @BinderThread -    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)      @Override      public void setStylusWindowIdleTimeoutForTest(              IInputMethodClient client, @DurationMillisLong long timeout) { -        super.setStylusWindowIdleTimeoutForTest_enforcePermission(); -          int uid = Binder.getCallingUid();          synchronized (ImfLock.class) {              if (!canInteractWithImeLocked(uid, client, "setStylusWindowIdleTimeoutForTest", @@ -4402,10 +4418,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub      }      @BinderThread -    @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.CONTROL_UI_TRACING)      @Override      public void startImeTrace() { -        super.startImeTrace_enforcePermission();          ImeTracing.getInstance().startTrace(null /* printwriter */);          synchronized (ImfLock.class) {              mClientController.forAllClients(c -> c.mClient.setImeTraceEnabled(true /* enabled */)); @@ -4413,11 +4428,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub      }      @BinderThread -    @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.CONTROL_UI_TRACING)      @Override      public void stopImeTrace() { -        super.stopImeTrace_enforcePermission(); -          ImeTracing.getInstance().stopTrace(null /* printwriter */);          synchronized (ImfLock.class) {              mClientController.forAllClients(c -> c.mClient.setImeTraceEnabled(false /* enabled */)); @@ -4697,7 +4710,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub                          // implemented so that auxiliary subtypes will be excluded when the soft                          // keyboard is invisible.                          synchronized (ImfLock.class) { -                            showAuxSubtypes = isInputShown(); +                            showAuxSubtypes = isInputShownLocked();                          }                          break;                      case InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES: @@ -5844,7 +5857,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub      @BinderThread      @Override -    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { +    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {          if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;          PriorityDump.dump(mPriorityDumper, fd, pw, args); @@ -5974,7 +5987,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub      public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,              @Nullable FileDescriptor err,              @NonNull String[] args, @Nullable ShellCallback callback, -            @NonNull ResultReceiver resultReceiver) throws RemoteException { +            @NonNull ResultReceiver resultReceiver, @NonNull Binder self) {          final int callingUid = Binder.getCallingUid();          // Reject any incoming calls from non-shell users, including ones from the system user.          if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) { @@ -5995,7 +6008,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub              throw new SecurityException(errorMsg);          }          new ShellCommandImpl(this).exec( -                this, in, out, err, args, callback, resultReceiver); +                self, in, out, err, args, callback, resultReceiver);      }      private static final class ShellCommandImpl extends ShellCommand { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java b/services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java new file mode 100644 index 000000000000..60b9a4cfe840 --- /dev/null +++ b/services/core/java/com/android/server/inputmethod/InputMethodSettingsRepository.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.inputmethod; + +import android.annotation.NonNull; +import android.annotation.UserIdInt; +import android.content.Context; +import android.content.pm.UserInfo; +import android.os.Handler; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.inputmethod.DirectBootAwareness; +import com.android.server.LocalServices; +import com.android.server.pm.UserManagerInternal; + +final class InputMethodSettingsRepository { +    @GuardedBy("ImfLock.class") +    @NonNull +    private static final SparseArray<InputMethodSettings> sPerUserMap = new SparseArray<>(); + +    /** +     * Not intended to be instantiated. +     */ +    private InputMethodSettingsRepository() { +    } + +    @NonNull +    @GuardedBy("ImfLock.class") +    static InputMethodSettings get(@UserIdInt int userId) { +        final InputMethodSettings obj = sPerUserMap.get(userId); +        if (obj != null) { +            return obj; +        } +        return InputMethodSettings.createEmptyMap(userId); +    } + +    @GuardedBy("ImfLock.class") +    static void put(@UserIdInt int userId, @NonNull InputMethodSettings obj) { +        sPerUserMap.put(userId, obj); +    } + +    static void initialize(@NonNull Handler handler, @NonNull Context context) { +        final UserManagerInternal userManagerInternal = +                LocalServices.getService(UserManagerInternal.class); +        handler.post(() -> { +            userManagerInternal.addUserLifecycleListener( +                    new UserManagerInternal.UserLifecycleListener() { +                        @Override +                        public void onUserRemoved(UserInfo user) { +                            final int userId = user.id; +                            handler.post(() -> { +                                synchronized (ImfLock.class) { +                                    sPerUserMap.remove(userId); +                                } +                            }); +                        } +                    }); +            synchronized (ImfLock.class) { +                for (int userId : userManagerInternal.getUserIds()) { +                    final InputMethodSettings settings = +                            InputMethodManagerService.queryInputMethodServicesInternal( +                                    context, +                                    userId, +                                    AdditionalSubtypeMapRepository.get(userId), +                                    DirectBootAwareness.AUTO); +                    sPerUserMap.put(userId, settings); +                } +            } +        }); +    } +} diff --git a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java index ffc2319b60af..1cd1ddce78fd 100644 --- a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java +++ b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java @@ -36,17 +36,16 @@ import static com.android.server.inputmethod.InputMethodManagerService.TAG;  import android.Manifest;  import android.annotation.BinderThread; -import android.annotation.EnforcePermission;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.RequiresPermission;  import android.annotation.UserIdInt;  import android.os.Binder;  import android.os.IBinder; -import android.os.RemoteException;  import android.os.ResultReceiver;  import android.os.ShellCallback;  import android.util.Slog; +import android.view.MotionEvent;  import android.view.WindowManager;  import android.view.inputmethod.CursorAnchorInfo;  import android.view.inputmethod.EditorInfo; @@ -56,6 +55,7 @@ import android.view.inputmethod.InputMethodManager;  import android.view.inputmethod.InputMethodSubtype;  import android.window.ImeOnBackInvokedDispatcher; +import com.android.internal.annotations.GuardedBy;  import com.android.internal.inputmethod.DirectBootAwareness;  import com.android.internal.inputmethod.IBooleanListener;  import com.android.internal.inputmethod.IConnectionlessHandwritingCallback; @@ -76,22 +76,25 @@ import java.util.List;  import java.util.concurrent.CompletableFuture;  import java.util.concurrent.ExecutionException;  import java.util.concurrent.Executor; -import java.util.function.BooleanSupplier;  /**   * A proxy that processes all {@link IInputMethodManager} calls asynchronously. - * @hide   */ -public class ZeroJankProxy extends IInputMethodManager.Stub { +final class ZeroJankProxy implements IInputMethodManagerImpl.Callback { -    private final IInputMethodManager mInner; +    interface Callback extends IInputMethodManagerImpl.Callback { +        @GuardedBy("ImfLock.class") +        ClientState getClientStateLocked(IInputMethodClient client); +        @GuardedBy("ImfLock.class") +        boolean isInputShownLocked(); +    } + +    private final Callback mInner;      private final Executor mExecutor; -    private final BooleanSupplier mIsInputShown; -    ZeroJankProxy(Executor executor, IInputMethodManager inner, BooleanSupplier isInputShown) { +    ZeroJankProxy(Executor executor, Callback inner) {          mInner = inner;          mExecutor = executor; -        mIsInputShown = isInputShown;      }      private void offload(ThrowingRunnable r) { @@ -126,45 +129,43 @@ public class ZeroJankProxy extends IInputMethodManager.Stub {      @Override      public void addClient(IInputMethodClient client, IRemoteInputConnection inputConnection, -            int selfReportedDisplayId) throws RemoteException { +            int selfReportedDisplayId) {          offload(() -> mInner.addClient(client, inputConnection, selfReportedDisplayId));      }      @Override -    public InputMethodInfo getCurrentInputMethodInfoAsUser(int userId) throws RemoteException { +    public InputMethodInfo getCurrentInputMethodInfoAsUser(int userId) {          return mInner.getCurrentInputMethodInfoAsUser(userId);      }      @Override      public List<InputMethodInfo> getInputMethodList( -            int userId, @DirectBootAwareness int directBootAwareness) throws RemoteException { +            int userId, @DirectBootAwareness int directBootAwareness) {          return mInner.getInputMethodList(userId, directBootAwareness);      }      @Override -    public List<InputMethodInfo> getEnabledInputMethodList(int userId) throws RemoteException { +    public List<InputMethodInfo> getEnabledInputMethodList(int userId) {          return mInner.getEnabledInputMethodList(userId);      }      @Override      public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId, -            boolean allowsImplicitlyEnabledSubtypes, int userId) -            throws RemoteException { +            boolean allowsImplicitlyEnabledSubtypes, int userId) {          return mInner.getEnabledInputMethodSubtypeList(imiId, allowsImplicitlyEnabledSubtypes,                  userId);      }      @Override -    public InputMethodSubtype getLastInputMethodSubtype(int userId) throws RemoteException { +    public InputMethodSubtype getLastInputMethodSubtype(int userId) {          return mInner.getLastInputMethodSubtype(userId);      }      @Override      public boolean showSoftInput(IInputMethodClient client, IBinder windowToken,              @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags, -            int lastClickTooType, ResultReceiver resultReceiver, -            @SoftInputShowHideReason int reason) -            throws RemoteException { +            @MotionEvent.ToolType int lastClickToolType, ResultReceiver resultReceiver, +            @SoftInputShowHideReason int reason) {          offload(                  () -> {                      if (!mInner.showSoftInput( @@ -172,7 +173,7 @@ public class ZeroJankProxy extends IInputMethodManager.Stub {                              windowToken,                              statsToken,                              flags, -                            lastClickTooType, +                            lastClickToolType,                              resultReceiver,                              reason)) {                          sendResultReceiverFailure(resultReceiver); @@ -184,8 +185,7 @@ public class ZeroJankProxy extends IInputMethodManager.Stub {      @Override      public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,              @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags, -            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) -            throws RemoteException { +            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {          offload(                  () -> {                      if (!mInner.hideSoftInput( @@ -200,17 +200,19 @@ public class ZeroJankProxy extends IInputMethodManager.Stub {          if (resultReceiver == null) {              return;          } -        resultReceiver.send( -                mIsInputShown.getAsBoolean() +        final boolean isInputShown; +        synchronized (ImfLock.class) { +            isInputShown = mInner.isInputShownLocked(); +        } +        resultReceiver.send(isInputShown                          ? InputMethodManager.RESULT_UNCHANGED_SHOWN                          : InputMethodManager.RESULT_UNCHANGED_HIDDEN,                  null);      }      @Override -    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) -    public void hideSoftInputFromServerForTest() throws RemoteException { -        super.hideSoftInputFromServerForTest_enforcePermission(); +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD) +    public void hideSoftInputFromServerForTest() {          mInner.hideSoftInputFromServerForTest();      } @@ -225,8 +227,7 @@ public class ZeroJankProxy extends IInputMethodManager.Stub {              IRemoteInputConnection inputConnection,              IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,              int unverifiedTargetSdkVersion, @UserIdInt int userId, -            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq) -            throws RemoteException { +            @NonNull ImeOnBackInvokedDispatcher imeDispatcher, int startInputSeq) {          offload(() -> {              InputBindResult result = mInner.startInputOrWindowGainedFocus(startInputReason, client,                      windowToken, startInputFlags, softInputMode, windowFlags, @@ -249,99 +250,92 @@ public class ZeroJankProxy extends IInputMethodManager.Stub {              IRemoteInputConnection inputConnection,              IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection,              int unverifiedTargetSdkVersion, @UserIdInt int userId, -            @NonNull ImeOnBackInvokedDispatcher imeDispatcher) -            throws RemoteException { +            @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {          // Should never be called when flag is enabled i.e. when this proxy is used.          return null;      }      @Override      public void showInputMethodPickerFromClient(IInputMethodClient client, -            int auxiliarySubtypeMode) -            throws RemoteException { +            int auxiliarySubtypeMode) {          offload(() -> mInner.showInputMethodPickerFromClient(client, auxiliarySubtypeMode));      } -    @EnforcePermission(Manifest.permission.WRITE_SECURE_SETTINGS) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.WRITE_SECURE_SETTINGS)      @Override -    public void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId) -            throws RemoteException { +    public void showInputMethodPickerFromSystem(int auxiliarySubtypeMode, int displayId) {          mInner.showInputMethodPickerFromSystem(auxiliarySubtypeMode, displayId);      } -    @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)      @Override -    public boolean isInputMethodPickerShownForTest() throws RemoteException { -        super.isInputMethodPickerShownForTest_enforcePermission(); +    public boolean isInputMethodPickerShownForTest() {          return mInner.isInputMethodPickerShownForTest();      }      @Override -    public InputMethodSubtype getCurrentInputMethodSubtype(int userId) throws RemoteException { +    public InputMethodSubtype getCurrentInputMethodSubtype(int userId) {          return mInner.getCurrentInputMethodSubtype(userId);      }      @Override      public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes, -            @UserIdInt int userId) throws RemoteException { +            @UserIdInt int userId) {          mInner.setAdditionalInputMethodSubtypes(imiId, subtypes, userId);      }      @Override      public void setExplicitlyEnabledInputMethodSubtypes(String imeId, -            @NonNull int[] subtypeHashCodes, @UserIdInt int userId) throws RemoteException { +            @NonNull int[] subtypeHashCodes, @UserIdInt int userId) {          mInner.setExplicitlyEnabledInputMethodSubtypes(imeId, subtypeHashCodes, userId);      }      @Override -    public int getInputMethodWindowVisibleHeight(IInputMethodClient client) -            throws RemoteException { +    public int getInputMethodWindowVisibleHeight(IInputMethodClient client) {          return mInner.getInputMethodWindowVisibleHeight(client);      }      @Override -    public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) -            throws RemoteException { +    public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) {          // Already async TODO(b/293640003): ordering issues?          mInner.reportPerceptibleAsync(windowToken, perceptible);      } -    @EnforcePermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.INTERNAL_SYSTEM_WINDOW)      @Override -    public void removeImeSurface() throws RemoteException { +    public void removeImeSurface() {          mInner.removeImeSurface();      }      @Override -    public void removeImeSurfaceFromWindowAsync(IBinder windowToken) throws RemoteException { +    public void removeImeSurfaceFromWindowAsync(IBinder windowToken) {          mInner.removeImeSurfaceFromWindowAsync(windowToken);      }      @Override -    public void startProtoDump(byte[] bytes, int i, String s) throws RemoteException { +    public void startProtoDump(byte[] bytes, int i, String s) {          mInner.startProtoDump(bytes, i, s);      }      @Override -    public boolean isImeTraceEnabled() throws RemoteException { +    public boolean isImeTraceEnabled() {          return mInner.isImeTraceEnabled();      } -    @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.CONTROL_UI_TRACING)      @Override -    public void startImeTrace() throws RemoteException { +    public void startImeTrace() {          mInner.startImeTrace();      } -    @EnforcePermission(Manifest.permission.CONTROL_UI_TRACING) +    @IInputMethodManagerImpl.PermissionVerified(Manifest.permission.CONTROL_UI_TRACING)      @Override -    public void stopImeTrace() throws RemoteException { +    public void stopImeTrace() {          mInner.stopImeTrace();      }      @Override -    public void startStylusHandwriting(IInputMethodClient client) -            throws RemoteException { +    public void startStylusHandwriting(IInputMethodClient client) {          offload(() -> mInner.startStylusHandwriting(client));      } @@ -349,7 +343,7 @@ public class ZeroJankProxy extends IInputMethodManager.Stub {      public void startConnectionlessStylusHandwriting(IInputMethodClient client, int userId,              @Nullable CursorAnchorInfo cursorAnchorInfo, @Nullable String delegatePackageName,              @Nullable String delegatorPackageName, -            @NonNull IConnectionlessHandwritingCallback callback) throws RemoteException { +            @NonNull IConnectionlessHandwritingCallback callback) {          offload(() -> mInner.startConnectionlessStylusHandwriting(                  client, userId, cursorAnchorInfo, delegatePackageName, delegatorPackageName,                  callback)); @@ -363,14 +357,11 @@ public class ZeroJankProxy extends IInputMethodManager.Stub {              @NonNull String delegatorPackageName,              @InputMethodManager.HandwritingDelegateFlags int flags) {          try { -            return CompletableFuture.supplyAsync(() -> { -                try { -                    return mInner.acceptStylusHandwritingDelegation( -                            client, userId, delegatePackageName, delegatorPackageName, flags); -                } catch (RemoteException e) { -                    throw new RuntimeException(e); -                } -            }, this::offload).get(); +            return CompletableFuture.supplyAsync(() -> +                            mInner.acceptStylusHandwritingDelegation( +                                    client, userId, delegatePackageName, delegatorPackageName, +                                    flags), +                    this::offload).get();          } catch (InterruptedException e) {              throw new RuntimeException(e);          } catch (ExecutionException e) { @@ -384,8 +375,7 @@ public class ZeroJankProxy extends IInputMethodManager.Stub {              @UserIdInt int userId,              @NonNull String delegatePackageName,              @NonNull String delegatorPackageName, -            @InputMethodManager.HandwritingDelegateFlags int flags, IBooleanListener callback) -            throws RemoteException { +            @InputMethodManager.HandwritingDelegateFlags int flags, IBooleanListener callback) {          offload(() -> mInner.acceptStylusHandwritingDelegationAsync(                  client, userId, delegatePackageName, delegatorPackageName, flags, callback));      } @@ -401,52 +391,45 @@ public class ZeroJankProxy extends IInputMethodManager.Stub {      }      @Override -    public boolean isStylusHandwritingAvailableAsUser(int userId, boolean connectionless) -            throws RemoteException { +    public boolean isStylusHandwritingAvailableAsUser(int userId, boolean connectionless) {          return mInner.isStylusHandwritingAvailableAsUser(userId, connectionless);      } -    @EnforcePermission("android.permission.TEST_INPUT_METHOD") +    @IInputMethodManagerImpl.PermissionVerified("android.permission.TEST_INPUT_METHOD")      @Override -    public void addVirtualStylusIdForTestSession(IInputMethodClient client) -            throws RemoteException { +    public void addVirtualStylusIdForTestSession(IInputMethodClient client) {          mInner.addVirtualStylusIdForTestSession(client);      } -    @EnforcePermission("android.permission.TEST_INPUT_METHOD") +    @IInputMethodManagerImpl.PermissionVerified("android.permission.TEST_INPUT_METHOD")      @Override -    public void setStylusWindowIdleTimeoutForTest(IInputMethodClient client, long timeout) -            throws RemoteException { +    public void setStylusWindowIdleTimeoutForTest(IInputMethodClient client, long timeout) {          mInner.setStylusWindowIdleTimeoutForTest(client, timeout);      }      @Override -    public IImeTracker getImeTrackerService() throws RemoteException { +    public IImeTracker getImeTrackerService() {          return mInner.getImeTrackerService();      }      @BinderThread      @Override      public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, -            @Nullable FileDescriptor err, -            @NonNull String[] args, @Nullable ShellCallback callback, -            @NonNull ResultReceiver resultReceiver) throws RemoteException { -        ((InputMethodManagerService) mInner).onShellCommand( -                in, out, err, args, callback, resultReceiver); +            @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback callback, +            @NonNull ResultReceiver resultReceiver, @NonNull Binder self) { +        mInner.onShellCommand(in, out, err, args, callback, resultReceiver, self);      }      @Override -    protected void dump(@NonNull FileDescriptor fd, -            @NonNull PrintWriter fout, +    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,              @Nullable String[] args) { -        ((InputMethodManagerService) mInner).dump(fd, fout, args); +        mInner.dump(fd, fout, args);      }      private void sendOnStartInputResult(              IInputMethodClient client, InputBindResult res, int startInputSeq) {          synchronized (ImfLock.class) { -            InputMethodManagerService service = (InputMethodManagerService) mInner; -            final ClientState cs = service.getClientState(client); +            final ClientState cs = mInner.getClientStateLocked(client);              if (cs != null && cs.mClient != null) {                  cs.mClient.onStartInputResult(res, startInputSeq);              } else { diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 19562ef79fbb..dbdb155eb2e3 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -950,13 +950,18 @@ public class LockSettingsService extends ILockSettings.Stub {                              && android.multiuser.Flags.enablePrivateSpaceFeatures()                              && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {                          mHandler.post(() -> { -                            UserProperties userProperties = -                                    mUserManager.getUserProperties(UserHandle.of(userId)); -                            if (userProperties != null -                                    && userProperties.getAllowStoppingUserWithDelayedLocking()) { -                                int strongAuthRequired = LockPatternUtils.StrongAuthTracker -                                        .getDefaultFlags(mContext); -                                requireStrongAuth(strongAuthRequired, userId); +                            try { +                                UserProperties userProperties = +                                        mUserManager.getUserProperties(UserHandle.of(userId)); +                                if (userProperties != null && userProperties +                                        .getAllowStoppingUserWithDelayedLocking()) { +                                    int strongAuthRequired = LockPatternUtils.StrongAuthTracker +                                            .getDefaultFlags(mContext); +                                    requireStrongAuth(strongAuthRequired, userId); +                                } +                            } catch (IllegalArgumentException e) { +                                Slogf.d(TAG, "User %d does not exist or has been removed", +                                        userId);                              }                          });                      } diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 1a129cb080a8..064443ce7d10 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -267,9 +267,11 @@ public final class MediaRouterService extends IMediaRouterService.Stub      // Binder call      @Override      public boolean showMediaOutputSwitcher(String packageName) { -        if (!validatePackageName(Binder.getCallingUid(), packageName)) { +        int uid = Binder.getCallingUid(); +        if (!validatePackageName(uid, packageName)) {              throw new SecurityException("packageName must match the calling identity");          } +        UserHandle userHandle = UserHandle.getUserHandleForUid(uid);          final long token = Binder.clearCallingIdentity();          try {              if (mContext.getSystemService(ActivityManager.class).getPackageImportance(packageName) @@ -280,7 +282,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub              synchronized (mLock) {                  StatusBarManagerInternal statusBar =                          LocalServices.getService(StatusBarManagerInternal.class); -                statusBar.showMediaOutputSwitcher(packageName); +                statusBar.showMediaOutputSwitcher(packageName, userHandle);              }          } finally {              Binder.restoreCallingIdentity(token); diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java index 0cd7654f70ea..dfb2b0a750e3 100644 --- a/services/core/java/com/android/server/media/MediaSession2Record.java +++ b/services/core/java/com/android/server/media/MediaSession2Record.java @@ -157,6 +157,11 @@ public class MediaSession2Record extends MediaSessionRecordImpl {      }      @Override +    public void expireTempEngaged() { +        // NA as MediaSession2 doesn't support UserEngagementStates for FGS. +    } + +    @Override      public boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,              KeyEvent ke, int sequenceId, ResultReceiver cb) {          // TODO(jaewan): Implement. diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 62a947123ddf..3d6855547bcd 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -24,6 +24,7 @@ import static android.media.session.MediaController.PlaybackInfo.PLAYBACK_TYPE_L  import static android.media.session.MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE;  import android.Manifest; +import android.annotation.IntDef;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.RequiresPermission; @@ -85,6 +86,8 @@ import com.android.server.LocalServices;  import com.android.server.uri.UriGrantsManagerInternal;  import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy;  import java.util.ArrayList;  import java.util.Arrays;  import java.util.Collection; @@ -225,6 +228,49 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde      private int mPolicies; +    private @UserEngagementState int mUserEngagementState = USER_DISENGAGED; + +    @IntDef({USER_PERMANENTLY_ENGAGED, USER_TEMPORARY_ENGAGED, USER_DISENGAGED}) +    @Retention(RetentionPolicy.SOURCE) +    private @interface UserEngagementState {} + +    /** +     * Indicates that the session is active and in one of the user engaged states. +     * +     * @see #updateUserEngagedStateIfNeededLocked(boolean) () +     */ +    private static final int USER_PERMANENTLY_ENGAGED = 0; + +    /** +     * Indicates that the session is active and in {@link PlaybackState#STATE_PAUSED} state. +     * +     * @see #updateUserEngagedStateIfNeededLocked(boolean) () +     */ +    private static final int USER_TEMPORARY_ENGAGED = 1; + +    /** +     * Indicates that the session is either not active or in one of the user disengaged states +     * +     * @see #updateUserEngagedStateIfNeededLocked(boolean) () +     */ +    private static final int USER_DISENGAGED = 2; + +    /** +     * Indicates the duration of the temporary engaged states. +     * +     * <p>Some {@link MediaSession} states like {@link PlaybackState#STATE_PAUSED} are temporarily +     * engaged, meaning the corresponding session is only considered in an engaged state for the +     * duration of this timeout, and only if coming from an engaged state. +     * +     * <p>For example, if a session is transitioning from a user-engaged state {@link +     * PlaybackState#STATE_PLAYING} to a temporary user-engaged state {@link +     * PlaybackState#STATE_PAUSED}, then the session will be considered in a user-engaged state for +     * the duration of this timeout, starting at the transition instant. However, a temporary +     * user-engaged state is not considered user-engaged when transitioning from a non-user engaged +     * state {@link PlaybackState#STATE_STOPPED}. +     */ +    private static final int TEMP_USER_ENGAGED_TIMEOUT = 600000; +      public MediaSessionRecord(              int ownerPid,              int ownerUid, @@ -548,6 +594,7 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde              mSessionCb.mCb.asBinder().unlinkToDeath(this, 0);              mDestroyed = true;              mPlaybackState = null; +            updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true);              mHandler.post(MessageHandler.MSG_DESTROYED);          }      } @@ -559,6 +606,12 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde          }      } +    @Override +    public void expireTempEngaged() { +        mHandler.removeCallbacks(mHandleTempEngagedSessionTimeout); +        updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true); +    } +      /**       * Sends media button.       * @@ -1129,6 +1182,11 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde                  }              }; +    private final Runnable mHandleTempEngagedSessionTimeout = +            () -> { +                updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true); +            }; +      @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)      private static boolean componentNameExists(              @NonNull ComponentName componentName, @NonNull Context context, int userId) { @@ -1145,6 +1203,40 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde          return !resolveInfos.isEmpty();      } +    private void updateUserEngagedStateIfNeededLocked(boolean isTimeoutExpired) { +        int oldUserEngagedState = mUserEngagementState; +        int newUserEngagedState; +        if (!isActive() || mPlaybackState == null) { +            newUserEngagedState = USER_DISENGAGED; +        } else if (isActive() && mPlaybackState.isActive()) { +            newUserEngagedState = USER_PERMANENTLY_ENGAGED; +        } else if (mPlaybackState.getState() == PlaybackState.STATE_PAUSED) { +            newUserEngagedState = +                    oldUserEngagedState == USER_PERMANENTLY_ENGAGED || !isTimeoutExpired +                            ? USER_TEMPORARY_ENGAGED +                            : USER_DISENGAGED; +        } else { +            newUserEngagedState = USER_DISENGAGED; +        } +        if (oldUserEngagedState == newUserEngagedState) { +            return; +        } + +        if (newUserEngagedState == USER_TEMPORARY_ENGAGED) { +            mHandler.postDelayed(mHandleTempEngagedSessionTimeout, TEMP_USER_ENGAGED_TIMEOUT); +        } else if (oldUserEngagedState == USER_TEMPORARY_ENGAGED) { +            mHandler.removeCallbacks(mHandleTempEngagedSessionTimeout); +        } + +        boolean wasUserEngaged = oldUserEngagedState != USER_DISENGAGED; +        boolean isNowUserEngaged = newUserEngagedState != USER_DISENGAGED; +        mUserEngagementState = newUserEngagedState; +        if (wasUserEngaged != isNowUserEngaged) { +            mService.onSessionUserEngagementStateChange( +                    /* mediaSessionRecord= */ this, /* isUserEngaged= */ isNowUserEngaged); +        } +    } +      private final class SessionStub extends ISession.Stub {          @Override          public void destroySession() throws RemoteException { @@ -1182,8 +1274,10 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde                          .logFgsApiEnd(ActivityManager.FOREGROUND_SERVICE_API_TYPE_MEDIA_PLAYBACK,                                  callingUid, callingPid);              } - -            mIsActive = active; +            synchronized (mLock) { +                mIsActive = active; +                updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ false); +            }              long token = Binder.clearCallingIdentity();              try {                  mService.onSessionActiveStateChanged(MediaSessionRecord.this, mPlaybackState); @@ -1341,6 +1435,7 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde                      && TRANSITION_PRIORITY_STATES.contains(newState));              synchronized (mLock) {                  mPlaybackState = state; +                updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ false);              }              final long token = Binder.clearCallingIdentity();              try { @@ -1362,12 +1457,14 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde          @Override          public IBinder getBinderForSetQueue() throws RemoteException { -            return new ParcelableListBinder<QueueItem>((list) -> { -                synchronized (mLock) { -                    mQueue = list; -                } -                mHandler.post(MessageHandler.MSG_UPDATE_QUEUE); -            }); +            return new ParcelableListBinder<QueueItem>( +                    QueueItem.class, +                    (list) -> { +                        synchronized (mLock) { +                            mQueue = list; +                        } +                        mHandler.post(MessageHandler.MSG_UPDATE_QUEUE); +                    });          }          @Override diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java index 09991995099e..b57b14835987 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java +++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java @@ -196,6 +196,12 @@ public abstract class MediaSessionRecordImpl {       */      public abstract boolean isClosed(); +    /** +     * Note: This method is only used for testing purposes If the session is temporary engaged, the +     * timeout will expire and it will become disengaged. +     */ +    public abstract void expireTempEngaged(); +      @Override      public final boolean equals(Object o) {          if (this == o) return true; diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 53c32cf31d21..74adf5e0d52c 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -367,11 +367,13 @@ public class MediaSessionService extends SystemService implements Monitor {              }              boolean isUserEngaged = isUserEngaged(record, playbackState); -            Log.d(TAG, "onSessionActiveStateChanged: " -                    + "record=" + record -                    + "playbackState=" + playbackState -                    + "allowRunningInForeground=" + isUserEngaged); -            setForegroundServiceAllowance(record, /* allowRunningInForeground= */ isUserEngaged); +            Log.d( +                    TAG, +                    "onSessionActiveStateChanged:" +                            + " record=" +                            + record +                            + " playbackState=" +                            + playbackState);              reportMediaInteractionEvent(record, isUserEngaged);              mHandler.postSessionsChanged(record);          } @@ -479,11 +481,13 @@ public class MediaSessionService extends SystemService implements Monitor {              }              user.mPriorityStack.onPlaybackStateChanged(record, shouldUpdatePriority);              boolean isUserEngaged = isUserEngaged(record, playbackState); -            Log.d(TAG, "onSessionPlaybackStateChanged: " -                    + "record=" + record -                    + "playbackState=" + playbackState -                    + "allowRunningInForeground=" + isUserEngaged); -            setForegroundServiceAllowance(record, /* allowRunningInForeground= */ isUserEngaged); +            Log.d( +                    TAG, +                    "onSessionPlaybackStateChanged:" +                            + " record=" +                            + record +                            + " playbackState=" +                            + playbackState);              reportMediaInteractionEvent(record, isUserEngaged);          }      } @@ -650,68 +654,112 @@ public class MediaSessionService extends SystemService implements Monitor {          session.close();          Log.d(TAG, "destroySessionLocked: record=" + session); -        setForegroundServiceAllowance(session, /* allowRunningInForeground= */ false); +          reportMediaInteractionEvent(session, /* userEngaged= */ false);          mHandler.postSessionsChanged(session);      } -    private void setForegroundServiceAllowance( -            MediaSessionRecordImpl record, boolean allowRunningInForeground) { -        if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) { -            return; -        } -        ForegroundServiceDelegationOptions foregroundServiceDelegationOptions = -                record.getForegroundServiceDelegationOptions(); -        if (foregroundServiceDelegationOptions == null) { -            return; -        } -        if (allowRunningInForeground) { -            onUserSessionEngaged(record); +    void onSessionUserEngagementStateChange( +            MediaSessionRecordImpl mediaSessionRecord, boolean isUserEngaged) { +        if (isUserEngaged) { +            addUserEngagedSession(mediaSessionRecord); +            startFgsIfSessionIsLinkedToNotification(mediaSessionRecord);          } else { -            onUserDisengaged(record); +            removeUserEngagedSession(mediaSessionRecord); +            stopFgsIfNoSessionIsLinkedToNotification(mediaSessionRecord);          }      } -    private void onUserSessionEngaged(MediaSessionRecordImpl mediaSessionRecord) { +    private void addUserEngagedSession(MediaSessionRecordImpl mediaSessionRecord) {          synchronized (mLock) {              int uid = mediaSessionRecord.getUid();              mUserEngagedSessionsForFgs.putIfAbsent(uid, new HashSet<>());              mUserEngagedSessionsForFgs.get(uid).add(mediaSessionRecord); +        } +    } + +    private void removeUserEngagedSession(MediaSessionRecordImpl mediaSessionRecord) { +        synchronized (mLock) { +            int uid = mediaSessionRecord.getUid(); +            Set<MediaSessionRecordImpl> mUidUserEngagedSessionsForFgs = +                    mUserEngagedSessionsForFgs.get(uid); +            if (mUidUserEngagedSessionsForFgs == null) { +                return; +            } + +            mUidUserEngagedSessionsForFgs.remove(mediaSessionRecord); +            if (mUidUserEngagedSessionsForFgs.isEmpty()) { +                mUserEngagedSessionsForFgs.remove(uid); +            } +        } +    } + +    private void startFgsIfSessionIsLinkedToNotification( +            MediaSessionRecordImpl mediaSessionRecord) { +        Log.d(TAG, "startFgsIfSessionIsLinkedToNotification: record=" + mediaSessionRecord); +        if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) { +            return; +        } +        synchronized (mLock) { +            int uid = mediaSessionRecord.getUid();              for (Notification mediaNotification : mMediaNotifications.getOrDefault(uid, Set.of())) {                  if (mediaSessionRecord.isLinkedToNotification(mediaNotification)) { -                    mActivityManagerInternal.startForegroundServiceDelegate( -                            mediaSessionRecord.getForegroundServiceDelegationOptions(), -                            /* connection= */ null); +                    startFgsDelegate(mediaSessionRecord.getForegroundServiceDelegationOptions());                      return;                  }              }          }      } -    private void onUserDisengaged(MediaSessionRecordImpl mediaSessionRecord) { +    private void startFgsDelegate( +            ForegroundServiceDelegationOptions foregroundServiceDelegationOptions) { +        final long token = Binder.clearCallingIdentity(); +        try { +            mActivityManagerInternal.startForegroundServiceDelegate( +                    foregroundServiceDelegationOptions, /* connection= */ null); +        } finally { +            Binder.restoreCallingIdentity(token); +        } +    } + +    private void stopFgsIfNoSessionIsLinkedToNotification( +            MediaSessionRecordImpl mediaSessionRecord) { +        Log.d(TAG, "stopFgsIfNoSessionIsLinkedToNotification: record=" + mediaSessionRecord); +        if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) { +            return; +        }          synchronized (mLock) {              int uid = mediaSessionRecord.getUid(); -            if (mUserEngagedSessionsForFgs.containsKey(uid)) { -                mUserEngagedSessionsForFgs.get(uid).remove(mediaSessionRecord); -                if (mUserEngagedSessionsForFgs.get(uid).isEmpty()) { -                    mUserEngagedSessionsForFgs.remove(uid); -                } +            ForegroundServiceDelegationOptions foregroundServiceDelegationOptions = +                    mediaSessionRecord.getForegroundServiceDelegationOptions(); +            if (foregroundServiceDelegationOptions == null) { +                return;              } -            boolean shouldStopFgs = true; -            for (MediaSessionRecordImpl sessionRecord : +            for (MediaSessionRecordImpl record :                      mUserEngagedSessionsForFgs.getOrDefault(uid, Set.of())) { -                for (Notification mediaNotification : mMediaNotifications.getOrDefault(uid, -                        Set.of())) { -                    if (sessionRecord.isLinkedToNotification(mediaNotification)) { -                        shouldStopFgs = false; +                for (Notification mediaNotification : +                        mMediaNotifications.getOrDefault(uid, Set.of())) { +                    if (record.isLinkedToNotification(mediaNotification)) { +                        // A user engaged session linked with a media notification is found. +                        // We shouldn't call stop FGS in this case. +                        return;                      }                  }              } -            if (shouldStopFgs) { -                mActivityManagerInternal.stopForegroundServiceDelegate( -                        mediaSessionRecord.getForegroundServiceDelegationOptions()); -            } + +            stopFgsDelegate(foregroundServiceDelegationOptions); +        } +    } + +    private void stopFgsDelegate( +            ForegroundServiceDelegationOptions foregroundServiceDelegationOptions) { +        final long token = Binder.clearCallingIdentity(); +        try { +            mActivityManagerInternal.stopForegroundServiceDelegate( +                    foregroundServiceDelegationOptions); +        } finally { +            Binder.restoreCallingIdentity(token);          }      } @@ -2502,7 +2550,6 @@ public class MediaSessionService extends SystemService implements Monitor {              }              MediaSessionRecord session = null;              MediaButtonReceiverHolder mediaButtonReceiverHolder = null; -              if (mCustomMediaKeyDispatcher != null) {                  MediaSession.Token token = mCustomMediaKeyDispatcher.getMediaSession(                          keyEvent, uid, asSystemService); @@ -2630,6 +2677,18 @@ public class MediaSessionService extends SystemService implements Monitor {                      && streamType <= AudioManager.STREAM_NOTIFICATION;          } +        @Override +        public void expireTempEngagedSessions() { +            synchronized (mLock) { +                for (Set<MediaSessionRecordImpl> uidSessions : +                        mUserEngagedSessionsForFgs.values()) { +                    for (MediaSessionRecordImpl sessionRecord : uidSessions) { +                        sessionRecord.expireTempEngaged(); +                    } +                } +            } +        } +          private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {              private final String mPackageName;              private final int mPid; @@ -3127,7 +3186,6 @@ public class MediaSessionService extends SystemService implements Monitor {              super.onNotificationPosted(sbn);              Notification postedNotification = sbn.getNotification();              int uid = sbn.getUid(); -              if (!postedNotification.isMediaNotification()) {                  return;              } @@ -3138,11 +3196,9 @@ public class MediaSessionService extends SystemService implements Monitor {                          mUserEngagedSessionsForFgs.getOrDefault(uid, Set.of())) {                      ForegroundServiceDelegationOptions foregroundServiceDelegationOptions =                              mediaSessionRecord.getForegroundServiceDelegationOptions(); -                    if (mediaSessionRecord.isLinkedToNotification(postedNotification) -                            && foregroundServiceDelegationOptions != null) { -                        mActivityManagerInternal.startForegroundServiceDelegate( -                                foregroundServiceDelegationOptions, -                                /* connection= */ null); +                    if (foregroundServiceDelegationOptions != null +                            && mediaSessionRecord.isLinkedToNotification(postedNotification)) { +                        startFgsDelegate(foregroundServiceDelegationOptions);                          return;                      }                  } @@ -3173,21 +3229,7 @@ public class MediaSessionService extends SystemService implements Monitor {                      return;                  } -                boolean shouldStopFgs = true; -                for (MediaSessionRecordImpl mediaSessionRecord : -                        mUserEngagedSessionsForFgs.getOrDefault(uid, Set.of())) { -                    for (Notification mediaNotification : -                            mMediaNotifications.getOrDefault(uid, Set.of())) { -                        if (mediaSessionRecord.isLinkedToNotification(mediaNotification)) { -                            shouldStopFgs = false; -                        } -                    } -                } -                if (shouldStopFgs -                        && notificationRecord.getForegroundServiceDelegationOptions() != null) { -                    mActivityManagerInternal.stopForegroundServiceDelegate( -                            notificationRecord.getForegroundServiceDelegationOptions()); -                } +                stopFgsIfNoSessionIsLinkedToNotification(notificationRecord);              }          } diff --git a/services/core/java/com/android/server/media/MediaShellCommand.java b/services/core/java/com/android/server/media/MediaShellCommand.java index a56380827f2c..a20de3198d2c 100644 --- a/services/core/java/com/android/server/media/MediaShellCommand.java +++ b/services/core/java/com/android/server/media/MediaShellCommand.java @@ -92,6 +92,8 @@ public class MediaShellCommand extends ShellCommand {                  runMonitor();              } else if (cmd.equals("volume")) {                  runVolume(); +            } else if (cmd.equals("expire-temp-engaged-sessions")) { +                expireTempEngagedSessions();              } else {                  showError("Error: unknown command '" + cmd + "'");                  return -1; @@ -367,4 +369,8 @@ public class MediaShellCommand extends ShellCommand {      private void runVolume() throws Exception {          VolumeCtrl.run(this);      } + +    private void expireTempEngagedSessions() throws Exception { +        mSessionService.expireTempEngagedSessions(); +    }  } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 956e10c79246..b14242ef8e08 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -22,6 +22,7 @@ import static android.Manifest.permission.STATUS_BAR_SERVICE;  import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;  import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE;  import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.app.AppOpsManager.MODE_DEFAULT;  import static android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR;  import static android.app.Flags.lifetimeExtensionRefactor;  import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; @@ -701,7 +702,7 @@ public class NotificationManagerService extends SystemService {      private static final int MY_UID = Process.myUid();      private static final int MY_PID = Process.myPid(); -    private static final IBinder ALLOWLIST_TOKEN = new Binder(); +    static final IBinder ALLOWLIST_TOKEN = new Binder();      protected RankingHandler mRankingHandler;      private long mLastOverRateLogTime;      private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; @@ -3399,21 +3400,21 @@ public class NotificationManagerService extends SystemService {          // ============================================================================          @Override -        public void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, +        public boolean enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration,                  boolean isUiContext, int displayId,                  @Nullable ITransientNotificationCallback textCallback) { -            enqueueToast(pkg, token, text, /* callback= */ null, duration, isUiContext, displayId, -                    textCallback); +            return enqueueToast(pkg, token, text, /* callback= */ null, duration, isUiContext, +                    displayId, textCallback);          }          @Override -        public void enqueueToast(String pkg, IBinder token, ITransientNotification callback, +        public boolean enqueueToast(String pkg, IBinder token, ITransientNotification callback,                  int duration, boolean isUiContext, int displayId) { -            enqueueToast(pkg, token, /* text= */ null, callback, duration, isUiContext, displayId, -                    /* textCallback= */ null); +            return enqueueToast(pkg, token, /* text= */ null, callback, duration, isUiContext, +                    displayId, /* textCallback= */ null);          } -        private void enqueueToast(String pkg, IBinder token, @Nullable CharSequence text, +        private boolean enqueueToast(String pkg, IBinder token, @Nullable CharSequence text,                  @Nullable ITransientNotification callback, int duration, boolean isUiContext,                  int displayId, @Nullable ITransientNotificationCallback textCallback) {              if (DBG) { @@ -3425,7 +3426,7 @@ public class NotificationManagerService extends SystemService {                      || (text != null && callback != null) || token == null) {                  Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " text=" + text + " callback="                          + " token=" + token); -                return; +                return false;              }              final int callingUid = Binder.getCallingUid(); @@ -3451,7 +3452,7 @@ public class NotificationManagerService extends SystemService {              boolean isAppRenderedToast = (callback != null);              if (!checkCanEnqueueToast(pkg, callingUid, displayId, isAppRenderedToast,                      isSystemToast)) { -                return; +                return false;              }              synchronized (mToastQueue) { @@ -3477,7 +3478,7 @@ public class NotificationManagerService extends SystemService {                                  if (count >= MAX_PACKAGE_TOASTS) {                                      Slog.e(TAG, "Package has already queued " + count                                              + " toasts. Not showing more. Package=" + pkg); -                                    return; +                                    return false;                                  }                              }                          } @@ -3513,6 +3514,7 @@ public class NotificationManagerService extends SystemService {                      Binder.restoreCallingIdentity(callingId);                  }              } +            return true;          }          @GuardedBy("mToastQueue") @@ -3597,8 +3599,8 @@ public class NotificationManagerService extends SystemService {              }          } -        @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING)          @Override +        @EnforcePermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING)          public void setToastRateLimitingEnabled(boolean enable) {              super.setToastRateLimitingEnabled_enforcePermission(); @@ -4523,7 +4525,6 @@ public class NotificationManagerService extends SystemService {              return getActiveNotificationsWithAttribution(callingPkg, null);          } -        @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)          /**           * System-only API for getting a list of current (i.e. not cleared) notifications.           * @@ -4531,6 +4532,7 @@ public class NotificationManagerService extends SystemService {           * @returns A list of all the notifications, in natural order.           */          @Override +        @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)          public StatusBarNotification[] getActiveNotificationsWithAttribution(String callingPkg,                  String callingAttributionTag) {              // enforce() will ensure the calling uid has the correct permission @@ -4548,9 +4550,9 @@ public class NotificationManagerService extends SystemService {              });              // noteOp will check to make sure the callingPkg matches the uid -            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, -                    callingAttributionTag, null) -                    == MODE_ALLOWED) { +            int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, +                        callingAttributionTag, null); +            if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {                  synchronized (mNotificationLock) {                      final int N = mNotificationList.size();                      for (int i = 0; i < N; i++) { @@ -4626,7 +4628,7 @@ public class NotificationManagerService extends SystemService {                      // Remove background token before returning notification to untrusted app, this                      // ensures the app isn't able to perform background operations that are                      // associated with notification interactions. -                    notification.clearAllowlistToken(); +                    notification.overrideAllowlistToken(null);                      return new StatusBarNotification(                              sbn.getPackageName(),                              sbn.getOpPkg(), @@ -4650,12 +4652,12 @@ public class NotificationManagerService extends SystemService {                      includeSnoozed);          } -        @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)          /**           * System-only API for getting a list of recent (cleared, no longer shown) notifications.           */          @Override          @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) +        @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)          public StatusBarNotification[] getHistoricalNotificationsWithAttribution(String callingPkg,                  String callingAttributionTag, int count, boolean includeSnoozed) {              // enforce() will ensure the calling uid has the correct permission @@ -4665,9 +4667,9 @@ public class NotificationManagerService extends SystemService {              int uid = Binder.getCallingUid();              // noteOp will check to make sure the callingPkg matches the uid -            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, -                    callingAttributionTag, null) -                    == MODE_ALLOWED) { +            int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, +                        callingAttributionTag, null); +            if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {                  synchronized (mArchive) {                      tmp = mArchive.getArray(mUm, count, includeSnoozed);                  } @@ -4675,7 +4677,6 @@ public class NotificationManagerService extends SystemService {              return tmp;          } -        @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)          /**           * System-only API for getting a list of historical notifications. May contain multiple days           * of notifications. @@ -4683,6 +4684,7 @@ public class NotificationManagerService extends SystemService {          @Override          @WorkerThread          @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS) +        @EnforcePermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)          public NotificationHistory getNotificationHistory(String callingPkg,                  String callingAttributionTag) {              // enforce() will ensure the calling uid has the correct permission @@ -4690,9 +4692,9 @@ public class NotificationManagerService extends SystemService {              int uid = Binder.getCallingUid();              // noteOp will check to make sure the callingPkg matches the uid -            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, -                    callingAttributionTag, null) -                    == MODE_ALLOWED) { +            int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg, +                        callingAttributionTag, null); +            if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) {                  IntArray currentUserIds = mUserProfiles.getCurrentProfileIds();                  Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "notifHistoryReadHistory");                  try { @@ -7213,6 +7215,17 @@ public class NotificationManagerService extends SystemService {                      + " trying to post for invalid pkg " + pkg + " in user " + incomingUserId);          } +        if (android.app.Flags.secureAllowlistToken()) { +            IBinder allowlistToken = notification.getAllowlistToken(); +            if (allowlistToken != null && allowlistToken != ALLOWLIST_TOKEN) { +                throw new SecurityException( +                        "Unexpected allowlist token received from " + callingUid); +            } +            // allowlistToken is populated by unparceling, so it can be null if the notification was +            // posted from inside system_server. Ensure it's the expected value. +            notification.overrideAllowlistToken(ALLOWLIST_TOKEN); +        } +          checkRestrictedCategories(notification);          // Notifications passed to setForegroundService() have FLAG_FOREGROUND_SERVICE, diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 4b8e4852aee7..6c93fe787816 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -32,6 +32,7 @@ import static android.os.Process.INVALID_UID;  import static android.os.Trace.TRACE_TAG_RRO;  import static android.os.Trace.traceBegin;  import static android.os.Trace.traceEnd; +  import static com.android.server.om.OverlayManagerServiceImpl.OperationFailedException;  import android.annotation.NonNull; @@ -279,7 +280,8 @@ public final class OverlayManagerService extends SystemService {              HandlerThread packageMonitorThread = new HandlerThread(TAG);              packageMonitorThread.start(); -            mPackageMonitor.register(context, packageMonitorThread.getLooper(), true); +            mPackageMonitor.register( +                    context, packageMonitorThread.getLooper(), UserHandle.ALL, true);              final IntentFilter userFilter = new IntentFilter();              userFilter.addAction(ACTION_USER_ADDED); @@ -369,17 +371,17 @@ public final class OverlayManagerService extends SystemService {          @Override          public void onPackageAppearedWithExtras(String packageName, Bundle extras) { -            handlePackageAdd(packageName, extras); +            handlePackageAdd(packageName, extras, getChangingUserId());          }          @Override          public void onPackageChangedWithExtras(String packageName, Bundle extras) { -            handlePackageChange(packageName, extras); +            handlePackageChange(packageName, extras, getChangingUserId());          }          @Override          public void onPackageDisappearedWithExtras(String packageName, Bundle extras) { -            handlePackageRemove(packageName, extras); +            handlePackageRemove(packageName, extras, getChangingUserId());          }      } @@ -393,54 +395,45 @@ public final class OverlayManagerService extends SystemService {          return userIds;      } -    private void handlePackageAdd(String packageName, Bundle extras) { +    private void handlePackageAdd(String packageName, Bundle extras, int userId) {          final boolean replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); -        final int uid = extras.getInt(Intent.EXTRA_UID, 0); -        final int[] userIds = getUserIds(uid);          if (replacing) { -            onPackageReplaced(packageName, userIds); +            onPackageReplaced(packageName, userId);          } else { -            onPackageAdded(packageName, userIds); +            onPackageAdded(packageName, userId);          }      } -    private void handlePackageChange(String packageName, Bundle extras) { -        final int uid = extras.getInt(Intent.EXTRA_UID, 0); -        final int[] userIds = getUserIds(uid); +    private void handlePackageChange(String packageName, Bundle extras, int userId) {          if (!ACTION_OVERLAY_CHANGED.equals(extras.getString(EXTRA_REASON))) { -            onPackageChanged(packageName, userIds); +            onPackageChanged(packageName, userId);          }      } -    private void handlePackageRemove(String packageName, Bundle extras) { +    private void handlePackageRemove(String packageName, Bundle extras, int userId) {          final boolean replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);          final boolean systemUpdateUninstall =                  extras.getBoolean(Intent.EXTRA_SYSTEM_UPDATE_UNINSTALL, false); -        final int uid = extras.getInt(Intent.EXTRA_UID, 0); -        final int[] userIds = getUserIds(uid);          if (replacing) { -            onPackageReplacing(packageName, systemUpdateUninstall, userIds); +            onPackageReplacing(packageName, systemUpdateUninstall, userId);          } else { -            onPackageRemoved(packageName, userIds); +            onPackageRemoved(packageName, userId);          }      } -    private void onPackageAdded(@NonNull final String packageName, -            @NonNull final int[] userIds) { +    private void onPackageAdded(@NonNull final String packageName, final int userId) {          try {              traceBegin(TRACE_TAG_RRO, "OMS#onPackageAdded " + packageName); -            for (final int userId : userIds) { -                synchronized (mLock) { -                    var packageState = mPackageManager.onPackageAdded(packageName, userId); -                    if (packageState != null && !mPackageManager.isInstantApp(packageName, -                            userId)) { -                        try { -                            updateTargetPackagesLocked( -                                    mImpl.onPackageAdded(packageName, userId)); -                        } catch (OperationFailedException e) { -                            Slog.e(TAG, "onPackageAdded internal error", e); -                        } +            synchronized (mLock) { +                var packageState = mPackageManager.onPackageAdded(packageName, userId); +                if (packageState != null && !mPackageManager.isInstantApp(packageName, +                        userId)) { +                    try { +                        updateTargetPackagesLocked( +                                mImpl.onPackageAdded(packageName, userId)); +                    } catch (OperationFailedException e) { +                        Slog.e(TAG, "onPackageAdded internal error", e);                      }                  }              } @@ -449,21 +442,18 @@ public final class OverlayManagerService extends SystemService {          }      } -    private void onPackageChanged(@NonNull final String packageName, -            @NonNull final int[] userIds) { +    private void onPackageChanged(@NonNull final String packageName, final int userId) {          try {              traceBegin(TRACE_TAG_RRO, "OMS#onPackageChanged " + packageName); -            for (int userId : userIds) { -                synchronized (mLock) { -                    var packageState = mPackageManager.onPackageUpdated(packageName, userId); -                    if (packageState != null && !mPackageManager.isInstantApp(packageName, -                            userId)) { -                        try { -                            updateTargetPackagesLocked( -                                    mImpl.onPackageChanged(packageName, userId)); -                        } catch (OperationFailedException e) { -                            Slog.e(TAG, "onPackageChanged internal error", e); -                        } +            synchronized (mLock) { +                var packageState = mPackageManager.onPackageUpdated(packageName, userId); +                if (packageState != null && !mPackageManager.isInstantApp(packageName, +                        userId)) { +                    try { +                        updateTargetPackagesLocked( +                                mImpl.onPackageChanged(packageName, userId)); +                    } catch (OperationFailedException e) { +                        Slog.e(TAG, "onPackageChanged internal error", e);                      }                  }              } @@ -473,20 +463,18 @@ public final class OverlayManagerService extends SystemService {      }      private void onPackageReplacing(@NonNull final String packageName, -            boolean systemUpdateUninstall, @NonNull final int[] userIds) { +                                    boolean systemUpdateUninstall, final int userId) {          try {              traceBegin(TRACE_TAG_RRO, "OMS#onPackageReplacing " + packageName); -            for (int userId : userIds) { -                synchronized (mLock) { -                    var packageState = mPackageManager.onPackageUpdated(packageName, userId); -                    if (packageState != null && !mPackageManager.isInstantApp(packageName, -                            userId)) { -                        try { -                            updateTargetPackagesLocked(mImpl.onPackageReplacing(packageName, -                                    systemUpdateUninstall, userId)); -                        } catch (OperationFailedException e) { -                            Slog.e(TAG, "onPackageReplacing internal error", e); -                        } +            synchronized (mLock) { +                var packageState = mPackageManager.onPackageUpdated(packageName, userId); +                if (packageState != null && !mPackageManager.isInstantApp(packageName, +                        userId)) { +                    try { +                        updateTargetPackagesLocked(mImpl.onPackageReplacing(packageName, +                                systemUpdateUninstall, userId)); +                    } catch (OperationFailedException e) { +                        Slog.e(TAG, "onPackageReplacing internal error", e);                      }                  }              } @@ -495,21 +483,18 @@ public final class OverlayManagerService extends SystemService {          }      } -    private void onPackageReplaced(@NonNull final String packageName, -            @NonNull final int[] userIds) { +    private void onPackageReplaced(@NonNull final String packageName, final int userId) {          try {              traceBegin(TRACE_TAG_RRO, "OMS#onPackageReplaced " + packageName); -            for (int userId : userIds) { -                synchronized (mLock) { -                    var packageState = mPackageManager.onPackageUpdated(packageName, userId); -                    if (packageState != null && !mPackageManager.isInstantApp(packageName, -                            userId)) { -                        try { -                            updateTargetPackagesLocked( -                                    mImpl.onPackageReplaced(packageName, userId)); -                        } catch (OperationFailedException e) { -                            Slog.e(TAG, "onPackageReplaced internal error", e); -                        } +            synchronized (mLock) { +                var packageState = mPackageManager.onPackageUpdated(packageName, userId); +                if (packageState != null && !mPackageManager.isInstantApp(packageName, +                        userId)) { +                    try { +                        updateTargetPackagesLocked( +                                mImpl.onPackageReplaced(packageName, userId)); +                    } catch (OperationFailedException e) { +                        Slog.e(TAG, "onPackageReplaced internal error", e);                      }                  }              } @@ -518,15 +503,12 @@ public final class OverlayManagerService extends SystemService {          }      } -    private void onPackageRemoved(@NonNull final String packageName, -            @NonNull final int[] userIds) { +    private void onPackageRemoved(@NonNull final String packageName, final int userId) {          try {              traceBegin(TRACE_TAG_RRO, "OMS#onPackageRemoved " + packageName); -            for (int userId : userIds) { -                synchronized (mLock) { -                    mPackageManager.onPackageRemoved(packageName, userId); -                    updateTargetPackagesLocked(mImpl.onPackageRemoved(packageName, userId)); -                } +            synchronized (mLock) { +                mPackageManager.onPackageRemoved(packageName, userId); +                updateTargetPackagesLocked(mImpl.onPackageRemoved(packageName, userId));              }          } finally {              traceEnd(TRACE_TAG_RRO); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 68cd3e463905..614828add52b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5753,17 +5753,22 @@ public class PackageManagerService implements PackageSender, TestUtilityService          @Override          public void setApplicationCategoryHint(String packageName, int categoryHint,                  String callerPackageName) { +            final int callingUid = Binder.getCallingUid(); +            final int userId = UserHandle.getCallingUserId();              final FunctionalUtils.ThrowingBiFunction<PackageStateMutator.InitialState, Computer,                      PackageStateMutator.Result> implementation = (initialState, computer) -> { -                if (computer.getInstantAppPackageName(Binder.getCallingUid()) != null) { +                if (computer.getInstantAppPackageName(callingUid) != null) {                      throw new SecurityException(                              "Instant applications don't have access to this method");                  } -                mInjector.getSystemService(AppOpsManager.class) -                        .checkPackage(Binder.getCallingUid(), callerPackageName); +                final int callerPackageUid = computer.getPackageUid(callerPackageName, 0, userId); +                if (callerPackageUid != callingUid) { +                    throw new SecurityException( +                            "Package " + callerPackageName + " does not belong to " + callingUid); +                }                  PackageStateInternal packageState = computer.getPackageStateForInstalledAndFiltered( -                        packageName, Binder.getCallingUid(), UserHandle.getCallingUserId()); +                        packageName, callingUid, userId);                  if (packageState == null) {                      throw new IllegalArgumentException("Unknown target package " + packageName);                  } diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java index 1fe49c7d5834..7ef7ce7afb65 100644 --- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java +++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java @@ -16,6 +16,8 @@  package com.android.server.pm; +import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.PARSE_APEX; +  import android.apex.ApexInfo;  import android.apex.ApexInfoList;  import android.apex.ApexSessionInfo; @@ -399,7 +401,7 @@ final class PackageSessionVerifier {              final ParsedPackage parsedPackage;              try (PackageParser2 packageParser = mPackageParserSupplier.get()) {                  File apexFile = new File(apexInfo.modulePath); -                parsedPackage = packageParser.parsePackage(apexFile, 0, false); +                parsedPackage = packageParser.parsePackage(apexFile, PARSE_APEX, false);              } catch (PackageParserException e) {                  throw new PackageManagerException(                          PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java index 33b5a707d9df..1e7fdfec783f 100644 --- a/services/core/java/com/android/server/pm/UserTypeFactory.java +++ b/services/core/java/com/android/server/pm/UserTypeFactory.java @@ -306,7 +306,7 @@ public final class UserTypeFactory {                          R.color.black)                  .setDarkThemeBadgeColors(                          R.color.white) -                .setDefaultRestrictions(getDefaultProfileRestrictions()) +                .setDefaultRestrictions(getDefaultPrivateProfileRestrictions())                  .setDefaultCrossProfileIntentFilters(getDefaultPrivateCrossProfileIntentFilter())                  .setDefaultUserProperties(new UserProperties.Builder()                          .setStartWithParent(true) @@ -430,6 +430,13 @@ public final class UserTypeFactory {          return restrictions;      } +    @VisibleForTesting +    static Bundle getDefaultPrivateProfileRestrictions() { +        final Bundle restrictions = getDefaultProfileRestrictions(); +        restrictions.putBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING, true); +        return restrictions; +    } +      private static Bundle getDefaultManagedProfileSecureSettings() {          // Only add String values to the bundle, settings are written as Strings eventually          final Bundle settings = new Bundle(); 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 f7f76aaaee16..57ea233c0a2b 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -807,7 +807,7 @@ final class DefaultPermissionGrantPolicy {                      getDefaultSystemHandlerActivityPackage(pm,                              SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),                      userId, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS, -                    NOTIFICATION_PERMISSIONS, PHONE_PERMISSIONS); +                    NOTIFICATION_PERMISSIONS, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS);          }          // Voice recognition diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index b5d49b36affe..53863aa83ab4 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -622,6 +622,7 @@ public final class PowerManagerService extends SystemService      // Value we store for tracking face down behavior.      @VisibleForTesting      boolean mIsFaceDown = false; +    private boolean mUseFaceDownDetector = true;      private long mLastFlipTime = 0L;      // The screen brightness setting override from the window manager @@ -3253,7 +3254,7 @@ public final class PowerManagerService extends SystemService                      mScreenTimeoutOverridePolicy.getScreenTimeoutOverrideLocked(                              mWakeLockSummary, screenOffTimeout);          } -        if (mIsFaceDown) { +        if (mIsFaceDown && mUseFaceDownDetector) {              shortestScreenOffTimeout = Math.min(screenDimDuration, shortestScreenOffTimeout);          } @@ -4701,6 +4702,7 @@ public final class PowerManagerService extends SystemService              pw.println("  mHoldingDisplaySuspendBlocker=" + mHoldingDisplaySuspendBlocker);              pw.println("  mLastFlipTime=" + mLastFlipTime);              pw.println("  mIsFaceDown=" + mIsFaceDown); +            pw.println("  mUseFaceDownDetector=" + mUseFaceDownDetector);              pw.println();              pw.println("Settings and Configuration:"); @@ -6921,6 +6923,16 @@ public final class PowerManagerService extends SystemService                  Binder.restoreCallingIdentity(ident);              }          } + +        public void setUseFaceDownDetector(boolean enable) { +            final long ident = Binder.clearCallingIdentity(); +            try { +                mUseFaceDownDetector = enable; +            } finally { +                Binder.restoreCallingIdentity(ident); +            } +        } +      }      @VisibleForTesting diff --git a/services/core/java/com/android/server/power/PowerManagerShellCommand.java b/services/core/java/com/android/server/power/PowerManagerShellCommand.java index 9439b762fde0..20184e9fd1a7 100644 --- a/services/core/java/com/android/server/power/PowerManagerShellCommand.java +++ b/services/core/java/com/android/server/power/PowerManagerShellCommand.java @@ -63,6 +63,8 @@ class PowerManagerShellCommand extends ShellCommand {                      return runListAmbientDisplaySuppressionTokens();                  case "set-prox":                      return runSetProx(); +                case "set-face-down-detector": +                    return runSetFaceDownDetector();                  default:                      return handleDefaultCommands(cmd);              } @@ -178,6 +180,20 @@ class PowerManagerShellCommand extends ShellCommand {          return 0;      } +    /** +     * To be used for testing - allowing us to disable the usage of face down detector. +     */ +    private int runSetFaceDownDetector() { +        try { +            mService.setUseFaceDownDetector(Boolean.parseBoolean(getNextArgRequired())); +        } catch (Exception e) { +            PrintWriter pw = getOutPrintWriter(); +            pw.println("Error: " + e); +            return -1; +        } +        return 0; +    } +      @Override      public void onHelp() {          final PrintWriter pw = getOutPrintWriter(); @@ -203,6 +219,8 @@ class PowerManagerShellCommand extends ShellCommand {          pw.println("    Acquires the proximity sensor wakelock. Wakelock is associated with");          pw.println("    a specific display if specified. 'list' lists wakelocks previously");          pw.println("    created by set-prox including their held status."); +        pw.println("  set-face-down-detector [true|false]"); +        pw.println("    sets whether we use face down detector timeouts or not");          pw.println();          Intent.printIntentArgsHelp(pw , ""); diff --git a/services/core/java/com/android/server/power/stats/AggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/AggregatedPowerStats.java index 894226cf32c9..e1b4b88ed1df 100644 --- a/services/core/java/com/android/server/power/stats/AggregatedPowerStats.java +++ b/services/core/java/com/android/server/power/stats/AggregatedPowerStats.java @@ -34,11 +34,14 @@ import org.xmlpull.v1.XmlPullParserException;  import java.io.IOException;  import java.io.StringWriter; +import java.text.SimpleDateFormat;  import java.util.ArrayList;  import java.util.Arrays; +import java.util.Date;  import java.util.HashSet;  import java.util.List;  import java.util.Set; +import java.util.TimeZone;  /**   * This class represents aggregated power stats for a variety of power components (CPU, WiFi, @@ -66,7 +69,7 @@ class AggregatedPowerStats {                  aggregatedPowerStatsConfig.getPowerComponentsAggregatedStatsConfigs();          mPowerComponentStats = new PowerComponentAggregatedPowerStats[configs.size()];          for (int i = 0; i < configs.size(); i++) { -            mPowerComponentStats[i] = new PowerComponentAggregatedPowerStats(configs.get(i)); +            mPowerComponentStats[i] = new PowerComponentAggregatedPowerStats(this, configs.get(i));          }      } @@ -223,7 +226,7 @@ class AggregatedPowerStats {              if (i == 0) {                  baseTime = clockUpdate.monotonicTime;                  sb.append("Start time: ") -                        .append(DateFormat.format("yyyy-MM-dd-HH-mm-ss", clockUpdate.currentTime)) +                        .append(formatDateTime(clockUpdate.currentTime))                          .append(" (")                          .append(baseTime)                          .append(") duration: ") @@ -235,8 +238,7 @@ class AggregatedPowerStats {                  TimeUtils.formatDuration(                          clockUpdate.monotonicTime - baseTime, sb,                          TimeUtils.HUNDRED_DAY_FIELD_LEN + 3); -                sb.append(" ").append( -                        DateFormat.format("yyyy-MM-dd-HH-mm-ss", clockUpdate.currentTime)); +                sb.append(" ").append(formatDateTime(clockUpdate.currentTime));                  ipw.increaseIndent();                  ipw.println(sb);                  ipw.decreaseIndent(); @@ -267,6 +269,12 @@ class AggregatedPowerStats {          }      } +    private static String formatDateTime(long timeInMillis) { +        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); +        format.getCalendar().setTimeZone(TimeZone.getTimeZone("GMT")); +        return format.format(new Date(timeInMillis)); +    } +      @Override      public String toString() {          StringWriter sw = new StringWriter(); diff --git a/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java b/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java index 6fbbc0f072e8..5aad570ffd41 100644 --- a/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java +++ b/services/core/java/com/android/server/power/stats/AggregatedPowerStatsConfig.java @@ -75,7 +75,7 @@ public class AggregatedPowerStatsConfig {          private final int mPowerComponentId;          private @TrackedState int[] mTrackedDeviceStates;          private @TrackedState int[] mTrackedUidStates; -        private AggregatedPowerStatsProcessor mProcessor = NO_OP_PROCESSOR; +        private PowerStatsProcessor mProcessor = NO_OP_PROCESSOR;          PowerComponent(int powerComponentId) {              this.mPowerComponentId = powerComponentId; @@ -85,6 +85,9 @@ public class AggregatedPowerStatsConfig {           * Configures which states should be tracked as separate dimensions for the entire device.           */          public PowerComponent trackDeviceStates(@TrackedState int... states) { +            if (mTrackedDeviceStates != null) { +                throw new IllegalStateException("Component is already configured"); +            }              mTrackedDeviceStates = states;              return this;          } @@ -93,6 +96,9 @@ public class AggregatedPowerStatsConfig {           * Configures which states should be tracked as separate dimensions on a per-UID basis.           */          public PowerComponent trackUidStates(@TrackedState int... states) { +            if (mTrackedUidStates != null) { +                throw new IllegalStateException("Component is already configured"); +            }              mTrackedUidStates = states;              return this;          } @@ -102,7 +108,7 @@ public class AggregatedPowerStatsConfig {           * before giving the aggregates stats to consumers. The processor can complete the           * aggregation process, for example by computing estimated power usage.           */ -        public PowerComponent setProcessor(@NonNull AggregatedPowerStatsProcessor processor) { +        public PowerComponent setProcessor(@NonNull PowerStatsProcessor processor) {              mProcessor = processor;              return this;          } @@ -137,7 +143,7 @@ public class AggregatedPowerStatsConfig {          }          @NonNull -        public AggregatedPowerStatsProcessor getProcessor() { +        public PowerStatsProcessor getProcessor() {              return mProcessor;          } @@ -153,6 +159,7 @@ public class AggregatedPowerStatsConfig {              }              return false;          } +      }      private final List<PowerComponent> mPowerComponents = new ArrayList<>(); @@ -168,23 +175,55 @@ public class AggregatedPowerStatsConfig {          return builder;      } +    /** +     * Creates a configuration for the specified power component, which is a subcomponent +     * of a different power component.  The tracked states will be the same as the parent +     * component's. +     */ +    public PowerComponent trackPowerComponent(int powerComponentId, +            int parentPowerComponentId) { +        PowerComponent parent = null; +        for (int i = 0; i < mPowerComponents.size(); i++) { +            PowerComponent powerComponent = mPowerComponents.get(i); +            if (powerComponent.getPowerComponentId() == parentPowerComponentId) { +                parent = powerComponent; +                break; +            } +        } + +        if (parent == null) { +            throw new IllegalArgumentException( +                    "Parent component " + parentPowerComponentId + " is not configured"); +        } + +        PowerComponent powerComponent = trackPowerComponent(powerComponentId); +        powerComponent.mTrackedDeviceStates = parent.mTrackedDeviceStates; +        powerComponent.mTrackedUidStates = parent.mTrackedUidStates; +        return powerComponent; +    } +      public List<PowerComponent> getPowerComponentsAggregatedStatsConfigs() {          return mPowerComponents;      } -    private static final AggregatedPowerStatsProcessor NO_OP_PROCESSOR = -            new AggregatedPowerStatsProcessor() { +    private static final PowerStatsProcessor NO_OP_PROCESSOR = +            new PowerStatsProcessor() {                  @Override -                public void finish(PowerComponentAggregatedPowerStats stats) { +                void finish(PowerComponentAggregatedPowerStats stats) {                  }                  @Override -                public String deviceStatsToString(PowerStats.Descriptor descriptor, long[] stats) { +                String deviceStatsToString(PowerStats.Descriptor descriptor, long[] stats) {                      return Arrays.toString(stats);                  }                  @Override -                public String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats) { +                String stateStatsToString(PowerStats.Descriptor descriptor, int key, long[] stats) { +                    return descriptor.getStateLabel(key) + " " + Arrays.toString(stats); +                } + +                @Override +                String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats) {                      return Arrays.toString(stats);                  }              }; diff --git a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java index a8eda3ca6a47..cb10da9787df 100644 --- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java @@ -24,6 +24,7 @@ import android.hardware.power.stats.EnergyConsumer;  import android.hardware.power.stats.EnergyConsumerResult;  import android.hardware.power.stats.EnergyConsumerType;  import android.net.wifi.WifiManager; +import android.os.BatteryConsumer;  import android.os.BatteryStats;  import android.os.Bundle;  import android.os.OutcomeReceiver; @@ -603,24 +604,31 @@ public class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStat          }          if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) { -            // We were asked to fetch Telephony data. -            if (mTelephony != null) { -                CompletableFuture<ModemActivityInfo> temp = new CompletableFuture<>(); -                mTelephony.requestModemActivityInfo(Runnable::run, -                        new OutcomeReceiver<ModemActivityInfo, -                                TelephonyManager.ModemActivityInfoException>() { -                            @Override -                            public void onResult(ModemActivityInfo result) { -                                temp.complete(result); -                            } - -                            @Override -                            public void onError(TelephonyManager.ModemActivityInfoException e) { -                                Slog.w(TAG, "error reading modem stats:" + e); -                                temp.complete(null); -                            } -                        }); -                modemFuture = temp; +            @SuppressWarnings("GuardedBy") +            PowerStatsCollector collector = mStats.getPowerStatsCollector( +                    BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO); +            if (collector.isEnabled()) { +                collector.schedule(); +            } else { +                // We were asked to fetch Telephony data. +                if (mTelephony != null) { +                    CompletableFuture<ModemActivityInfo> temp = new CompletableFuture<>(); +                    mTelephony.requestModemActivityInfo(Runnable::run, +                            new OutcomeReceiver<ModemActivityInfo, +                                    TelephonyManager.ModemActivityInfoException>() { +                                @Override +                                public void onResult(ModemActivityInfo result) { +                                    temp.complete(result); +                                } + +                                @Override +                                public void onError(TelephonyManager.ModemActivityInfoException e) { +                                    Slog.w(TAG, "error reading modem stats:" + e); +                                    temp.complete(null); +                                } +                            }); +                    modemFuture = temp; +                }              }              if (!railUpdated) {                  synchronized (mStats) { diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java index 3a84897839a1..d060c7ca3034 100644 --- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java @@ -22,6 +22,8 @@ import static android.os.BatteryStats.Uid.NUM_PROCESS_STATE;  import static android.os.BatteryStatsManager.NUM_WIFI_STATES;  import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES; +import static com.android.server.power.stats.MobileRadioPowerStatsCollector.mapRadioAccessNetworkTypeToRadioAccessTechnology; +  import android.annotation.IntDef;  import android.annotation.NonNull;  import android.annotation.Nullable; @@ -35,6 +37,7 @@ import android.content.ContentResolver;  import android.content.Context;  import android.content.Intent;  import android.content.IntentFilter; +import android.content.pm.PackageManager;  import android.database.ContentObserver;  import android.hardware.usb.UsbManager;  import android.location.GnssSignalQuality; @@ -71,6 +74,7 @@ import android.os.connectivity.CellularBatteryStats;  import android.os.connectivity.GpsBatteryStats;  import android.os.connectivity.WifiActivityEnergyInfo;  import android.os.connectivity.WifiBatteryStats; +import android.power.PowerStatsInternal;  import android.provider.Settings;  import android.telephony.AccessNetworkConstants;  import android.telephony.Annotation.NetworkType; @@ -99,6 +103,7 @@ import android.util.PrintWriterPrinter;  import android.util.Printer;  import android.util.Slog;  import android.util.SparseArray; +import android.util.SparseBooleanArray;  import android.util.SparseDoubleArray;  import android.util.SparseIntArray;  import android.util.SparseLongArray; @@ -137,6 +142,7 @@ import com.android.internal.util.FrameworkStatsLog;  import com.android.internal.util.XmlUtils;  import com.android.modules.utils.TypedXmlPullParser;  import com.android.modules.utils.TypedXmlSerializer; +import com.android.server.LocalServices;  import com.android.server.power.optimization.Flags;  import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes; @@ -166,8 +172,12 @@ import java.util.List;  import java.util.Map;  import java.util.Queue;  import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit;  import java.util.concurrent.atomic.AtomicInteger;  import java.util.concurrent.locks.ReentrantLock; +import java.util.function.IntSupplier; +import java.util.function.LongSupplier; +import java.util.function.Supplier;  /**   * All information we are collecting about things that can happen that impact @@ -281,7 +291,8 @@ public class BatteryStatsImpl extends BatteryStats {      private final LongSparseArray<SamplingTimer> mKernelMemoryStats = new LongSparseArray<>();      private int[] mCpuPowerBracketMap;      private final CpuPowerStatsCollector mCpuPowerStatsCollector; -    private boolean mPowerStatsCollectorEnabled; +    private final MobileRadioPowerStatsCollector mMobileRadioPowerStatsCollector; +    private final SparseBooleanArray mPowerStatsCollectorEnabled = new SparseBooleanArray();      public LongSparseArray<SamplingTimer> getKernelMemoryStats() {          return mKernelMemoryStats; @@ -433,9 +444,11 @@ public class BatteryStatsImpl extends BatteryStats {      public static class BatteryStatsConfig {          static final int RESET_ON_UNPLUG_HIGH_BATTERY_LEVEL_FLAG = 1 << 0;          static final int RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG = 1 << 1; +        static final long DEFAULT_POWER_STATS_COLLECTION_THROTTLE_PERIOD = +                TimeUnit.HOURS.toMillis(1);          private final int mFlags; -        private final long mPowerStatsThrottlePeriodCpu; +        private SparseLongArray mPowerStatsThrottlePeriods;          private BatteryStatsConfig(Builder builder) {              int flags = 0; @@ -446,7 +459,7 @@ public class BatteryStatsImpl extends BatteryStats {                  flags |= RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;              }              mFlags = flags; -            mPowerStatsThrottlePeriodCpu = builder.mPowerStatsThrottlePeriodCpu; +            mPowerStatsThrottlePeriods = builder.mPowerStatsThrottlePeriods;          }          /** @@ -467,8 +480,9 @@ public class BatteryStatsImpl extends BatteryStats {                      == RESET_ON_UNPLUG_AFTER_SIGNIFICANT_CHARGE_FLAG;          } -        long getPowerStatsThrottlePeriodCpu() { -            return mPowerStatsThrottlePeriodCpu; +        long getPowerStatsThrottlePeriod(@BatteryConsumer.PowerComponent int powerComponent) { +            return mPowerStatsThrottlePeriods.get(powerComponent, +                    DEFAULT_POWER_STATS_COLLECTION_THROTTLE_PERIOD);          }          /** @@ -477,12 +491,16 @@ public class BatteryStatsImpl extends BatteryStats {          public static class Builder {              private boolean mResetOnUnplugHighBatteryLevel;              private boolean mResetOnUnplugAfterSignificantCharge; -            private long mPowerStatsThrottlePeriodCpu; +            private SparseLongArray mPowerStatsThrottlePeriods;              public Builder() {                  mResetOnUnplugHighBatteryLevel = true;                  mResetOnUnplugAfterSignificantCharge = true; -                mPowerStatsThrottlePeriodCpu = 60000; +                mPowerStatsThrottlePeriods = new SparseLongArray(); +                setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_CPU, +                        TimeUnit.MINUTES.toMillis(1)); +                setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, +                        TimeUnit.HOURS.toMillis(1));              }              /** @@ -512,10 +530,11 @@ public class BatteryStatsImpl extends BatteryStats {              /**               * Sets the minimum amount of time (in millis) to wait between passes -             * of CPU power stats collection. +             * of power stats collection for the specified power component.               */ -            public Builder setPowerStatsThrottlePeriodCpu(long periodMs) { -                mPowerStatsThrottlePeriodCpu = periodMs; +            public Builder setPowerStatsThrottlePeriodMillis( +                    @BatteryConsumer.PowerComponent int powerComponent, long periodMs) { +                mPowerStatsThrottlePeriods.put(powerComponent, periodMs);                  return this;              }          } @@ -597,7 +616,7 @@ public class BatteryStatsImpl extends BatteryStats {      @SuppressWarnings("GuardedBy")    // errorprone false positive on getProcStateTimeCounter      @VisibleForTesting      public void updateProcStateCpuTimesLocked(int uid, long elapsedRealtimeMs, long uptimeMs) { -        if (mPowerStatsCollectorEnabled) { +        if (mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_CPU)) {              return;          } @@ -653,7 +672,7 @@ public class BatteryStatsImpl extends BatteryStats {       */      @SuppressWarnings("GuardedBy")    // errorprone false positive on getProcStateTimeCounter      public void updateCpuTimesForAllUids() { -        if (mPowerStatsCollectorEnabled && mCpuPowerStatsCollector != null) { +        if (mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_CPU)) {              mCpuPowerStatsCollector.schedule();              return;          } @@ -713,7 +732,8 @@ public class BatteryStatsImpl extends BatteryStats {      @GuardedBy("this")      private void ensureKernelSingleUidTimeReaderLocked() { -        if (mPowerStatsCollectorEnabled || mKernelSingleUidTimeReader != null) { +        if (mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_CPU) +                || mKernelSingleUidTimeReader != null) {              return;          } @@ -830,8 +850,6 @@ public class BatteryStatsImpl extends BatteryStats {      private final HistoryEventTracker mActiveEvents = new HistoryEventTracker();      private final HistoryStepDetailsCalculatorImpl mStepDetailsCalculator =              new HistoryStepDetailsCalculatorImpl(); -    private final PowerStats.DescriptorRegistry mPowerStatsDescriptorRegistry = -            new PowerStats.DescriptorRegistry();      private boolean mHaveBatteryLevel = false;      private boolean mBatteryPluggedIn; @@ -1759,7 +1777,7 @@ public class BatteryStatsImpl extends BatteryStats {          return mMaxLearnedBatteryCapacityUah;      } -    public class FrameworkStatsLogger { +    public static class FrameworkStatsLogger {          public void uidProcessStateChanged(int uid, int state) {              // TODO(b/155216561): It is possible for isolated uids to be in a higher              // state than its parent uid. We should track the highest state within the union of host @@ -1768,25 +1786,24 @@ public class BatteryStatsImpl extends BatteryStats {                      ActivityManager.processStateAmToProto(state));          } -        public void wakelockStateChanged(int uid, WorkChain wc, String name, int type, -                int procState, boolean acquired) { +        public void wakelockStateChanged(int uid, WorkChain wc, String name, +                int procState, boolean acquired, int powerManagerWakeLockLevel) {              int event = acquired                      ? FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE                      : FrameworkStatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE;              if (wc != null) {                  FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), -                        wc.getTags(), getPowerManagerWakeLockLevel(type), name, -                        event, procState); +                        wc.getTags(), powerManagerWakeLockLevel, name, event, procState);              } else { -                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, -                        mapIsolatedUid(uid), null, getPowerManagerWakeLockLevel(type), name, -                        event, procState); +                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, uid, +                        null, powerManagerWakeLockLevel, name, event, procState);              }          } -        public void kernelWakeupReported(long deltaUptimeUs) { -            FrameworkStatsLog.write(FrameworkStatsLog.KERNEL_WAKEUP_REPORTED, mLastWakeupReason, -                    /* duration_usec */ deltaUptimeUs, mLastWakeupElapsedTimeMs); +        public void kernelWakeupReported(long deltaUptimeUs, String lastWakeupReason, +                long lastWakeupElapsedTimeMs) { +            FrameworkStatsLog.write(FrameworkStatsLog.KERNEL_WAKEUP_REPORTED, lastWakeupReason, +                    /* duration_usec */ deltaUptimeUs, lastWakeupElapsedTimeMs);          }          public void gpsScanStateChanged(int uid, WorkChain workChain, boolean stateOn) { @@ -1838,44 +1855,18 @@ public class BatteryStatsImpl extends BatteryStats {              FrameworkStatsLog.write(                      FrameworkStatsLog.PHONE_SIGNAL_STRENGTH_CHANGED, strengthBin);          } -    } - -    private final FrameworkStatsLogger mFrameworkStatsLogger; -    @VisibleForTesting -    public BatteryStatsImpl(Clock clock, File historyDirectory, @NonNull Handler handler, -            @NonNull PowerStatsUidResolver powerStatsUidResolver, -            @NonNull FrameworkStatsLogger frameworkStatsLogger, -            @NonNull BatteryStatsHistory.TraceDelegate traceDelegate, -            @NonNull BatteryStatsHistory.EventLogger eventLogger) { -        mClock = clock; -        initKernelStatsReaders(); -        mBatteryStatsConfig = new BatteryStatsConfig.Builder().build(); -        mHandler = handler; -        mPowerStatsUidResolver = powerStatsUidResolver; -        mFrameworkStatsLogger = frameworkStatsLogger; -        mConstants = new Constants(mHandler); -        mStartClockTimeMs = clock.currentTimeMillis(); -        mDailyFile = null; -        mMonotonicClock = new MonotonicClock(0, mClock); -        if (historyDirectory == null) { -            mCheckinFile = null; -            mStatsFile = null; -            mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_BUFFER, -                    mStepDetailsCalculator, mClock, mMonotonicClock, traceDelegate, eventLogger); -        } else { -            mCheckinFile = new AtomicFile(new File(historyDirectory, "batterystats-checkin.bin")); -            mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin")); -            mHistory = new BatteryStatsHistory(historyDirectory, mConstants.MAX_HISTORY_FILES, -                    mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock, mMonotonicClock, -                    traceDelegate, eventLogger); +        /** +         * Records a statsd event when the batterystats config file is written to disk. +         */ +        public void writeCommitSysConfigFile(String fileName, long durationMs) { +            com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(fileName, +                    durationMs);          } -        mPlatformIdleStateCallback = null; -        mEnergyConsumerRetriever = null; -        mUserInfoProvider = null; -        mCpuPowerStatsCollector = null;      } +    private final FrameworkStatsLogger mFrameworkStatsLogger; +      private void initKernelStatsReaders() {          if (!isKernelStatsAvailable()) {              return; @@ -1893,6 +1884,92 @@ public class BatteryStatsImpl extends BatteryStats {          mTmpRailStats = new RailStats();      } +    private class PowerStatsCollectorInjector implements CpuPowerStatsCollector.Injector, +            MobileRadioPowerStatsCollector.Injector { +        private PackageManager mPackageManager; +        private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever; +        private NetworkStatsManager mNetworkStatsManager; +        private TelephonyManager mTelephonyManager; + +        void setContext(Context context) { +            mPackageManager = context.getPackageManager(); +            mConsumedEnergyRetriever = new PowerStatsCollector.ConsumedEnergyRetrieverImpl( +                    LocalServices.getService(PowerStatsInternal.class)); +            mNetworkStatsManager = context.getSystemService(NetworkStatsManager.class); +            mTelephonyManager = context.getSystemService(TelephonyManager.class); +        } + +        @Override +        public Handler getHandler() { +            return mHandler; +        } + +        @Override +        public Clock getClock() { +            return mClock; +        } + +        @Override +        public PowerStatsUidResolver getUidResolver() { +            return mPowerStatsUidResolver; +        } + +        @Override +        public CpuScalingPolicies getCpuScalingPolicies() { +            return mCpuScalingPolicies; +        } + +        @Override +        public PowerProfile getPowerProfile() { +            return mPowerProfile; +        } + +        @Override +        public CpuPowerStatsCollector.KernelCpuStatsReader getKernelCpuStatsReader() { +            return new CpuPowerStatsCollector.KernelCpuStatsReader(); +        } + +        @Override +        public PackageManager getPackageManager() { +            return mPackageManager; +        } + +        @Override +        public PowerStatsCollector.ConsumedEnergyRetriever getConsumedEnergyRetriever() { +            return mConsumedEnergyRetriever; +        } + +        @Override +        public IntSupplier getVoltageSupplier() { +            return () -> mBatteryVoltageMv; +        } + +        @Override +        public Supplier<NetworkStats> getMobileNetworkStatsSupplier() { +            return () -> readMobileNetworkStatsLocked(mNetworkStatsManager); +        } + +        @Override +        public TelephonyManager getTelephonyManager() { +            return mTelephonyManager; +        } + +        @Override +        public LongSupplier getCallDurationSupplier() { +            return () -> mPhoneOnTimer.getTotalTimeLocked(mClock.elapsedRealtime() * 1000, +                    STATS_SINCE_CHARGED); +        } + +        @Override +        public LongSupplier getPhoneSignalScanDurationSupplier() { +            return () -> mPhoneSignalScanningTimer.getTotalTimeLocked( +                    mClock.elapsedRealtime() * 1000, STATS_SINCE_CHARGED); +        } +    } + +    private final PowerStatsCollectorInjector mPowerStatsCollectorInjector = +            new PowerStatsCollectorInjector(); +      /**       * TimeBase observer.       */ @@ -4849,8 +4926,9 @@ public class BatteryStatsImpl extends BatteryStats {              Uid uidStats = getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs);              uidStats.noteStartWakeLocked(pid, name, type, elapsedRealtimeMs); -            mFrameworkStatsLogger.wakelockStateChanged(mapIsolatedUid(uid), wc, name, type, -                    uidStats.mProcessState, true /* acquired */); +            mFrameworkStatsLogger.wakelockStateChanged(mapIsolatedUid(uid), wc, name, +                    uidStats.mProcessState, true /* acquired */, +                    getPowerManagerWakeLockLevel(type));          }      } @@ -4893,8 +4971,9 @@ public class BatteryStatsImpl extends BatteryStats {              Uid uidStats = getUidStatsLocked(mappedUid, elapsedRealtimeMs, uptimeMs);              uidStats.noteStopWakeLocked(pid, name, type, elapsedRealtimeMs); -            mFrameworkStatsLogger.wakelockStateChanged(mapIsolatedUid(uid), wc, name, type, -                    uidStats.mProcessState, false /* acquired */); +            mFrameworkStatsLogger.wakelockStateChanged(mapIsolatedUid(uid), wc, name, +                    uidStats.mProcessState, false/* acquired */, +                    getPowerManagerWakeLockLevel(type));              if (mappedUid != uid) {                  // Decrement the ref count for the isolated uid and delete the mapping if uneeded. @@ -4910,8 +4989,8 @@ public class BatteryStatsImpl extends BatteryStats {       * TODO: Delete this. Instead, FrameworkStatsLog.write should be called from       * PowerManager's Notifier.       */ -    private int getPowerManagerWakeLockLevel(int battertStatsWakelockType) { -        switch (battertStatsWakelockType) { +    private int getPowerManagerWakeLockLevel(int batteryStatsWakelockType) { +        switch (batteryStatsWakelockType) {              // PowerManager.PARTIAL_WAKE_LOCK or PROXIMITY_SCREEN_OFF_WAKE_LOCK              case BatteryStats.WAKE_TYPE_PARTIAL:                  return PowerManager.PARTIAL_WAKE_LOCK; @@ -4929,7 +5008,7 @@ public class BatteryStatsImpl extends BatteryStats {                  return -1;              default: -                Slog.e(TAG, "Illegal wakelock type in batterystats: " + battertStatsWakelockType); +                Slog.e(TAG, "Illegal wakelock type in batterystats: " + batteryStatsWakelockType);                  return -1;          }      } @@ -5131,7 +5210,8 @@ public class BatteryStatsImpl extends BatteryStats {              long deltaUptimeMs = uptimeMs - mLastWakeupUptimeMs;              SamplingTimer timer = getWakeupReasonTimerLocked(mLastWakeupReason);              timer.add(deltaUptimeMs * 1000, 1, elapsedRealtimeMs); // time in in microseconds -            mFrameworkStatsLogger.kernelWakeupReported(deltaUptimeMs * 1000); +            mFrameworkStatsLogger.kernelWakeupReported(deltaUptimeMs * 1000, mLastWakeupReason, +                    mLastWakeupElapsedTimeMs);              mLastWakeupReason = null;          }      } @@ -5738,16 +5818,19 @@ public class BatteryStatsImpl extends BatteryStats {                  mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);                  mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs); -                if (mLastModemActivityInfo != null) { -                    if (elapsedRealtimeMs < mLastModemActivityInfo.getTimestampMillis() +                if (mMobileRadioPowerStatsCollector.isEnabled()) { +                    mMobileRadioPowerStatsCollector.schedule(); +                } else { +                    // Check if modem Activity info has been collected recently, don't bother +                    // triggering another update. +                    if (mLastModemActivityInfo == null +                            || elapsedRealtimeMs >= mLastModemActivityInfo.getTimestampMillis()                              + MOBILE_RADIO_POWER_STATE_UPDATE_FREQ_MS) { -                        // Modem Activity info has been collected recently, don't bother -                        // triggering another update. -                        return false; +                        mExternalSync.scheduleSync("modem-data", +                                BatteryExternalStatsWorker.UPDATE_RADIO); +                        return true;                      }                  } -                // Tell the caller to collect radio network/power stats. -                return true;              }          }          return false; @@ -5915,6 +5998,7 @@ public class BatteryStatsImpl extends BatteryStats {              mPhoneOnTimer.startRunningLocked(elapsedRealtimeMs);              if (mConstants.PHONE_ON_EXTERNAL_STATS_COLLECTION) {                  scheduleSyncExternalStatsLocked("phone-on", ExternalStatsSync.UPDATE_RADIO); +                mMobileRadioPowerStatsCollector.schedule();              }          }      } @@ -5927,6 +6011,7 @@ public class BatteryStatsImpl extends BatteryStats {              mPhoneOn = false;              mPhoneOnTimer.stopRunningLocked(elapsedRealtimeMs);              scheduleSyncExternalStatsLocked("phone-off", ExternalStatsSync.UPDATE_RADIO); +            mMobileRadioPowerStatsCollector.schedule();          }      } @@ -6269,27 +6354,6 @@ public class BatteryStatsImpl extends BatteryStats {          }      } -    @RadioAccessTechnology -    private static int mapRadioAccessNetworkTypeToRadioAccessTechnology( -            @AccessNetworkConstants.RadioAccessNetworkType int dataType) { -        switch (dataType) { -            case AccessNetworkConstants.AccessNetworkType.NGRAN: -                return RADIO_ACCESS_TECHNOLOGY_NR; -            case AccessNetworkConstants.AccessNetworkType.EUTRAN: -                return RADIO_ACCESS_TECHNOLOGY_LTE; -            case AccessNetworkConstants.AccessNetworkType.UNKNOWN: //fallthrough -            case AccessNetworkConstants.AccessNetworkType.GERAN: //fallthrough -            case AccessNetworkConstants.AccessNetworkType.UTRAN: //fallthrough -            case AccessNetworkConstants.AccessNetworkType.CDMA2000: //fallthrough -            case AccessNetworkConstants.AccessNetworkType.IWLAN: -                return RADIO_ACCESS_TECHNOLOGY_OTHER; -            default: -                Slog.w(TAG, -                        "Unhandled RadioAccessNetworkType (" + dataType + "), mapping to OTHER"); -                return RADIO_ACCESS_TECHNOLOGY_OTHER; -        } -    } -      @GuardedBy("this")      public void noteWifiOnLocked(long elapsedRealtimeMs, long uptimeMs) {          if (!mWifiOn) { @@ -8311,7 +8375,7 @@ public class BatteryStatsImpl extends BatteryStats {          @GuardedBy("mBsi")          private void ensureMultiStateCounters(long timestampMs) { -            if (mBsi.mPowerStatsCollectorEnabled) { +            if (mBsi.mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_CPU)) {                  throw new IllegalStateException("Multi-state counters used in streamlined mode");              } @@ -10612,7 +10676,8 @@ public class BatteryStatsImpl extends BatteryStats {                      mProcessStateTimer[uidRunningState].startRunningLocked(elapsedRealtimeMs);                  } -                if (!mBsi.mPowerStatsCollectorEnabled && mBsi.trackPerProcStateCpuTimes()) { +                if (!mBsi.mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_CPU) +                        && mBsi.trackPerProcStateCpuTimes()) {                      mBsi.updateProcStateCpuTimesLocked(mUid, elapsedRealtimeMs, uptimeMs);                      LongArrayMultiStateCounter onBatteryCounter = @@ -10634,7 +10699,8 @@ public class BatteryStatsImpl extends BatteryStats {                  final int batteryConsumerProcessState =                          mapUidProcessStateToBatteryConsumerProcessState(uidRunningState); -                if (mBsi.mSystemReady && mBsi.mPowerStatsCollectorEnabled) { +                if (mBsi.mSystemReady && mBsi.mPowerStatsCollectorEnabled.get( +                        BatteryConsumer.POWER_COMPONENT_CPU)) {                      mBsi.mHistory.recordProcessStateChange(elapsedRealtimeMs, uptimeMs, mUid,                              batteryConsumerProcessState);                  } @@ -10982,11 +11048,27 @@ public class BatteryStatsImpl extends BatteryStats {      public BatteryStatsImpl(@NonNull BatteryStatsConfig config, @NonNull Clock clock,              @NonNull MonotonicClock monotonicClock, @Nullable File systemDir, -            @NonNull Handler handler, @Nullable PlatformIdleStateCallback cb, -            @Nullable EnergyStatsRetriever energyStatsCb, +            @NonNull Handler handler, @Nullable PlatformIdleStateCallback platformIdleStateCallback, +            @Nullable EnergyStatsRetriever energyStatsRetriever,              @NonNull UserInfoProvider userInfoProvider, @NonNull PowerProfile powerProfile,              @NonNull CpuScalingPolicies cpuScalingPolicies,              @NonNull PowerStatsUidResolver powerStatsUidResolver) { +        this(config, clock, monotonicClock, systemDir, handler, platformIdleStateCallback, +                energyStatsRetriever, userInfoProvider, powerProfile, cpuScalingPolicies, +                powerStatsUidResolver, new FrameworkStatsLogger(), +                new BatteryStatsHistory.TraceDelegate(), new BatteryStatsHistory.EventLogger()); +    } + +    public BatteryStatsImpl(@NonNull BatteryStatsConfig config, @NonNull Clock clock, +            @NonNull MonotonicClock monotonicClock, @Nullable File systemDir, +            @NonNull Handler handler, @Nullable PlatformIdleStateCallback platformIdleStateCallback, +            @Nullable EnergyStatsRetriever energyStatsRetriever, +            @NonNull UserInfoProvider userInfoProvider, @NonNull PowerProfile powerProfile, +            @NonNull CpuScalingPolicies cpuScalingPolicies, +            @NonNull PowerStatsUidResolver powerStatsUidResolver, +            @NonNull FrameworkStatsLogger frameworkStatsLogger, +            @NonNull BatteryStatsHistory.TraceDelegate traceDelegate, +            @NonNull BatteryStatsHistory.EventLogger eventLogger) {          mClock = clock;          initKernelStatsReaders(); @@ -10998,29 +11080,34 @@ public class BatteryStatsImpl extends BatteryStats {          mPowerProfile = powerProfile;          mCpuScalingPolicies = cpuScalingPolicies;          mPowerStatsUidResolver = powerStatsUidResolver; -        mFrameworkStatsLogger = new FrameworkStatsLogger(); +        mFrameworkStatsLogger = frameworkStatsLogger;          initPowerProfile(); -        if (systemDir == null) { -            mStatsFile = null; -            mCheckinFile = null; -            mDailyFile = null; -            mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_BUFFER, -                    mStepDetailsCalculator, mClock, mMonotonicClock); -        } else { +        if (systemDir != null) {              mStatsFile = new AtomicFile(new File(systemDir, "batterystats.bin"));              mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));              mDailyFile = new AtomicFile(new File(systemDir, "batterystats-daily.xml")); -            mHistory = new BatteryStatsHistory(systemDir, mConstants.MAX_HISTORY_FILES, -                    mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock, mMonotonicClock); +        } else { +            mStatsFile = null; +            mCheckinFile = null; +            mDailyFile = null;          } -        mCpuPowerStatsCollector = new CpuPowerStatsCollector(mCpuScalingPolicies, mPowerProfile, -                mPowerStatsUidResolver, () -> mBatteryVoltageMv, mHandler, -                mBatteryStatsConfig.getPowerStatsThrottlePeriodCpu()); +        mHistory = new BatteryStatsHistory(null /* historyBuffer */, systemDir, +                mConstants.MAX_HISTORY_FILES, mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, +                mClock, mMonotonicClock, traceDelegate, eventLogger); + +        mCpuPowerStatsCollector = new CpuPowerStatsCollector(mPowerStatsCollectorInjector, +                mBatteryStatsConfig.getPowerStatsThrottlePeriod( +                        BatteryConsumer.POWER_COMPONENT_CPU));          mCpuPowerStatsCollector.addConsumer(this::recordPowerStats); +        mMobileRadioPowerStatsCollector = new MobileRadioPowerStatsCollector( +                mPowerStatsCollectorInjector, mBatteryStatsConfig.getPowerStatsThrottlePeriod( +                BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)); +        mMobileRadioPowerStatsCollector.addConsumer(this::recordPowerStats); +          mStartCount++;          initTimersAndCounters();          mOnBattery = mOnBatteryInternal = false; @@ -11030,8 +11117,8 @@ public class BatteryStatsImpl extends BatteryStats {          mStartPlatformVersion = mEndPlatformVersion = Build.ID;          initDischarge(realtimeUs);          updateDailyDeadlineLocked(); -        mPlatformIdleStateCallback = cb; -        mEnergyConsumerRetriever = energyStatsCb; +        mPlatformIdleStateCallback = platformIdleStateCallback; +        mEnergyConsumerRetriever = energyStatsRetriever;          mUserInfoProvider = userInfoProvider;          mPowerStatsUidResolver.addListener(new PowerStatsUidResolver.Listener() { @@ -11296,8 +11383,7 @@ public class BatteryStatsImpl extends BatteryStats {                                  memStream.writeTo(stream);                                  stream.flush();                                  mDailyFile.finishWrite(stream); -                                com.android.internal.logging.EventLogTags.writeCommitSysConfigFile( -                                        "batterystats-daily", +                                mFrameworkStatsLogger.writeCommitSysConfigFile("batterystats-daily",                                          initialTimeMs + SystemClock.uptimeMillis() - startTimeMs2);                              } catch (IOException e) {                                  Slog.w("BatteryStats", @@ -11809,7 +11895,7 @@ public class BatteryStatsImpl extends BatteryStats {          // Store the empty state to disk to ensure consistency          writeSyncLocked(); -        if (mPowerStatsCollectorEnabled) { +        if (mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_CPU)) {              schedulePowerStatsSampleCollection();          } @@ -11953,7 +12039,7 @@ public class BatteryStatsImpl extends BatteryStats {          return networkStatsManager.getWifiUidStats();      } -    private static class NetworkStatsDelta { +    static class NetworkStatsDelta {          int mUid;          int mSet;          long mRxBytes; @@ -11985,9 +12071,16 @@ public class BatteryStatsImpl extends BatteryStats {          public long getTxPackets() {              return mTxPackets;          } + +        @Override +        public String toString() { +            return "NetworkStatsDelta{mUid=" + mUid + ", mSet=" + mSet + ", mRxBytes=" + mRxBytes +                    + ", mRxPackets=" + mRxPackets + ", mTxBytes=" + mTxBytes + ", mTxPackets=" +                    + mTxPackets + '}'; +        }      } -    private List<NetworkStatsDelta> computeDelta(NetworkStats currentStats, +    static List<NetworkStatsDelta> computeDelta(NetworkStats currentStats,              NetworkStats lastStats) {          List<NetworkStatsDelta> deltaList = new ArrayList<>();          for (NetworkStats.Entry entry : currentStats) { @@ -12418,13 +12511,11 @@ public class BatteryStatsImpl extends BatteryStats {          addModemTxPowerToHistory(deltaInfo, elapsedRealtimeMs, uptimeMs);          // Grab a separate lock to acquire the network stats, which may do I/O. -        NetworkStats delta = null; +        List<NetworkStatsDelta> delta = null;          synchronized (mModemNetworkLock) {              final NetworkStats latestStats = readMobileNetworkStatsLocked(networkStatsManager);              if (latestStats != null) { -                delta = latestStats.subtract(mLastModemNetworkStats != null -                        ? mLastModemNetworkStats -                        : new NetworkStats(0, -1)); +                delta = computeDelta(latestStats, mLastModemNetworkStats);                  mLastModemNetworkStats = latestStats;              }          } @@ -12527,7 +12618,7 @@ public class BatteryStatsImpl extends BatteryStats {              long totalRxPackets = 0;              long totalTxPackets = 0;              if (delta != null) { -                for (NetworkStats.Entry entry : delta) { +                for (NetworkStatsDelta entry : delta) {                      if (entry.getRxPackets() == 0 && entry.getTxPackets() == 0) {                          continue;                      } @@ -12568,7 +12659,7 @@ public class BatteryStatsImpl extends BatteryStats {                  // Now distribute proportional blame to the apps that did networking.                  long totalPackets = totalRxPackets + totalTxPackets;                  if (totalPackets > 0) { -                    for (NetworkStats.Entry entry : delta) { +                    for (NetworkStatsDelta entry : delta) {                          if (entry.getRxPackets() == 0 && entry.getTxPackets() == 0) {                              continue;                          } @@ -14408,17 +14499,41 @@ public class BatteryStatsImpl extends BatteryStats {      /**       * Notifies BatteryStatsImpl that the system server is ready.       */ -    public void onSystemReady() { +    public void onSystemReady(Context context) {          if (mCpuUidFreqTimeReader != null) {              mCpuUidFreqTimeReader.onSystemReady();          } -        if (mCpuPowerStatsCollector != null) { -            mCpuPowerStatsCollector.setEnabled(mPowerStatsCollectorEnabled); -        } + +        mPowerStatsCollectorInjector.setContext(context); + +        mCpuPowerStatsCollector.setEnabled( +                mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_CPU)); +        mCpuPowerStatsCollector.schedule(); + +        mMobileRadioPowerStatsCollector.setEnabled( +                mPowerStatsCollectorEnabled.get(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)); +        mMobileRadioPowerStatsCollector.schedule(); +          mSystemReady = true;      }      /** +     * Returns a PowerStatsCollector for the specified power component or null if unavailable. +     */ +    @Nullable +    PowerStatsCollector getPowerStatsCollector( +            @BatteryConsumer.PowerComponent int powerComponent) { +        switch (powerComponent) { +            case BatteryConsumer.POWER_COMPONENT_CPU: +                return mCpuPowerStatsCollector; +            case BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO: +                return mMobileRadioPowerStatsCollector; +        } +        return null; +    } + + +    /**       * Force recording of all history events regardless of the "charging" state.       */      @VisibleForTesting @@ -14561,9 +14676,10 @@ public class BatteryStatsImpl extends BatteryStats {                                      stream.write(parcel.marshall());                                      stream.flush();                                      mCheckinFile.finishWrite(stream); -                                    com.android.internal.logging.EventLogTags.writeCommitSysConfigFile( -                                            "batterystats-checkin", initialTimeMs -                                            + SystemClock.uptimeMillis() - startTimeMs2); +                                    mFrameworkStatsLogger.writeCommitSysConfigFile( +                                            "batterystats-checkin", +                                            initialTimeMs + SystemClock.uptimeMillis() +                                                    - startTimeMs2);                                  } catch (IOException e) {                                      Slog.w("BatteryStats",                                              "Error writing checkin battery statistics", e); @@ -15437,9 +15553,10 @@ public class BatteryStatsImpl extends BatteryStats {      /**       * Enables or disables the PowerStatsCollector mode.       */ -    public void setPowerStatsCollectorEnabled(boolean enabled) { +    public void setPowerStatsCollectorEnabled(@BatteryConsumer.PowerComponent int powerComponent, +            boolean enabled) {          synchronized (this) { -            mPowerStatsCollectorEnabled = enabled; +            mPowerStatsCollectorEnabled.put(powerComponent, enabled);          }      } @@ -15944,10 +16061,8 @@ public class BatteryStatsImpl extends BatteryStats {       * Callers will need to wait for the collection to complete on the handler thread.       */      public void schedulePowerStatsSampleCollection() { -        if (mCpuPowerStatsCollector == null) { -            return; -        }          mCpuPowerStatsCollector.forceSchedule(); +        mMobileRadioPowerStatsCollector.forceSchedule();      }      /** @@ -15965,6 +16080,7 @@ public class BatteryStatsImpl extends BatteryStats {       */      public void dumpStatsSample(PrintWriter pw) {          mCpuPowerStatsCollector.collectAndDump(pw); +        mMobileRadioPowerStatsCollector.collectAndDump(pw);      }      private final Runnable mWriteAsyncRunnable = () -> { @@ -16036,7 +16152,7 @@ public class BatteryStatsImpl extends BatteryStats {                          + " duration ms:" + (SystemClock.uptimeMillis() - startTimeMs)                          + " bytes:" + p.dataSize());              } -            com.android.internal.logging.EventLogTags.writeCommitSysConfigFile( +            mFrameworkStatsLogger.writeCommitSysConfigFile(                      "batterystats", SystemClock.uptimeMillis() - startTimeMs);          } catch (IOException e) {              Slog.w(TAG, "Error writing battery statistics", e); @@ -17262,10 +17378,8 @@ public class BatteryStatsImpl extends BatteryStats {              pw.println();              dumpConstantsLocked(pw); -            if (mCpuPowerStatsCollector != null) { -                pw.println(); -                mCpuPowerStatsCollector.dumpCpuPowerBracketsLocked(pw); -            } +            pw.println(); +            mCpuPowerStatsCollector.dumpCpuPowerBracketsLocked(pw);              pw.println();              dumpEnergyConsumerStatsLocked(pw); diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java index 30b80ae781ff..97f09865beeb 100644 --- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java +++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java @@ -27,6 +27,7 @@ import android.os.UidBatteryConsumer;  import android.util.Log;  import android.util.Slog;  import android.util.SparseArray; +import android.util.SparseBooleanArray;  import com.android.internal.os.Clock;  import com.android.internal.os.CpuScalingPolicies; @@ -43,7 +44,7 @@ import java.util.List;  public class BatteryUsageStatsProvider {      private static final String TAG = "BatteryUsageStatsProv";      private final Context mContext; -    private boolean mPowerStatsExporterEnabled; +    private final SparseBooleanArray mPowerStatsExporterEnabled = new SparseBooleanArray();      private final PowerStatsExporter mPowerStatsExporter;      private final PowerStatsStore mPowerStatsStore;      private final PowerProfile mPowerProfile; @@ -71,14 +72,20 @@ public class BatteryUsageStatsProvider {                  // Power calculators are applied in the order of registration                  mPowerCalculators.add(new BatteryChargeCalculator()); -                if (!mPowerStatsExporterEnabled) { +                if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_CPU)) {                      mPowerCalculators.add(                              new CpuPowerCalculator(mCpuScalingPolicies, mPowerProfile));                  }                  mPowerCalculators.add(new MemoryPowerCalculator(mPowerProfile));                  mPowerCalculators.add(new WakelockPowerCalculator(mPowerProfile));                  if (!BatteryStats.checkWifiOnly(mContext)) { -                    mPowerCalculators.add(new MobileRadioPowerCalculator(mPowerProfile)); +                    if (!mPowerStatsExporterEnabled.get( +                            BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) { +                        mPowerCalculators.add(new MobileRadioPowerCalculator(mPowerProfile)); +                    } +                    if (!mPowerStatsExporterEnabled.get(BatteryConsumer.POWER_COMPONENT_PHONE)) { +                        mPowerCalculators.add(new PhonePowerCalculator(mPowerProfile)); +                    }                  }                  mPowerCalculators.add(new WifiPowerCalculator(mPowerProfile));                  mPowerCalculators.add(new BluetoothPowerCalculator(mPowerProfile)); @@ -89,7 +96,6 @@ public class BatteryUsageStatsProvider {                  mPowerCalculators.add(new FlashlightPowerCalculator(mPowerProfile));                  mPowerCalculators.add(new AudioPowerCalculator(mPowerProfile));                  mPowerCalculators.add(new VideoPowerCalculator(mPowerProfile)); -                mPowerCalculators.add(new PhonePowerCalculator(mPowerProfile));                  mPowerCalculators.add(new ScreenPowerCalculator(mPowerProfile));                  mPowerCalculators.add(new AmbientDisplayPowerCalculator(mPowerProfile));                  mPowerCalculators.add(new IdlePowerCalculator(mPowerProfile)); @@ -228,7 +234,7 @@ public class BatteryUsageStatsProvider {              }          } -        if (mPowerStatsExporterEnabled) { +        if (mPowerStatsExporterEnabled.indexOfValue(true) >= 0) {              mPowerStatsExporter.exportAggregatedPowerStats(batteryUsageStatsBuilder,                      monotonicStartTime, monotonicEndTime);          } @@ -393,7 +399,10 @@ public class BatteryUsageStatsProvider {          return builder.build();      } -    public void setPowerStatsExporterEnabled(boolean enabled) { -        mPowerStatsExporterEnabled = enabled; +    /** +     * Specify whether PowerStats based attribution is supported for the specified component. +     */ +    public void setPowerStatsExporterEnabled(int powerComponentId, boolean enabled) { +        mPowerStatsExporterEnabled.put(powerComponentId, enabled);      }  } diff --git a/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java index 1af127175f80..b1b2cc91d379 100644 --- a/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java +++ b/services/core/java/com/android/server/power/stats/CpuPowerStatsCollector.java @@ -16,14 +16,11 @@  package com.android.server.power.stats; -import android.hardware.power.stats.EnergyConsumer; -import android.hardware.power.stats.EnergyConsumerResult;  import android.hardware.power.stats.EnergyConsumerType;  import android.os.BatteryConsumer;  import android.os.Handler;  import android.os.PersistableBundle;  import android.os.Process; -import android.power.PowerStatsInternal;  import android.util.Slog;  import android.util.SparseArray; @@ -34,20 +31,11 @@ import com.android.internal.os.Clock;  import com.android.internal.os.CpuScalingPolicies;  import com.android.internal.os.PowerProfile;  import com.android.internal.os.PowerStats; -import com.android.server.LocalServices;  import java.io.PrintWriter; -import java.util.ArrayList;  import java.util.Arrays; -import java.util.Comparator; -import java.util.List;  import java.util.Locale; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException;  import java.util.function.IntSupplier; -import java.util.function.Supplier;  /**   * Collects snapshots of power-related system statistics. @@ -63,213 +51,54 @@ public class CpuPowerStatsCollector extends PowerStatsCollector {      private static final int DEFAULT_CPU_POWER_BRACKETS_PER_ENERGY_CONSUMER = 2;      private static final long POWER_STATS_ENERGY_CONSUMERS_TIMEOUT = 20000; +    interface Injector { +        Handler getHandler(); +        Clock getClock(); +        PowerStatsUidResolver getUidResolver(); +        CpuScalingPolicies getCpuScalingPolicies(); +        PowerProfile getPowerProfile(); +        KernelCpuStatsReader getKernelCpuStatsReader(); +        ConsumedEnergyRetriever getConsumedEnergyRetriever(); +        IntSupplier getVoltageSupplier(); + +        default int getDefaultCpuPowerBrackets() { +            return DEFAULT_CPU_POWER_BRACKETS; +        } + +        default int getDefaultCpuPowerBracketsPerEnergyConsumer() { +            return DEFAULT_CPU_POWER_BRACKETS_PER_ENERGY_CONSUMER; +        } +    } + +    private final Injector mInjector; +      private boolean mIsInitialized; -    private final CpuScalingPolicies mCpuScalingPolicies; -    private final PowerProfile mPowerProfile; -    private final KernelCpuStatsReader mKernelCpuStatsReader; -    private final PowerStatsUidResolver mUidResolver; -    private final Supplier<PowerStatsInternal> mPowerStatsSupplier; -    private final IntSupplier mVoltageSupplier; -    private final int mDefaultCpuPowerBrackets; -    private final int mDefaultCpuPowerBracketsPerEnergyConsumer; +    private CpuScalingPolicies mCpuScalingPolicies; +    private PowerProfile mPowerProfile; +    private KernelCpuStatsReader mKernelCpuStatsReader; +    private PowerStatsUidResolver mUidResolver; +    private ConsumedEnergyRetriever mConsumedEnergyRetriever; +    private IntSupplier mVoltageSupplier; +    private int mDefaultCpuPowerBrackets; +    private int mDefaultCpuPowerBracketsPerEnergyConsumer;      private long[] mCpuTimeByScalingStep;      private long[] mTempCpuTimeByScalingStep;      private long[] mTempUidStats;      private final SparseArray<UidStats> mUidStats = new SparseArray<>();      private boolean mIsPerUidTimeInStateSupported; -    private PowerStatsInternal mPowerStatsInternal;      private int[] mCpuEnergyConsumerIds = new int[0];      private PowerStats.Descriptor mPowerStatsDescriptor;      // Reusable instance      private PowerStats mCpuPowerStats; -    private CpuStatsArrayLayout mLayout; +    private CpuPowerStatsLayout mLayout;      private long mLastUpdateTimestampNanos;      private long mLastUpdateUptimeMillis;      private int mLastVoltageMv;      private long[] mLastConsumedEnergyUws; -    /** -     * Captures the positions and lengths of sections of the stats array, such as time-in-state, -     * power usage estimates etc. -     */ -    public static class CpuStatsArrayLayout extends StatsArrayLayout { -        private static final String EXTRA_DEVICE_TIME_BY_SCALING_STEP_POSITION = "dt"; -        private static final String EXTRA_DEVICE_TIME_BY_SCALING_STEP_COUNT = "dtc"; -        private static final String EXTRA_DEVICE_TIME_BY_CLUSTER_POSITION = "dc"; -        private static final String EXTRA_DEVICE_TIME_BY_CLUSTER_COUNT = "dcc"; -        private static final String EXTRA_UID_BRACKETS_POSITION = "ub"; -        private static final String EXTRA_UID_STATS_SCALING_STEP_TO_POWER_BRACKET = "us"; - -        private int mDeviceCpuTimeByScalingStepPosition; -        private int mDeviceCpuTimeByScalingStepCount; -        private int mDeviceCpuTimeByClusterPosition; -        private int mDeviceCpuTimeByClusterCount; - -        private int mUidPowerBracketsPosition; -        private int mUidPowerBracketCount; - -        private int[] mScalingStepToPowerBracketMap; - -        /** -         * Declare that the stats array has a section capturing CPU time per scaling step -         */ -        public void addDeviceSectionCpuTimeByScalingStep(int scalingStepCount) { -            mDeviceCpuTimeByScalingStepPosition = addDeviceSection(scalingStepCount); -            mDeviceCpuTimeByScalingStepCount = scalingStepCount; -        } - -        public int getCpuScalingStepCount() { -            return mDeviceCpuTimeByScalingStepCount; -        } - -        /** -         * Saves the time duration in the <code>stats</code> element -         * corresponding to the CPU scaling <code>state</code>. -         */ -        public void setTimeByScalingStep(long[] stats, int step, long value) { -            stats[mDeviceCpuTimeByScalingStepPosition + step] = value; -        } - -        /** -         * Extracts the time duration from the <code>stats</code> element -         * corresponding to the CPU scaling <code>step</code>. -         */ -        public long getTimeByScalingStep(long[] stats, int step) { -            return stats[mDeviceCpuTimeByScalingStepPosition + step]; -        } - -        /** -         * Declare that the stats array has a section capturing CPU time in each cluster -         */ -        public void addDeviceSectionCpuTimeByCluster(int clusterCount) { -            mDeviceCpuTimeByClusterPosition = addDeviceSection(clusterCount); -            mDeviceCpuTimeByClusterCount = clusterCount; -        } - -        public int getCpuClusterCount() { -            return mDeviceCpuTimeByClusterCount; -        } - -        /** -         * Saves the time duration in the <code>stats</code> element -         * corresponding to the CPU <code>cluster</code>. -         */ -        public void setTimeByCluster(long[] stats, int cluster, long value) { -            stats[mDeviceCpuTimeByClusterPosition + cluster] = value; -        } - -        /** -         * Extracts the time duration from the <code>stats</code> element -         * corresponding to the CPU <code>cluster</code>. -         */ -        public long getTimeByCluster(long[] stats, int cluster) { -            return stats[mDeviceCpuTimeByClusterPosition + cluster]; -        } - -        /** -         * Declare that the UID stats array has a section capturing CPU time per power bracket. -         */ -        public void addUidSectionCpuTimeByPowerBracket(int[] scalingStepToPowerBracketMap) { -            mScalingStepToPowerBracketMap = scalingStepToPowerBracketMap; -            updatePowerBracketCount(); -            mUidPowerBracketsPosition = addUidSection(mUidPowerBracketCount); -        } - -        private void updatePowerBracketCount() { -            mUidPowerBracketCount = 1; -            for (int bracket : mScalingStepToPowerBracketMap) { -                if (bracket >= mUidPowerBracketCount) { -                    mUidPowerBracketCount = bracket + 1; -                } -            } -        } - -        public int[] getScalingStepToPowerBracketMap() { -            return mScalingStepToPowerBracketMap; -        } - -        public int getCpuPowerBracketCount() { -            return mUidPowerBracketCount; -        } - -        /** -         * Saves time in <code>bracket</code> in the corresponding section of <code>stats</code>. -         */ -        public void setUidTimeByPowerBracket(long[] stats, int bracket, long value) { -            stats[mUidPowerBracketsPosition + bracket] = value; -        } - -        /** -         * Extracts the time in <code>bracket</code> from a UID stats array. -         */ -        public long getUidTimeByPowerBracket(long[] stats, int bracket) { -            return stats[mUidPowerBracketsPosition + bracket]; -        } - -        /** -         * Copies the elements of the stats array layout into <code>extras</code> -         */ -        public void toExtras(PersistableBundle extras) { -            super.toExtras(extras); -            extras.putInt(EXTRA_DEVICE_TIME_BY_SCALING_STEP_POSITION, -                    mDeviceCpuTimeByScalingStepPosition); -            extras.putInt(EXTRA_DEVICE_TIME_BY_SCALING_STEP_COUNT, -                    mDeviceCpuTimeByScalingStepCount); -            extras.putInt(EXTRA_DEVICE_TIME_BY_CLUSTER_POSITION, -                    mDeviceCpuTimeByClusterPosition); -            extras.putInt(EXTRA_DEVICE_TIME_BY_CLUSTER_COUNT, -                    mDeviceCpuTimeByClusterCount); -            extras.putInt(EXTRA_UID_BRACKETS_POSITION, mUidPowerBracketsPosition); -            putIntArray(extras, EXTRA_UID_STATS_SCALING_STEP_TO_POWER_BRACKET, -                    mScalingStepToPowerBracketMap); -        } - -        /** -         * Retrieves elements of the stats array layout from <code>extras</code> -         */ -        public void fromExtras(PersistableBundle extras) { -            super.fromExtras(extras); -            mDeviceCpuTimeByScalingStepPosition = -                    extras.getInt(EXTRA_DEVICE_TIME_BY_SCALING_STEP_POSITION); -            mDeviceCpuTimeByScalingStepCount = -                    extras.getInt(EXTRA_DEVICE_TIME_BY_SCALING_STEP_COUNT); -            mDeviceCpuTimeByClusterPosition = -                    extras.getInt(EXTRA_DEVICE_TIME_BY_CLUSTER_POSITION); -            mDeviceCpuTimeByClusterCount = -                    extras.getInt(EXTRA_DEVICE_TIME_BY_CLUSTER_COUNT); -            mUidPowerBracketsPosition = extras.getInt(EXTRA_UID_BRACKETS_POSITION); -            mScalingStepToPowerBracketMap = -                    getIntArray(extras, EXTRA_UID_STATS_SCALING_STEP_TO_POWER_BRACKET); -            if (mScalingStepToPowerBracketMap == null) { -                mScalingStepToPowerBracketMap = new int[mDeviceCpuTimeByScalingStepCount]; -            } -            updatePowerBracketCount(); -        } -    } - -    public CpuPowerStatsCollector(CpuScalingPolicies cpuScalingPolicies, PowerProfile powerProfile, -            PowerStatsUidResolver uidResolver, IntSupplier voltageSupplier, Handler handler, -            long throttlePeriodMs) { -        this(cpuScalingPolicies, powerProfile, handler, new KernelCpuStatsReader(), uidResolver, -                () -> LocalServices.getService(PowerStatsInternal.class), voltageSupplier, -                throttlePeriodMs, Clock.SYSTEM_CLOCK, DEFAULT_CPU_POWER_BRACKETS, -                DEFAULT_CPU_POWER_BRACKETS_PER_ENERGY_CONSUMER); -    } - -    public CpuPowerStatsCollector(CpuScalingPolicies cpuScalingPolicies, PowerProfile powerProfile, -            Handler handler, KernelCpuStatsReader kernelCpuStatsReader, -            PowerStatsUidResolver uidResolver, Supplier<PowerStatsInternal> powerStatsSupplier, -            IntSupplier voltageSupplier, long throttlePeriodMs, Clock clock, -            int defaultCpuPowerBrackets, int defaultCpuPowerBracketsPerEnergyConsumer) { -        super(handler, throttlePeriodMs, clock); -        mCpuScalingPolicies = cpuScalingPolicies; -        mPowerProfile = powerProfile; -        mKernelCpuStatsReader = kernelCpuStatsReader; -        mUidResolver = uidResolver; -        mPowerStatsSupplier = powerStatsSupplier; -        mVoltageSupplier = voltageSupplier; -        mDefaultCpuPowerBrackets = defaultCpuPowerBrackets; -        mDefaultCpuPowerBracketsPerEnergyConsumer = defaultCpuPowerBracketsPerEnergyConsumer; +    public CpuPowerStatsCollector(Injector injector, long throttlePeriodMs) { +        super(injector.getHandler(), throttlePeriodMs, injector.getClock()); +        mInjector = injector;      }      private boolean ensureInitialized() { @@ -281,19 +110,28 @@ public class CpuPowerStatsCollector extends PowerStatsCollector {              return false;          } -        mIsPerUidTimeInStateSupported = mKernelCpuStatsReader.nativeIsSupportedFeature(); -        mPowerStatsInternal = mPowerStatsSupplier.get(); - -        if (mPowerStatsInternal != null) { -            readCpuEnergyConsumerIds(); -        } +        mCpuScalingPolicies = mInjector.getCpuScalingPolicies(); +        mPowerProfile = mInjector.getPowerProfile(); +        mKernelCpuStatsReader = mInjector.getKernelCpuStatsReader(); +        mUidResolver = mInjector.getUidResolver(); +        mConsumedEnergyRetriever = mInjector.getConsumedEnergyRetriever(); +        mVoltageSupplier = mInjector.getVoltageSupplier(); +        mDefaultCpuPowerBrackets = mInjector.getDefaultCpuPowerBrackets(); +        mDefaultCpuPowerBracketsPerEnergyConsumer = +                mInjector.getDefaultCpuPowerBracketsPerEnergyConsumer(); + +        mIsPerUidTimeInStateSupported = mKernelCpuStatsReader.isSupportedFeature(); +        mCpuEnergyConsumerIds = +                mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.CPU_CLUSTER); +        mLastConsumedEnergyUws = new long[mCpuEnergyConsumerIds.length]; +        Arrays.fill(mLastConsumedEnergyUws, ENERGY_UNSPECIFIED);          int cpuScalingStepCount = mCpuScalingPolicies.getScalingStepCount();          mCpuTimeByScalingStep = new long[cpuScalingStepCount];          mTempCpuTimeByScalingStep = new long[cpuScalingStepCount];          int[] scalingStepToPowerBracketMap = initPowerBrackets(); -        mLayout = new CpuStatsArrayLayout(); +        mLayout = new CpuPowerStatsLayout();          mLayout.addDeviceSectionCpuTimeByScalingStep(cpuScalingStepCount);          mLayout.addDeviceSectionCpuTimeByCluster(mCpuScalingPolicies.getPolicies().length);          mLayout.addDeviceSectionUsageDuration(); @@ -306,7 +144,8 @@ public class CpuPowerStatsCollector extends PowerStatsCollector {          mLayout.toExtras(extras);          mPowerStatsDescriptor = new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_CPU, -                mLayout.getDeviceStatsArrayLength(), mLayout.getUidStatsArrayLength(), extras); +                mLayout.getDeviceStatsArrayLength(), /* stateLabels */null, +                /* stateStatsArrayLength */ 0, mLayout.getUidStatsArrayLength(), extras);          mCpuPowerStats = new PowerStats(mPowerStatsDescriptor);          mTempUidStats = new long[mLayout.getCpuPowerBracketCount()]; @@ -315,32 +154,6 @@ public class CpuPowerStatsCollector extends PowerStatsCollector {          return true;      } -    private void readCpuEnergyConsumerIds() { -        EnergyConsumer[] energyConsumerInfo = mPowerStatsInternal.getEnergyConsumerInfo(); -        if (energyConsumerInfo == null) { -            return; -        } - -        List<EnergyConsumer> cpuEnergyConsumers = new ArrayList<>(); -        for (EnergyConsumer energyConsumer : energyConsumerInfo) { -            if (energyConsumer.type == EnergyConsumerType.CPU_CLUSTER) { -                cpuEnergyConsumers.add(energyConsumer); -            } -        } -        if (cpuEnergyConsumers.isEmpty()) { -            return; -        } - -        cpuEnergyConsumers.sort(Comparator.comparing(c -> c.ordinal)); - -        mCpuEnergyConsumerIds = new int[cpuEnergyConsumers.size()]; -        for (int i = 0; i < mCpuEnergyConsumerIds.length; i++) { -            mCpuEnergyConsumerIds[i] = cpuEnergyConsumers.get(i).id; -        } -        mLastConsumedEnergyUws = new long[cpuEnergyConsumers.size()]; -        Arrays.fill(mLastConsumedEnergyUws, ENERGY_UNSPECIFIED); -    } -      private int[] initPowerBrackets() {          if (mPowerProfile.getCpuPowerBracketCount() != PowerProfile.POWER_BRACKETS_UNSPECIFIED) {              return initPowerBracketsFromPowerProfile(); @@ -372,6 +185,7 @@ public class CpuPowerStatsCollector extends PowerStatsCollector {          return stepToBracketMap;      } +      private int[] initPowerBracketsByCluster(int defaultBracketCountPerCluster) {          int[] stepToBracketMap = new int[mCpuScalingPolicies.getScalingStepCount()];          int index = 0; @@ -531,7 +345,7 @@ public class CpuPowerStatsCollector extends PowerStatsCollector {          mCpuPowerStats.uidStats.clear();          // TODO(b/305120724): additionally retrieve time-in-cluster for each CPU cluster -        long newTimestampNanos = mKernelCpuStatsReader.nativeReadCpuStats(this::processUidStats, +        long newTimestampNanos = mKernelCpuStatsReader.readCpuStats(this::processUidStats,                  mLayout.getScalingStepToPowerBracketMap(), mLastUpdateTimestampNanos,                  mTempCpuTimeByScalingStep, mTempUidStats);          for (int step = mLayout.getCpuScalingStepCount() - 1; step >= 0; step--) { @@ -571,35 +385,20 @@ public class CpuPowerStatsCollector extends PowerStatsCollector {          int averageVoltage = mLastVoltageMv != 0 ? (mLastVoltageMv + voltageMv) / 2 : voltageMv;          mLastVoltageMv = voltageMv; -        CompletableFuture<EnergyConsumerResult[]> future = -                mPowerStatsInternal.getEnergyConsumedAsync(mCpuEnergyConsumerIds); -        EnergyConsumerResult[] results = null; -        try { -            results = future.get( -                    POWER_STATS_ENERGY_CONSUMERS_TIMEOUT, TimeUnit.MILLISECONDS); -        } catch (InterruptedException | ExecutionException | TimeoutException e) { -            Slog.e(TAG, "Could not obtain energy consumers from PowerStatsService", e); -        } -        if (results == null) { +        long[] energyUws = mConsumedEnergyRetriever.getConsumedEnergyUws(mCpuEnergyConsumerIds); +        if (energyUws == null) {              return;          } -        for (int i = 0; i < mCpuEnergyConsumerIds.length; i++) { -            int id = mCpuEnergyConsumerIds[i]; -            for (EnergyConsumerResult result : results) { -                if (result.id == id) { -                    long energyDelta = mLastConsumedEnergyUws[i] != ENERGY_UNSPECIFIED -                            ? result.energyUWs - mLastConsumedEnergyUws[i] : 0; -                    if (energyDelta < 0) { -                        // Likely, restart of powerstats HAL -                        energyDelta = 0; -                    } -                    mLayout.setConsumedEnergy(mCpuPowerStats.stats, i, -                            uJtoUc(energyDelta, averageVoltage)); -                    mLastConsumedEnergyUws[i] = result.energyUWs; -                    break; -                } +        for (int i = energyUws.length - 1; i >= 0; i--) { +            long energyDelta = mLastConsumedEnergyUws[i] != ENERGY_UNSPECIFIED +                    ? energyUws[i] - mLastConsumedEnergyUws[i] : 0; +            if (energyDelta < 0) { +                // Likely, restart of powerstats HAL +                energyDelta = 0;              } +            mLayout.setConsumedEnergy(mCpuPowerStats.stats, i, uJtoUc(energyDelta, averageVoltage)); +            mLastConsumedEnergyUws[i] = energyUws[i];          }      } @@ -652,6 +451,17 @@ public class CpuPowerStatsCollector extends PowerStatsCollector {       * Native class that retrieves CPU stats from the kernel.       */      public static class KernelCpuStatsReader { +        protected boolean isSupportedFeature() { +            return nativeIsSupportedFeature(); +        } + +        protected long readCpuStats(KernelCpuStatsCallback callback, +                int[] scalingStepToPowerBracketMap, long lastUpdateTimestampNanos, +                long[] outCpuTimeByScalingStep, long[] tempForUidStats) { +            return nativeReadCpuStats(callback, scalingStepToPowerBracketMap, +                    lastUpdateTimestampNanos, outCpuTimeByScalingStep, tempForUidStats); +        } +          protected native boolean nativeIsSupportedFeature();          protected native long nativeReadCpuStats(KernelCpuStatsCallback callback, diff --git a/services/core/java/com/android/server/power/stats/CpuPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/CpuPowerStatsLayout.java new file mode 100644 index 000000000000..1bcb2c4bc5fa --- /dev/null +++ b/services/core/java/com/android/server/power/stats/CpuPowerStatsLayout.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.power.stats; + +import android.os.PersistableBundle; + +/** + * Captures the positions and lengths of sections of the stats array, such as time-in-state, + * power usage estimates etc. + */ +public class CpuPowerStatsLayout extends PowerStatsLayout { +    private static final String EXTRA_DEVICE_TIME_BY_SCALING_STEP_POSITION = "dt"; +    private static final String EXTRA_DEVICE_TIME_BY_SCALING_STEP_COUNT = "dtc"; +    private static final String EXTRA_DEVICE_TIME_BY_CLUSTER_POSITION = "dc"; +    private static final String EXTRA_DEVICE_TIME_BY_CLUSTER_COUNT = "dcc"; +    private static final String EXTRA_UID_BRACKETS_POSITION = "ub"; +    private static final String EXTRA_UID_STATS_SCALING_STEP_TO_POWER_BRACKET = "us"; + +    private int mDeviceCpuTimeByScalingStepPosition; +    private int mDeviceCpuTimeByScalingStepCount; +    private int mDeviceCpuTimeByClusterPosition; +    private int mDeviceCpuTimeByClusterCount; + +    private int mUidPowerBracketsPosition; +    private int mUidPowerBracketCount; + +    private int[] mScalingStepToPowerBracketMap; + +    /** +     * Declare that the stats array has a section capturing CPU time per scaling step +     */ +    public void addDeviceSectionCpuTimeByScalingStep(int scalingStepCount) { +        mDeviceCpuTimeByScalingStepPosition = addDeviceSection(scalingStepCount); +        mDeviceCpuTimeByScalingStepCount = scalingStepCount; +    } + +    public int getCpuScalingStepCount() { +        return mDeviceCpuTimeByScalingStepCount; +    } + +    /** +     * Saves the time duration in the <code>stats</code> element +     * corresponding to the CPU scaling <code>state</code>. +     */ +    public void setTimeByScalingStep(long[] stats, int step, long value) { +        stats[mDeviceCpuTimeByScalingStepPosition + step] = value; +    } + +    /** +     * Extracts the time duration from the <code>stats</code> element +     * corresponding to the CPU scaling <code>step</code>. +     */ +    public long getTimeByScalingStep(long[] stats, int step) { +        return stats[mDeviceCpuTimeByScalingStepPosition + step]; +    } + +    /** +     * Declare that the stats array has a section capturing CPU time in each cluster +     */ +    public void addDeviceSectionCpuTimeByCluster(int clusterCount) { +        mDeviceCpuTimeByClusterPosition = addDeviceSection(clusterCount); +        mDeviceCpuTimeByClusterCount = clusterCount; +    } + +    public int getCpuClusterCount() { +        return mDeviceCpuTimeByClusterCount; +    } + +    /** +     * Saves the time duration in the <code>stats</code> element +     * corresponding to the CPU <code>cluster</code>. +     */ +    public void setTimeByCluster(long[] stats, int cluster, long value) { +        stats[mDeviceCpuTimeByClusterPosition + cluster] = value; +    } + +    /** +     * Extracts the time duration from the <code>stats</code> element +     * corresponding to the CPU <code>cluster</code>. +     */ +    public long getTimeByCluster(long[] stats, int cluster) { +        return stats[mDeviceCpuTimeByClusterPosition + cluster]; +    } + +    /** +     * Declare that the UID stats array has a section capturing CPU time per power bracket. +     */ +    public void addUidSectionCpuTimeByPowerBracket(int[] scalingStepToPowerBracketMap) { +        mScalingStepToPowerBracketMap = scalingStepToPowerBracketMap; +        updatePowerBracketCount(); +        mUidPowerBracketsPosition = addUidSection(mUidPowerBracketCount); +    } + +    private void updatePowerBracketCount() { +        mUidPowerBracketCount = 1; +        for (int bracket : mScalingStepToPowerBracketMap) { +            if (bracket >= mUidPowerBracketCount) { +                mUidPowerBracketCount = bracket + 1; +            } +        } +    } + +    public int[] getScalingStepToPowerBracketMap() { +        return mScalingStepToPowerBracketMap; +    } + +    public int getCpuPowerBracketCount() { +        return mUidPowerBracketCount; +    } + +    /** +     * Saves time in <code>bracket</code> in the corresponding section of <code>stats</code>. +     */ +    public void setUidTimeByPowerBracket(long[] stats, int bracket, long value) { +        stats[mUidPowerBracketsPosition + bracket] = value; +    } + +    /** +     * Extracts the time in <code>bracket</code> from a UID stats array. +     */ +    public long getUidTimeByPowerBracket(long[] stats, int bracket) { +        return stats[mUidPowerBracketsPosition + bracket]; +    } + +    /** +     * Copies the elements of the stats array layout into <code>extras</code> +     */ +    public void toExtras(PersistableBundle extras) { +        super.toExtras(extras); +        extras.putInt(EXTRA_DEVICE_TIME_BY_SCALING_STEP_POSITION, +                mDeviceCpuTimeByScalingStepPosition); +        extras.putInt(EXTRA_DEVICE_TIME_BY_SCALING_STEP_COUNT, +                mDeviceCpuTimeByScalingStepCount); +        extras.putInt(EXTRA_DEVICE_TIME_BY_CLUSTER_POSITION, +                mDeviceCpuTimeByClusterPosition); +        extras.putInt(EXTRA_DEVICE_TIME_BY_CLUSTER_COUNT, +                mDeviceCpuTimeByClusterCount); +        extras.putInt(EXTRA_UID_BRACKETS_POSITION, mUidPowerBracketsPosition); +        putIntArray(extras, EXTRA_UID_STATS_SCALING_STEP_TO_POWER_BRACKET, +                mScalingStepToPowerBracketMap); +    } + +    /** +     * Retrieves elements of the stats array layout from <code>extras</code> +     */ +    public void fromExtras(PersistableBundle extras) { +        super.fromExtras(extras); +        mDeviceCpuTimeByScalingStepPosition = +                extras.getInt(EXTRA_DEVICE_TIME_BY_SCALING_STEP_POSITION); +        mDeviceCpuTimeByScalingStepCount = +                extras.getInt(EXTRA_DEVICE_TIME_BY_SCALING_STEP_COUNT); +        mDeviceCpuTimeByClusterPosition = +                extras.getInt(EXTRA_DEVICE_TIME_BY_CLUSTER_POSITION); +        mDeviceCpuTimeByClusterCount = +                extras.getInt(EXTRA_DEVICE_TIME_BY_CLUSTER_COUNT); +        mUidPowerBracketsPosition = extras.getInt(EXTRA_UID_BRACKETS_POSITION); +        mScalingStepToPowerBracketMap = +                getIntArray(extras, EXTRA_UID_STATS_SCALING_STEP_TO_POWER_BRACKET); +        if (mScalingStepToPowerBracketMap == null) { +            mScalingStepToPowerBracketMap = new int[mDeviceCpuTimeByScalingStepCount]; +        } +        updatePowerBracketCount(); +    } +} diff --git a/services/core/java/com/android/server/power/stats/CpuAggregatedPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/CpuPowerStatsProcessor.java index ed9414ff53a1..c34b8a8dc992 100644 --- a/services/core/java/com/android/server/power/stats/CpuAggregatedPowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/CpuPowerStatsProcessor.java @@ -29,8 +29,8 @@ import java.util.Arrays;  import java.util.List;  import java.util.concurrent.TimeUnit; -public class CpuAggregatedPowerStatsProcessor extends AggregatedPowerStatsProcessor { -    private static final String TAG = "CpuAggregatedPowerStatsProcessor"; +public class CpuPowerStatsProcessor extends PowerStatsProcessor { +    private static final String TAG = "CpuPowerStatsProcessor";      private static final double HOUR_IN_MILLIS = TimeUnit.HOURS.toMillis(1);      private static final int UNKNOWN = -1; @@ -64,7 +64,7 @@ public class CpuAggregatedPowerStatsProcessor extends AggregatedPowerStatsProces      private PowerStats.Descriptor mLastUsedDescriptor;      // Cached results of parsing of current PowerStats.Descriptor. Only refreshed when      // mLastUsedDescriptor changes -    private CpuPowerStatsCollector.CpuStatsArrayLayout mStatsLayout; +    private CpuPowerStatsLayout mStatsLayout;      // Sequence of steps for power estimation and intermediate results.      private PowerEstimationPlan mPlan; @@ -73,8 +73,7 @@ public class CpuAggregatedPowerStatsProcessor extends AggregatedPowerStatsProces      // Temp array for retrieval of UID power stats, to avoid repeated allocations      private long[] mTmpUidStatsArray; -    public CpuAggregatedPowerStatsProcessor(PowerProfile powerProfile, -            CpuScalingPolicies scalingPolicies) { +    public CpuPowerStatsProcessor(PowerProfile powerProfile, CpuScalingPolicies scalingPolicies) {          mCpuScalingPolicies = scalingPolicies;          mCpuScalingStepCount = scalingPolicies.getScalingStepCount();          mScalingStepToCluster = new int[mCpuScalingStepCount]; @@ -106,7 +105,7 @@ public class CpuAggregatedPowerStatsProcessor extends AggregatedPowerStatsProces          }          mLastUsedDescriptor = descriptor; -        mStatsLayout = new CpuPowerStatsCollector.CpuStatsArrayLayout(); +        mStatsLayout = new CpuPowerStatsLayout();          mStatsLayout.fromExtras(descriptor.extras);          mTmpDeviceStatsArray = new long[descriptor.statsArrayLength]; @@ -527,6 +526,12 @@ public class CpuAggregatedPowerStatsProcessor extends AggregatedPowerStatsProces      }      @Override +    String stateStatsToString(PowerStats.Descriptor descriptor, int key, long[] stats) { +        // Unsupported for this power component +        return null; +    } + +    @Override      public String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats) {          unpackPowerStatsDescriptor(descriptor);          StringBuilder sb = new StringBuilder(); diff --git a/services/core/java/com/android/server/power/stats/MobileRadioPowerCalculator.java b/services/core/java/com/android/server/power/stats/MobileRadioPowerCalculator.java index 9ea143e5c201..c01363a9c7ba 100644 --- a/services/core/java/com/android/server/power/stats/MobileRadioPowerCalculator.java +++ b/services/core/java/com/android/server/power/stats/MobileRadioPowerCalculator.java @@ -387,92 +387,14 @@ public class MobileRadioPowerCalculator extends PowerCalculator {          return consumptionMah;      } -    private static long buildModemPowerProfileKey(@ModemPowerProfile.ModemDrainType int drainType, -            @BatteryStats.RadioAccessTechnology int rat, @ServiceState.FrequencyRange int freqRange, -            int txLevel) { -        long key = PowerProfile.SUBSYSTEM_MODEM; - -        // Attach Modem drain type to the key if specified. -        if (drainType != IGNORE) { -            key |= drainType; -        } - -        // Attach RadioAccessTechnology to the key if specified. -        switch (rat) { -            case IGNORE: -                // do nothing -                break; -            case BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER: -                key |= ModemPowerProfile.MODEM_RAT_TYPE_DEFAULT; -                break; -            case BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE: -                key |= ModemPowerProfile.MODEM_RAT_TYPE_LTE; -                break; -            case BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR: -                key |= ModemPowerProfile.MODEM_RAT_TYPE_NR; -                break; -            default: -                Log.w(TAG, "Unexpected RadioAccessTechnology : " + rat); -        } - -        // Attach NR Frequency Range to the key if specified. -        switch (freqRange) { -            case IGNORE: -                // do nothing -                break; -            case ServiceState.FREQUENCY_RANGE_UNKNOWN: -                key |= ModemPowerProfile.MODEM_NR_FREQUENCY_RANGE_DEFAULT; -                break; -            case ServiceState.FREQUENCY_RANGE_LOW: -                key |= ModemPowerProfile.MODEM_NR_FREQUENCY_RANGE_LOW; -                break; -            case ServiceState.FREQUENCY_RANGE_MID: -                key |= ModemPowerProfile.MODEM_NR_FREQUENCY_RANGE_MID; -                break; -            case ServiceState.FREQUENCY_RANGE_HIGH: -                key |= ModemPowerProfile.MODEM_NR_FREQUENCY_RANGE_HIGH; -                break; -            case ServiceState.FREQUENCY_RANGE_MMWAVE: -                key |= ModemPowerProfile.MODEM_NR_FREQUENCY_RANGE_MMWAVE; -                break; -            default: -                Log.w(TAG, "Unexpected NR frequency range : " + freqRange); -        } - -        // Attach transmission level to the key if specified. -        switch (txLevel) { -            case IGNORE: -                // do nothing -                break; -            case 0: -                key |= ModemPowerProfile.MODEM_TX_LEVEL_0; -                break; -            case 1: -                key |= ModemPowerProfile.MODEM_TX_LEVEL_1; -                break; -            case 2: -                key |= ModemPowerProfile.MODEM_TX_LEVEL_2; -                break; -            case 3: -                key |= ModemPowerProfile.MODEM_TX_LEVEL_3; -                break; -            case 4: -                key |= ModemPowerProfile.MODEM_TX_LEVEL_4; -                break; -            default: -                Log.w(TAG, "Unexpected transmission level : " + txLevel); -        } -        return key; -    } -      /**       * Calculates active receive radio power consumption (in milliamp-hours) from the given state's       * duration.       */      public double calcRxStatePowerMah(@BatteryStats.RadioAccessTechnology int rat,              @ServiceState.FrequencyRange int freqRange, long rxDurationMs) { -        final long rxKey = buildModemPowerProfileKey(ModemPowerProfile.MODEM_DRAIN_TYPE_RX, rat, -                freqRange, IGNORE); +        final long rxKey = ModemPowerProfile.getAverageBatteryDrainKey( +                ModemPowerProfile.MODEM_DRAIN_TYPE_RX, rat, freqRange, IGNORE);          final double drainRateMa = mPowerProfile.getAverageBatteryDrainOrDefaultMa(rxKey,                  Double.NaN);          if (Double.isNaN(drainRateMa)) { @@ -495,8 +417,8 @@ public class MobileRadioPowerCalculator extends PowerCalculator {       */      public double calcTxStatePowerMah(@BatteryStats.RadioAccessTechnology int rat,              @ServiceState.FrequencyRange int freqRange, int txLevel, long txDurationMs) { -        final long txKey = buildModemPowerProfileKey(ModemPowerProfile.MODEM_DRAIN_TYPE_TX, rat, -                freqRange, txLevel); +        final long txKey = ModemPowerProfile.getAverageBatteryDrainKey( +                ModemPowerProfile.MODEM_DRAIN_TYPE_TX, rat, freqRange, txLevel);          final double drainRateMa = mPowerProfile.getAverageBatteryDrainOrDefaultMa(txKey,                  Double.NaN);          if (Double.isNaN(drainRateMa)) { diff --git a/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java new file mode 100644 index 000000000000..8c154e4a0875 --- /dev/null +++ b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsCollector.java @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.power.stats; + +import android.content.pm.PackageManager; +import android.hardware.power.stats.EnergyConsumerType; +import android.net.NetworkStats; +import android.os.BatteryConsumer; +import android.os.BatteryStats; +import android.os.Handler; +import android.os.OutcomeReceiver; +import android.os.PersistableBundle; +import android.telephony.AccessNetworkConstants; +import android.telephony.ModemActivityInfo; +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.Clock; +import com.android.internal.os.PowerStats; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.IntSupplier; +import java.util.function.LongSupplier; +import java.util.function.Supplier; + +public class MobileRadioPowerStatsCollector extends PowerStatsCollector { +    private static final String TAG = "MobileRadioPowerStatsCollector"; + +    /** +     * The soonest the Mobile Radio stats can be updated due to a mobile radio power state change +     * after it was last updated. +     */ +    @VisibleForTesting +    protected static final long MOBILE_RADIO_POWER_STATE_UPDATE_FREQ_MS = 1000 * 60 * 10; + +    private static final long MODEM_ACTIVITY_REQUEST_TIMEOUT = 20000; + +    private static final long ENERGY_UNSPECIFIED = -1; + +    @VisibleForTesting +    @AccessNetworkConstants.RadioAccessNetworkType +    static final int[] NETWORK_TYPES = { +            AccessNetworkConstants.AccessNetworkType.UNKNOWN, +            AccessNetworkConstants.AccessNetworkType.GERAN, +            AccessNetworkConstants.AccessNetworkType.UTRAN, +            AccessNetworkConstants.AccessNetworkType.EUTRAN, +            AccessNetworkConstants.AccessNetworkType.CDMA2000, +            AccessNetworkConstants.AccessNetworkType.IWLAN, +            AccessNetworkConstants.AccessNetworkType.NGRAN +    }; + +    interface Injector { +        Handler getHandler(); +        Clock getClock(); +        PowerStatsUidResolver getUidResolver(); +        PackageManager getPackageManager(); +        ConsumedEnergyRetriever getConsumedEnergyRetriever(); +        IntSupplier getVoltageSupplier(); +        Supplier<NetworkStats> getMobileNetworkStatsSupplier(); +        TelephonyManager getTelephonyManager(); +        LongSupplier getCallDurationSupplier(); +        LongSupplier getPhoneSignalScanDurationSupplier(); +    } + +    private final Injector mInjector; + +    private MobileRadioPowerStatsLayout mLayout; +    private boolean mIsInitialized; + +    private PowerStats mPowerStats; +    private long[] mDeviceStats; +    private PowerStatsUidResolver mPowerStatsUidResolver; +    private volatile TelephonyManager mTelephonyManager; +    private LongSupplier mCallDurationSupplier; +    private LongSupplier mScanDurationSupplier; +    private volatile Supplier<NetworkStats> mNetworkStatsSupplier; +    private ConsumedEnergyRetriever mConsumedEnergyRetriever; +    private IntSupplier mVoltageSupplier; +    private int[] mEnergyConsumerIds = new int[0]; +    private long mLastUpdateTimestampMillis; +    private ModemActivityInfo mLastModemActivityInfo; +    private NetworkStats mLastNetworkStats; +    private long[] mLastConsumedEnergyUws; +    private int mLastVoltageMv; +    private long mLastCallDuration; +    private long mLastScanDuration; + +    public MobileRadioPowerStatsCollector(Injector injector, long throttlePeriodMs) { +        super(injector.getHandler(), throttlePeriodMs, injector.getClock()); +        mInjector = injector; +    } + +    @Override +    public void setEnabled(boolean enabled) { +        if (enabled) { +            PackageManager packageManager = mInjector.getPackageManager(); +            super.setEnabled(packageManager != null +                    && packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)); +        } else { +            super.setEnabled(false); +        } +    } + +    private boolean ensureInitialized() { +        if (mIsInitialized) { +            return true; +        } + +        if (!isEnabled()) { +            return false; +        } + +        mPowerStatsUidResolver = mInjector.getUidResolver(); +        mConsumedEnergyRetriever = mInjector.getConsumedEnergyRetriever(); +        mVoltageSupplier = mInjector.getVoltageSupplier(); + +        mTelephonyManager = mInjector.getTelephonyManager(); +        mNetworkStatsSupplier = mInjector.getMobileNetworkStatsSupplier(); +        mCallDurationSupplier = mInjector.getCallDurationSupplier(); +        mScanDurationSupplier = mInjector.getPhoneSignalScanDurationSupplier(); + +        mEnergyConsumerIds = mConsumedEnergyRetriever.getEnergyConsumerIds( +                EnergyConsumerType.MOBILE_RADIO); +        mLastConsumedEnergyUws = new long[mEnergyConsumerIds.length]; +        Arrays.fill(mLastConsumedEnergyUws, ENERGY_UNSPECIFIED); + +        mLayout = new MobileRadioPowerStatsLayout(); +        mLayout.addDeviceMobileActivity(); +        mLayout.addDeviceSectionEnergyConsumers(mEnergyConsumerIds.length); +        mLayout.addStateStats(); +        mLayout.addUidNetworkStats(); +        mLayout.addDeviceSectionUsageDuration(); +        mLayout.addDeviceSectionPowerEstimate(); +        mLayout.addUidSectionPowerEstimate(); + +        SparseArray<String> stateLabels = new SparseArray<>(); +        for (int rat = 0; rat < BatteryStats.RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) { +            final int freqCount = rat == BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR +                    ? ServiceState.FREQUENCY_RANGE_COUNT : 1; +            for (int freq = 0; freq < freqCount; freq++) { +                int stateKey = makeStateKey(rat, freq); +                StringBuilder sb = new StringBuilder(); +                if (rat != BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER) { +                    sb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]); +                } +                if (freq != ServiceState.FREQUENCY_RANGE_UNKNOWN) { +                    if (!sb.isEmpty()) { +                        sb.append(" "); +                    } +                    sb.append(ServiceState.frequencyRangeToString(freq)); +                } +                stateLabels.put(stateKey, !sb.isEmpty() ? sb.toString() : "other"); +            } +        } + +        PersistableBundle extras = new PersistableBundle(); +        mLayout.toExtras(extras); +        PowerStats.Descriptor powerStatsDescriptor = new PowerStats.Descriptor( +                BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, mLayout.getDeviceStatsArrayLength(), +                stateLabels, mLayout.getStateStatsArrayLength(), mLayout.getUidStatsArrayLength(), +                extras); +        mPowerStats = new PowerStats(powerStatsDescriptor); +        mDeviceStats = mPowerStats.stats; + +        mIsInitialized = true; +        return true; +    } + +    @Override +    protected PowerStats collectStats() { +        if (!ensureInitialized()) { +            return null; +        } + +        collectModemActivityInfo(); + +        collectNetworkStats(); + +        if (mEnergyConsumerIds.length != 0) { +            collectEnergyConsumers(); +        } + +        if (mPowerStats.durationMs == 0) { +            setTimestamp(mClock.elapsedRealtime()); +        } + +        return mPowerStats; +    } + +    private void collectModemActivityInfo() { +        if (mTelephonyManager == null) { +            return; +        } + +        CompletableFuture<ModemActivityInfo> immediateFuture = new CompletableFuture<>(); +        mTelephonyManager.requestModemActivityInfo(Runnable::run, +                new OutcomeReceiver<>() { +                    @Override +                    public void onResult(ModemActivityInfo result) { +                        immediateFuture.complete(result); +                    } + +                    @Override +                    public void onError(TelephonyManager.ModemActivityInfoException e) { +                        Slog.w(TAG, "error reading modem stats:" + e); +                        immediateFuture.complete(null); +                    } +                }); + +        ModemActivityInfo activityInfo; +        try { +            activityInfo = immediateFuture.get(MODEM_ACTIVITY_REQUEST_TIMEOUT, +                    TimeUnit.MILLISECONDS); +        } catch (Exception e) { +            Slog.e(TAG, "Cannot acquire ModemActivityInfo"); +            activityInfo = null; +        } + +        ModemActivityInfo deltaInfo = mLastModemActivityInfo == null +                ? (activityInfo == null ? null : activityInfo.getDelta(activityInfo)) +                : mLastModemActivityInfo.getDelta(activityInfo); + +        mLastModemActivityInfo = activityInfo; + +        if (deltaInfo == null) { +            return; +        } + +        setTimestamp(deltaInfo.getTimestampMillis()); +        mLayout.setDeviceSleepTime(mDeviceStats, deltaInfo.getSleepTimeMillis()); +        mLayout.setDeviceIdleTime(mDeviceStats, deltaInfo.getIdleTimeMillis()); + +        long callDuration = mCallDurationSupplier.getAsLong(); +        if (callDuration >= mLastCallDuration) { +            mLayout.setDeviceCallTime(mDeviceStats, callDuration - mLastCallDuration); +        } +        mLastCallDuration = callDuration; + +        long scanDuration = mScanDurationSupplier.getAsLong(); +        if (scanDuration >= mLastScanDuration) { +            mLayout.setDeviceScanTime(mDeviceStats, scanDuration - mLastScanDuration); +        } +        mLastScanDuration = scanDuration; + +        SparseArray<long[]> stateStats = mPowerStats.stateStats; +        stateStats.clear(); + +        if (deltaInfo.getSpecificInfoLength() == 0) { +            mLayout.addRxTxTimesForRat(stateStats, +                    AccessNetworkConstants.AccessNetworkType.UNKNOWN, +                    ServiceState.FREQUENCY_RANGE_UNKNOWN, +                    deltaInfo.getReceiveTimeMillis(), +                    deltaInfo.getTransmitTimeMillis()); +        } else { +            for (int rat = 0; rat < NETWORK_TYPES.length; rat++) { +                if (rat == AccessNetworkConstants.AccessNetworkType.NGRAN) { +                    for (int freq = 0; freq < ServiceState.FREQUENCY_RANGE_COUNT; freq++) { +                        mLayout.addRxTxTimesForRat(stateStats, rat, freq, +                                deltaInfo.getReceiveTimeMillis(rat, freq), +                                deltaInfo.getTransmitTimeMillis(rat, freq)); +                    } +                } else { +                    mLayout.addRxTxTimesForRat(stateStats, rat, +                            ServiceState.FREQUENCY_RANGE_UNKNOWN, +                            deltaInfo.getReceiveTimeMillis(rat), +                            deltaInfo.getTransmitTimeMillis(rat)); +                } +            } +        } +    } + +    private void collectNetworkStats() { +        mPowerStats.uidStats.clear(); + +        NetworkStats networkStats = mNetworkStatsSupplier.get(); +        if (networkStats == null) { +            return; +        } + +        List<BatteryStatsImpl.NetworkStatsDelta> delta = +                BatteryStatsImpl.computeDelta(networkStats, mLastNetworkStats); +        mLastNetworkStats = networkStats; +        for (int i = delta.size() - 1; i >= 0; i--) { +            BatteryStatsImpl.NetworkStatsDelta uidDelta = delta.get(i); +            long rxBytes = uidDelta.getRxBytes(); +            long txBytes = uidDelta.getTxBytes(); +            long rxPackets = uidDelta.getRxPackets(); +            long txPackets = uidDelta.getTxPackets(); +            if (rxBytes == 0 && txBytes == 0 && rxPackets == 0 && txPackets == 0) { +                continue; +            } + +            int uid = mPowerStatsUidResolver.mapUid(uidDelta.getUid()); +            long[] stats = mPowerStats.uidStats.get(uid); +            if (stats == null) { +                stats = new long[mLayout.getUidStatsArrayLength()]; +                mPowerStats.uidStats.put(uid, stats); +                mLayout.setUidRxBytes(stats, rxBytes); +                mLayout.setUidTxBytes(stats, txBytes); +                mLayout.setUidRxPackets(stats, rxPackets); +                mLayout.setUidTxPackets(stats, txPackets); +            } else { +                mLayout.setUidRxBytes(stats, mLayout.getUidRxBytes(stats) + rxBytes); +                mLayout.setUidTxBytes(stats, mLayout.getUidTxBytes(stats) + txBytes); +                mLayout.setUidRxPackets(stats, mLayout.getUidRxPackets(stats) + rxPackets); +                mLayout.setUidTxPackets(stats, mLayout.getUidTxPackets(stats) + txPackets); +            } +        } +    } + +    private void collectEnergyConsumers() { +        int voltageMv = mVoltageSupplier.getAsInt(); +        if (voltageMv <= 0) { +            Slog.wtf(TAG, "Unexpected battery voltage (" + voltageMv +                    + " mV) when querying energy consumers"); +            return; +        } + +        int averageVoltage = mLastVoltageMv != 0 ? (mLastVoltageMv + voltageMv) / 2 : voltageMv; +        mLastVoltageMv = voltageMv; + +        long[] energyUws = mConsumedEnergyRetriever.getConsumedEnergyUws(mEnergyConsumerIds); +        if (energyUws == null) { +            return; +        } + +        for (int i = energyUws.length - 1; i >= 0; i--) { +            long energyDelta = mLastConsumedEnergyUws[i] != ENERGY_UNSPECIFIED +                    ? energyUws[i] - mLastConsumedEnergyUws[i] : 0; +            if (energyDelta < 0) { +                // Likely, restart of powerstats HAL +                energyDelta = 0; +            } +            mLayout.setConsumedEnergy(mPowerStats.stats, i, uJtoUc(energyDelta, averageVoltage)); +            mLastConsumedEnergyUws[i] = energyUws[i]; +        } +    } + +    static int makeStateKey(int rat, int freqRange) { +        if (rat == BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR) { +            return rat | (freqRange << 8); +        } else { +            return rat; +        } +    } + +    private void setTimestamp(long timestamp) { +        mPowerStats.durationMs = Math.max(timestamp - mLastUpdateTimestampMillis, 0); +        mLastUpdateTimestampMillis = timestamp; +    } + +    @BatteryStats.RadioAccessTechnology +    static int mapRadioAccessNetworkTypeToRadioAccessTechnology( +            @AccessNetworkConstants.RadioAccessNetworkType int networkType) { +        switch (networkType) { +            case AccessNetworkConstants.AccessNetworkType.NGRAN: +                return BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR; +            case AccessNetworkConstants.AccessNetworkType.EUTRAN: +                return BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE; +            case AccessNetworkConstants.AccessNetworkType.UNKNOWN: //fallthrough +            case AccessNetworkConstants.AccessNetworkType.GERAN: //fallthrough +            case AccessNetworkConstants.AccessNetworkType.UTRAN: //fallthrough +            case AccessNetworkConstants.AccessNetworkType.CDMA2000: //fallthrough +            case AccessNetworkConstants.AccessNetworkType.IWLAN: +                return BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER; +            default: +                Slog.w(TAG, +                        "Unhandled RadioAccessNetworkType (" + networkType + "), mapping to OTHER"); +                return BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER; +        } +    } +} diff --git a/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsLayout.java new file mode 100644 index 000000000000..81d7c2fa2880 --- /dev/null +++ b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsLayout.java @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.power.stats; + +import android.annotation.NonNull; +import android.os.PersistableBundle; +import android.telephony.ModemActivityInfo; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.os.PowerStats; + +/** + * Captures the positions and lengths of sections of the stats array, such as time-in-state, + * power usage estimates etc. + */ +class MobileRadioPowerStatsLayout extends PowerStatsLayout { +    private static final String TAG = "MobileRadioPowerStatsLayout"; +    private static final String EXTRA_DEVICE_SLEEP_TIME_POSITION = "dt-sleep"; +    private static final String EXTRA_DEVICE_IDLE_TIME_POSITION = "dt-idle"; +    private static final String EXTRA_DEVICE_SCAN_TIME_POSITION = "dt-scan"; +    private static final String EXTRA_DEVICE_CALL_TIME_POSITION = "dt-call"; +    private static final String EXTRA_DEVICE_CALL_POWER_POSITION = "dp-call"; +    private static final String EXTRA_STATE_RX_TIME_POSITION = "srx"; +    private static final String EXTRA_STATE_TX_TIMES_POSITION = "stx"; +    private static final String EXTRA_STATE_TX_TIMES_COUNT = "stxc"; +    private static final String EXTRA_UID_RX_BYTES_POSITION = "urxb"; +    private static final String EXTRA_UID_TX_BYTES_POSITION = "utxb"; +    private static final String EXTRA_UID_RX_PACKETS_POSITION = "urxp"; +    private static final String EXTRA_UID_TX_PACKETS_POSITION = "utxp"; + +    private int mDeviceSleepTimePosition; +    private int mDeviceIdleTimePosition; +    private int mDeviceScanTimePosition; +    private int mDeviceCallTimePosition; +    private int mDeviceCallPowerPosition; +    private int mStateRxTimePosition; +    private int mStateTxTimesPosition; +    private int mStateTxTimesCount; +    private int mUidRxBytesPosition; +    private int mUidTxBytesPosition; +    private int mUidRxPacketsPosition; +    private int mUidTxPacketsPosition; + +    MobileRadioPowerStatsLayout() { +    } + +    MobileRadioPowerStatsLayout(@NonNull PowerStats.Descriptor descriptor) { +        super(descriptor); +    } + +    void addDeviceMobileActivity() { +        mDeviceSleepTimePosition = addDeviceSection(1); +        mDeviceIdleTimePosition = addDeviceSection(1); +        mDeviceScanTimePosition = addDeviceSection(1); +        mDeviceCallTimePosition = addDeviceSection(1); +    } + +    void addStateStats() { +        mStateRxTimePosition = addStateSection(1); +        mStateTxTimesCount = ModemActivityInfo.getNumTxPowerLevels(); +        mStateTxTimesPosition = addStateSection(mStateTxTimesCount); +    } + +    void addUidNetworkStats() { +        mUidRxBytesPosition = addUidSection(1); +        mUidTxBytesPosition = addUidSection(1); +        mUidRxPacketsPosition = addUidSection(1); +        mUidTxPacketsPosition = addUidSection(1); +    } + +    @Override +    public void addDeviceSectionPowerEstimate() { +        super.addDeviceSectionPowerEstimate(); +        mDeviceCallPowerPosition = addDeviceSection(1); +    } + +    public void setDeviceSleepTime(long[] stats, long durationMillis) { +        stats[mDeviceSleepTimePosition] = durationMillis; +    } + +    public long getDeviceSleepTime(long[] stats) { +        return stats[mDeviceSleepTimePosition]; +    } + +    public void setDeviceIdleTime(long[] stats, long durationMillis) { +        stats[mDeviceIdleTimePosition] = durationMillis; +    } + +    public long getDeviceIdleTime(long[] stats) { +        return stats[mDeviceIdleTimePosition]; +    } + +    public void setDeviceScanTime(long[] stats, long durationMillis) { +        stats[mDeviceScanTimePosition] = durationMillis; +    } + +    public long getDeviceScanTime(long[] stats) { +        return stats[mDeviceScanTimePosition]; +    } + +    public void setDeviceCallTime(long[] stats, long durationMillis) { +        stats[mDeviceCallTimePosition] = durationMillis; +    } + +    public long getDeviceCallTime(long[] stats) { +        return stats[mDeviceCallTimePosition]; +    } + +    public void setDeviceCallPowerEstimate(long[] stats, double power) { +        stats[mDeviceCallPowerPosition] = (long) (power * MILLI_TO_NANO_MULTIPLIER); +    } + +    public double getDeviceCallPowerEstimate(long[] stats) { +        return stats[mDeviceCallPowerPosition] / MILLI_TO_NANO_MULTIPLIER; +    } + +    public void setStateRxTime(long[] stats, long durationMillis) { +        stats[mStateRxTimePosition] = durationMillis; +    } + +    public long getStateRxTime(long[] stats) { +        return stats[mStateRxTimePosition]; +    } + +    public void setStateTxTime(long[] stats, int level, int durationMillis) { +        stats[mStateTxTimesPosition + level] = durationMillis; +    } + +    public long getStateTxTime(long[] stats, int level) { +        return stats[mStateTxTimesPosition + level]; +    } + +    public void setUidRxBytes(long[] stats, long count) { +        stats[mUidRxBytesPosition] = count; +    } + +    public long getUidRxBytes(long[] stats) { +        return stats[mUidRxBytesPosition]; +    } + +    public void setUidTxBytes(long[] stats, long count) { +        stats[mUidTxBytesPosition] = count; +    } + +    public long getUidTxBytes(long[] stats) { +        return stats[mUidTxBytesPosition]; +    } + +    public void setUidRxPackets(long[] stats, long count) { +        stats[mUidRxPacketsPosition] = count; +    } + +    public long getUidRxPackets(long[] stats) { +        return stats[mUidRxPacketsPosition]; +    } + +    public void setUidTxPackets(long[] stats, long count) { +        stats[mUidTxPacketsPosition] = count; +    } + +    public long getUidTxPackets(long[] stats) { +        return stats[mUidTxPacketsPosition]; +    } + +    /** +     * Copies the elements of the stats array layout into <code>extras</code> +     */ +    public void toExtras(PersistableBundle extras) { +        super.toExtras(extras); +        extras.putInt(EXTRA_DEVICE_SLEEP_TIME_POSITION, mDeviceSleepTimePosition); +        extras.putInt(EXTRA_DEVICE_IDLE_TIME_POSITION, mDeviceIdleTimePosition); +        extras.putInt(EXTRA_DEVICE_SCAN_TIME_POSITION, mDeviceScanTimePosition); +        extras.putInt(EXTRA_DEVICE_CALL_TIME_POSITION, mDeviceCallTimePosition); +        extras.putInt(EXTRA_DEVICE_CALL_POWER_POSITION, mDeviceCallPowerPosition); +        extras.putInt(EXTRA_STATE_RX_TIME_POSITION, mStateRxTimePosition); +        extras.putInt(EXTRA_STATE_TX_TIMES_POSITION, mStateTxTimesPosition); +        extras.putInt(EXTRA_STATE_TX_TIMES_COUNT, mStateTxTimesCount); +        extras.putInt(EXTRA_UID_RX_BYTES_POSITION, mUidRxBytesPosition); +        extras.putInt(EXTRA_UID_TX_BYTES_POSITION, mUidTxBytesPosition); +        extras.putInt(EXTRA_UID_RX_PACKETS_POSITION, mUidRxPacketsPosition); +        extras.putInt(EXTRA_UID_TX_PACKETS_POSITION, mUidTxPacketsPosition); +    } + +    /** +     * Retrieves elements of the stats array layout from <code>extras</code> +     */ +    public void fromExtras(PersistableBundle extras) { +        super.fromExtras(extras); +        mDeviceSleepTimePosition = extras.getInt(EXTRA_DEVICE_SLEEP_TIME_POSITION); +        mDeviceIdleTimePosition = extras.getInt(EXTRA_DEVICE_IDLE_TIME_POSITION); +        mDeviceScanTimePosition = extras.getInt(EXTRA_DEVICE_SCAN_TIME_POSITION); +        mDeviceCallTimePosition = extras.getInt(EXTRA_DEVICE_CALL_TIME_POSITION); +        mDeviceCallPowerPosition = extras.getInt(EXTRA_DEVICE_CALL_POWER_POSITION); +        mStateRxTimePosition = extras.getInt(EXTRA_STATE_RX_TIME_POSITION); +        mStateTxTimesPosition = extras.getInt(EXTRA_STATE_TX_TIMES_POSITION); +        mStateTxTimesCount = extras.getInt(EXTRA_STATE_TX_TIMES_COUNT); +        mUidRxBytesPosition = extras.getInt(EXTRA_UID_RX_BYTES_POSITION); +        mUidTxBytesPosition = extras.getInt(EXTRA_UID_TX_BYTES_POSITION); +        mUidRxPacketsPosition = extras.getInt(EXTRA_UID_RX_PACKETS_POSITION); +        mUidTxPacketsPosition = extras.getInt(EXTRA_UID_TX_PACKETS_POSITION); +    } + +    public void addRxTxTimesForRat(SparseArray<long[]> stateStats, int networkType, int freqRange, +            long rxTime, int[] txTime) { +        if (txTime.length != mStateTxTimesCount) { +            Slog.wtf(TAG, "Invalid TX time array size: " + txTime.length); +            return; +        } + +        boolean nonZero = false; +        if (rxTime != 0) { +            nonZero = true; +        } else { +            for (int i = txTime.length - 1; i >= 0; i--) { +                if (txTime[i] != 0) { +                    nonZero = true; +                    break; +                } +            } +        } + +        if (!nonZero) { +            return; +        } + +        int rat = MobileRadioPowerStatsCollector.mapRadioAccessNetworkTypeToRadioAccessTechnology( +                networkType); +        int stateKey = MobileRadioPowerStatsCollector.makeStateKey(rat, freqRange); +        long[] stats = stateStats.get(stateKey); +        if (stats == null) { +            stats = new long[getStateStatsArrayLength()]; +            stateStats.put(stateKey, stats); +        } + +        stats[mStateRxTimePosition] += rxTime; +        for (int i = mStateTxTimesCount - 1; i >= 0; i--) { +            stats[mStateTxTimesPosition + i] += txTime[i]; +        } +    } +} diff --git a/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsProcessor.java new file mode 100644 index 000000000000..c97c64bafcba --- /dev/null +++ b/services/core/java/com/android/server/power/stats/MobileRadioPowerStatsProcessor.java @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.power.stats; + +import android.os.BatteryStats; +import android.telephony.CellSignalStrength; +import android.telephony.ModemActivityInfo; +import android.telephony.ServiceState; +import android.util.Log; +import android.util.Slog; +import android.util.SparseArray; + +import com.android.internal.os.PowerProfile; +import com.android.internal.os.PowerStats; +import com.android.internal.power.ModemPowerProfile; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class MobileRadioPowerStatsProcessor extends PowerStatsProcessor { +    private static final String TAG = "MobileRadioPowerStatsProcessor"; +    private static final boolean DEBUG = false; + +    private static final int NUM_SIGNAL_STRENGTH_LEVELS = +            CellSignalStrength.getNumSignalStrengthLevels(); +    private static final int IGNORE = -1; + +    private final UsageBasedPowerEstimator mSleepPowerEstimator; +    private final UsageBasedPowerEstimator mIdlePowerEstimator; +    private final UsageBasedPowerEstimator mCallPowerEstimator; +    private final UsageBasedPowerEstimator mScanPowerEstimator; + +    private static class RxTxPowerEstimators { +        UsageBasedPowerEstimator mRxPowerEstimator; +        UsageBasedPowerEstimator[] mTxPowerEstimators = +                new UsageBasedPowerEstimator[ModemActivityInfo.getNumTxPowerLevels()]; +    } + +    private final SparseArray<RxTxPowerEstimators> mRxTxPowerEstimators = new SparseArray<>(); + +    private PowerStats.Descriptor mLastUsedDescriptor; +    private MobileRadioPowerStatsLayout mStatsLayout; +    // Sequence of steps for power estimation and intermediate results. +    private PowerEstimationPlan mPlan; + +    private long[] mTmpDeviceStatsArray; +    private long[] mTmpStateStatsArray; +    private long[] mTmpUidStatsArray; + +    public MobileRadioPowerStatsProcessor(PowerProfile powerProfile) { +        final double sleepDrainRateMa = powerProfile.getAverageBatteryDrainOrDefaultMa( +                PowerProfile.SUBSYSTEM_MODEM | ModemPowerProfile.MODEM_DRAIN_TYPE_SLEEP, +                Double.NaN); +        if (Double.isNaN(sleepDrainRateMa)) { +            mSleepPowerEstimator = null; +        } else { +            mSleepPowerEstimator = new UsageBasedPowerEstimator(sleepDrainRateMa); +        } + +        final double idleDrainRateMa = powerProfile.getAverageBatteryDrainOrDefaultMa( +                PowerProfile.SUBSYSTEM_MODEM | ModemPowerProfile.MODEM_DRAIN_TYPE_IDLE, +                Double.NaN); +        if (Double.isNaN(idleDrainRateMa)) { +            mIdlePowerEstimator = null; +        } else { +            mIdlePowerEstimator = new UsageBasedPowerEstimator(idleDrainRateMa); +        } + +        // Instantiate legacy power estimators +        double powerRadioActiveMa = +                powerProfile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ACTIVE, Double.NaN); +        if (Double.isNaN(powerRadioActiveMa)) { +            double sum = 0; +            sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX); +            for (int i = 0; i < NUM_SIGNAL_STRENGTH_LEVELS; i++) { +                sum += powerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i); +            } +            powerRadioActiveMa = sum / (NUM_SIGNAL_STRENGTH_LEVELS + 1); +        } +        mCallPowerEstimator = new UsageBasedPowerEstimator(powerRadioActiveMa); + +        mScanPowerEstimator = new UsageBasedPowerEstimator( +                powerProfile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_SCANNING, 0)); + +        for (int rat = 0; rat < BatteryStats.RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) { +            final int freqCount = rat == BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR +                    ? ServiceState.FREQUENCY_RANGE_COUNT : 1; +            for (int freqRange = 0; freqRange < freqCount; freqRange++) { +                mRxTxPowerEstimators.put( +                        MobileRadioPowerStatsCollector.makeStateKey(rat, freqRange), +                        buildRxTxPowerEstimators(powerProfile, rat, freqRange)); +            } +        } +    } + +    private static RxTxPowerEstimators buildRxTxPowerEstimators(PowerProfile powerProfile, int rat, +            int freqRange) { +        RxTxPowerEstimators estimators = new RxTxPowerEstimators(); +        long rxKey = ModemPowerProfile.getAverageBatteryDrainKey( +                ModemPowerProfile.MODEM_DRAIN_TYPE_RX, rat, freqRange, IGNORE); +        double rxDrainRateMa = powerProfile.getAverageBatteryDrainOrDefaultMa(rxKey, Double.NaN); +        if (Double.isNaN(rxDrainRateMa)) { +            Log.w(TAG, "Unavailable Power Profile constant for key 0x" +                    + Long.toHexString(rxKey)); +            rxDrainRateMa = 0; +        } +        estimators.mRxPowerEstimator = new UsageBasedPowerEstimator(rxDrainRateMa); +        for (int txLevel = 0; txLevel < ModemActivityInfo.getNumTxPowerLevels(); txLevel++) { +            long txKey = ModemPowerProfile.getAverageBatteryDrainKey( +                    ModemPowerProfile.MODEM_DRAIN_TYPE_TX, rat, freqRange, txLevel); +            double txDrainRateMa = powerProfile.getAverageBatteryDrainOrDefaultMa(txKey, +                    Double.NaN); +            if (Double.isNaN(txDrainRateMa)) { +                Log.w(TAG, "Unavailable Power Profile constant for key 0x" +                        + Long.toHexString(txKey)); +                txDrainRateMa = 0; +            } +            estimators.mTxPowerEstimators[txLevel] = new UsageBasedPowerEstimator(txDrainRateMa); +        } +        return estimators; +    } + +    private static class Intermediates { +        /** +         * Number of received packets +         */ +        public long rxPackets; +        /** +         * Number of transmitted packets +         */ +        public long txPackets; +        /** +         * Estimated power for the RX state of the modem. +         */ +        public double rxPower; +        /** +         * Estimated power for the TX state of the modem. +         */ +        public double txPower; +        /** +         * Estimated power for IDLE, SLEEP and CELL-SCAN states of the modem. +         */ +        public double inactivePower; +        /** +         * Estimated power for IDLE, SLEEP and CELL-SCAN states of the modem. +         */ +        public double callPower; +        /** +         * Measured consumed energy from power monitoring hardware (micro-coulombs) +         */ +        public long consumedEnergy; +    } + +    @Override +    void finish(PowerComponentAggregatedPowerStats stats) { +        if (stats.getPowerStatsDescriptor() == null) { +            return; +        } + +        unpackPowerStatsDescriptor(stats.getPowerStatsDescriptor()); + +        if (mPlan == null) { +            mPlan = new PowerEstimationPlan(stats.getConfig()); +        } + +        for (int i = mPlan.deviceStateEstimations.size() - 1; i >= 0; i--) { +            DeviceStateEstimation estimation = mPlan.deviceStateEstimations.get(i); +            Intermediates intermediates = new Intermediates(); +            estimation.intermediates = intermediates; +            computeDevicePowerEstimates(stats, estimation.stateValues, intermediates); +        } + +        if (mStatsLayout.getEnergyConsumerCount() != 0) { +            double ratio = computeEstimateAdjustmentRatioUsingConsumedEnergy(); +            if (ratio != 1) { +                for (int i = mPlan.deviceStateEstimations.size() - 1; i >= 0; i--) { +                    DeviceStateEstimation estimation = mPlan.deviceStateEstimations.get(i); +                    adjustDevicePowerEstimates(stats, estimation.stateValues, +                            (Intermediates) estimation.intermediates, ratio); +                } +            } +        } + +        combineDeviceStateEstimates(); + +        ArrayList<Integer> uids = new ArrayList<>(); +        stats.collectUids(uids); +        if (!uids.isEmpty()) { +            for (int uid : uids) { +                for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) { +                    computeUidRxTxTotals(stats, uid, mPlan.uidStateEstimates.get(i)); +                } +            } + +            for (int uid : uids) { +                for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) { +                    computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(i)); +                } +            } +        } +        mPlan.resetIntermediates(); +    } + +    private void unpackPowerStatsDescriptor(PowerStats.Descriptor descriptor) { +        if (descriptor.equals(mLastUsedDescriptor)) { +            return; +        } + +        mLastUsedDescriptor = descriptor; +        mStatsLayout = new MobileRadioPowerStatsLayout(descriptor); +        mTmpDeviceStatsArray = new long[descriptor.statsArrayLength]; +        mTmpStateStatsArray = new long[descriptor.stateStatsArrayLength]; +        mTmpUidStatsArray = new long[descriptor.uidStatsArrayLength]; +    } + +    /** +     * Compute power estimates using the power profile. +     */ +    private void computeDevicePowerEstimates(PowerComponentAggregatedPowerStats stats, +            int[] deviceStates, Intermediates intermediates) { +        if (!stats.getDeviceStats(mTmpDeviceStatsArray, deviceStates)) { +            return; +        } + +        for (int i = mStatsLayout.getEnergyConsumerCount() - 1; i >= 0; i--) { +            intermediates.consumedEnergy += mStatsLayout.getConsumedEnergy(mTmpDeviceStatsArray, i); +        } + +        if (mSleepPowerEstimator != null) { +            intermediates.inactivePower += mSleepPowerEstimator.calculatePower( +                    mStatsLayout.getDeviceSleepTime(mTmpDeviceStatsArray)); +        } + +        if (mIdlePowerEstimator != null) { +            intermediates.inactivePower += mIdlePowerEstimator.calculatePower( +                    mStatsLayout.getDeviceIdleTime(mTmpDeviceStatsArray)); +        } + +        if (mScanPowerEstimator != null) { +            intermediates.inactivePower += mScanPowerEstimator.calculatePower( +                    mStatsLayout.getDeviceScanTime(mTmpDeviceStatsArray)); +        } + +        stats.forEachStateStatsKey(key -> { +            RxTxPowerEstimators estimators = mRxTxPowerEstimators.get(key); +            stats.getStateStats(mTmpStateStatsArray, key, deviceStates); +            long rxTime = mStatsLayout.getStateRxTime(mTmpStateStatsArray); +            intermediates.rxPower += estimators.mRxPowerEstimator.calculatePower(rxTime); +            for (int txLevel = 0; txLevel < ModemActivityInfo.getNumTxPowerLevels(); txLevel++) { +                long txTime = mStatsLayout.getStateTxTime(mTmpStateStatsArray, txLevel); +                intermediates.txPower += +                        estimators.mTxPowerEstimators[txLevel].calculatePower(txTime); +            } +        }); + +        if (mCallPowerEstimator != null) { +            intermediates.callPower = mCallPowerEstimator.calculatePower( +                    mStatsLayout.getDeviceCallTime(mTmpDeviceStatsArray)); +        } + +        mStatsLayout.setDevicePowerEstimate(mTmpDeviceStatsArray, +                intermediates.rxPower + intermediates.txPower + intermediates.inactivePower); +        mStatsLayout.setDeviceCallPowerEstimate(mTmpDeviceStatsArray, intermediates.callPower); +        stats.setDeviceStats(deviceStates, mTmpDeviceStatsArray); +    } + +    /** +     * Compute an adjustment ratio using the total power estimated using the power profile +     * and the total power measured by hardware. +     */ +    private double computeEstimateAdjustmentRatioUsingConsumedEnergy() { +        long totalConsumedEnergy = 0; +        double totalPower = 0; + +        for (int i = mPlan.deviceStateEstimations.size() - 1; i >= 0; i--) { +            Intermediates intermediates = +                    (Intermediates) mPlan.deviceStateEstimations.get(i).intermediates; +            totalPower += intermediates.rxPower + intermediates.txPower +                    + intermediates.inactivePower + intermediates.callPower; +            totalConsumedEnergy += intermediates.consumedEnergy; +        } + +        if (totalPower == 0) { +            return 1; +        } + +        return uCtoMah(totalConsumedEnergy) / totalPower; +    } + +    /** +     * Uniformly apply the same adjustment to all power estimates in order to ensure that the total +     * estimated power matches the measured consumed power.  We are not claiming that all +     * averages captured in the power profile have to be off by the same percentage in reality. +     */ +    private void adjustDevicePowerEstimates(PowerComponentAggregatedPowerStats stats, +            int[] deviceStates, Intermediates intermediates, double ratio) { +        intermediates.rxPower *= ratio; +        intermediates.txPower *= ratio; +        intermediates.inactivePower *= ratio; +        intermediates.callPower *= ratio; + +        if (!stats.getDeviceStats(mTmpDeviceStatsArray, deviceStates)) { +            return; +        } + +        mStatsLayout.setDevicePowerEstimate(mTmpDeviceStatsArray, +                intermediates.rxPower + intermediates.txPower + intermediates.inactivePower); +        mStatsLayout.setDeviceCallPowerEstimate(mTmpDeviceStatsArray, intermediates.callPower); +        stats.setDeviceStats(deviceStates, mTmpDeviceStatsArray); +    } + +    /** +     * This step is effectively a no-op in the cases where we track the same states for +     * the entire device and all UIDs (e.g. screen on/off, on-battery/on-charger etc). However, +     * if the lists of tracked states are not the same, we need to combine some estimates +     * before distributing them proportionally to UIDs. +     */ +    private void combineDeviceStateEstimates() { +        for (int i = mPlan.combinedDeviceStateEstimations.size() - 1; i >= 0; i--) { +            CombinedDeviceStateEstimate cdse = mPlan.combinedDeviceStateEstimations.get(i); +            Intermediates cdseIntermediates = new Intermediates(); +            cdse.intermediates = cdseIntermediates; +            List<DeviceStateEstimation> deviceStateEstimations = cdse.deviceStateEstimations; +            for (int j = deviceStateEstimations.size() - 1; j >= 0; j--) { +                DeviceStateEstimation dse = deviceStateEstimations.get(j); +                Intermediates intermediates = (Intermediates) dse.intermediates; +                cdseIntermediates.rxPower += intermediates.rxPower; +                cdseIntermediates.txPower += intermediates.txPower; +                cdseIntermediates.inactivePower += intermediates.inactivePower; +                cdseIntermediates.consumedEnergy += intermediates.consumedEnergy; +            } +        } +    } + +    private void computeUidRxTxTotals(PowerComponentAggregatedPowerStats stats, int uid, +            UidStateEstimate uidStateEstimate) { +        Intermediates intermediates = +                (Intermediates) uidStateEstimate.combinedDeviceStateEstimate.intermediates; +        for (UidStateProportionalEstimate proportionalEstimate : +                uidStateEstimate.proportionalEstimates) { +            if (!stats.getUidStats(mTmpUidStatsArray, uid, proportionalEstimate.stateValues)) { +                continue; +            } + +            intermediates.rxPackets += mStatsLayout.getUidRxPackets(mTmpUidStatsArray); +            intermediates.txPackets += mStatsLayout.getUidTxPackets(mTmpUidStatsArray); +        } +    } + +    private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats, int uid, +            UidStateEstimate uidStateEstimate) { +        Intermediates intermediates = +                (Intermediates) uidStateEstimate.combinedDeviceStateEstimate.intermediates; +        for (UidStateProportionalEstimate proportionalEstimate : +                uidStateEstimate.proportionalEstimates) { +            if (!stats.getUidStats(mTmpUidStatsArray, uid, proportionalEstimate.stateValues)) { +                continue; +            } + +            double power = 0; +            if (intermediates.rxPackets != 0) { +                power += intermediates.rxPower * mStatsLayout.getUidRxPackets(mTmpUidStatsArray) +                        / intermediates.rxPackets; +            } +            if (intermediates.txPackets != 0) { +                power += intermediates.txPower * mStatsLayout.getUidTxPackets(mTmpUidStatsArray) +                        / intermediates.txPackets; +            } + +            mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); +            stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray); + +            if (DEBUG) { +                Slog.d(TAG, "UID: " + uid +                        + " states: " + Arrays.toString(proportionalEstimate.stateValues) +                        + " stats: " + Arrays.toString(mTmpUidStatsArray) +                        + " rx: " + mStatsLayout.getUidRxPackets(mTmpUidStatsArray) +                        + " rx-power: " + intermediates.rxPower +                        + " rx-packets: " + intermediates.rxPackets +                        + " tx: " + mStatsLayout.getUidTxPackets(mTmpUidStatsArray) +                        + " tx-power: " + intermediates.txPower +                        + " tx-packets: " + intermediates.txPackets +                        + " power: " + power); +            } +        } +    } + +    @Override +    String deviceStatsToString(PowerStats.Descriptor descriptor, long[] stats) { +        unpackPowerStatsDescriptor(descriptor); +        return "idle: " + mStatsLayout.getDeviceIdleTime(stats) +                + " sleep: " + mStatsLayout.getDeviceSleepTime(stats) +                + " scan: " + mStatsLayout.getDeviceScanTime(stats) +                + " power: " + mStatsLayout.getDevicePowerEstimate(stats); +    } + +    @Override +    String stateStatsToString(PowerStats.Descriptor descriptor, int key, long[] stats) { +        unpackPowerStatsDescriptor(descriptor); +        StringBuilder sb = new StringBuilder(); +        sb.append(descriptor.getStateLabel(key)); +        sb.append(" rx: ").append(mStatsLayout.getStateRxTime(stats)); +        sb.append(" tx: "); +        for (int txLevel = 0; txLevel < ModemActivityInfo.getNumTxPowerLevels(); txLevel++) { +            if (txLevel != 0) { +                sb.append(", "); +            } +            sb.append(mStatsLayout.getStateTxTime(stats, txLevel)); +        } +        return sb.toString(); +    } + +    @Override +    String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats) { +        unpackPowerStatsDescriptor(descriptor); +        return "rx: " + mStatsLayout.getUidRxPackets(stats) +                + " tx: " + mStatsLayout.getUidTxPackets(stats) +                + " power: " + mStatsLayout.getUidPowerEstimate(stats); +    } +} diff --git a/services/core/java/com/android/server/power/stats/MultiStateStats.java b/services/core/java/com/android/server/power/stats/MultiStateStats.java index 935695008a9a..6c4a2b6e6359 100644 --- a/services/core/java/com/android/server/power/stats/MultiStateStats.java +++ b/services/core/java/com/android/server/power/stats/MultiStateStats.java @@ -288,6 +288,14 @@ public class MultiStateStats {      }      /** +     * Copies time-in-state and timestamps from the supplied prototype. Does not +     * copy accumulated counts. +     */ +    public void copyStatesFrom(MultiStateStats otherStats) { +        mCounter.copyStatesFrom(otherStats.mCounter); +    } + +    /**       * Updates the current composite state by changing one of the States supplied to the Factory       * constructor.       * diff --git a/services/core/java/com/android/server/power/stats/PhoneCallPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/PhoneCallPowerStatsProcessor.java new file mode 100644 index 000000000000..62b653f61373 --- /dev/null +++ b/services/core/java/com/android/server/power/stats/PhoneCallPowerStatsProcessor.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.power.stats; + +import android.os.BatteryConsumer; +import android.os.PersistableBundle; + +import com.android.internal.os.PowerStats; + +public class PhoneCallPowerStatsProcessor extends PowerStatsProcessor { +    private final PowerStatsLayout mStatsLayout; +    private final PowerStats.Descriptor mDescriptor; +    private final long[] mTmpDeviceStats; +    private PowerStats.Descriptor mMobileRadioStatsDescriptor; +    private MobileRadioPowerStatsLayout mMobileRadioStatsLayout; +    private long[] mTmpMobileRadioDeviceStats; + +    public PhoneCallPowerStatsProcessor() { +        mStatsLayout = new PowerStatsLayout(); +        mStatsLayout.addDeviceSectionPowerEstimate(); +        PersistableBundle extras = new PersistableBundle(); +        mStatsLayout.toExtras(extras); +        mDescriptor = new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_PHONE, +                mStatsLayout.getDeviceStatsArrayLength(), null, 0, 0, extras); +        mTmpDeviceStats = new long[mDescriptor.statsArrayLength]; +    } + +    @Override +    void finish(PowerComponentAggregatedPowerStats stats) { +        stats.setPowerStatsDescriptor(mDescriptor); + +        PowerComponentAggregatedPowerStats mobileRadioStats = +                stats.getAggregatedPowerStats().getPowerComponentStats( +                        BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO); +        if (mobileRadioStats == null) { +            return; +        } + +        if (mMobileRadioStatsDescriptor == null) { +            mMobileRadioStatsDescriptor = mobileRadioStats.getPowerStatsDescriptor(); +            if (mMobileRadioStatsDescriptor == null) { +                return; +            } + +            mMobileRadioStatsLayout = +                    new MobileRadioPowerStatsLayout( +                            mMobileRadioStatsDescriptor); +            mTmpMobileRadioDeviceStats = new long[mMobileRadioStatsDescriptor.statsArrayLength]; +        } + +        MultiStateStats.States[] deviceStateConfig = +                mobileRadioStats.getConfig().getDeviceStateConfig(); + +        // Phone call power estimates have already been calculated by the mobile radio stats +        // processor. All that remains to be done is copy the estimates over. +        MultiStateStats.States.forEachTrackedStateCombination(deviceStateConfig, +                states -> { +                    mobileRadioStats.getDeviceStats(mTmpMobileRadioDeviceStats, states); +                    double callPowerEstimate = +                            mMobileRadioStatsLayout.getDeviceCallPowerEstimate( +                                    mTmpMobileRadioDeviceStats); +                    mStatsLayout.setDevicePowerEstimate(mTmpDeviceStats, callPowerEstimate); +                    stats.setDeviceStats(states, mTmpDeviceStats); +                }); +    } + +    @Override +    String deviceStatsToString(PowerStats.Descriptor descriptor, long[] stats) { +        return "power: " + mStatsLayout.getDevicePowerEstimate(stats); +    } + +    @Override +    String stateStatsToString(PowerStats.Descriptor descriptor, int key, long[] stats) { +        // Unsupported for this power component +        return null; +    } + +    @Override +    String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats) { +        // Unsupported for this power component +        return null; +    } +} diff --git a/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java index 1637022f705d..6d58307dbefa 100644 --- a/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java +++ b/services/core/java/com/android/server/power/stats/PowerComponentAggregatedPowerStats.java @@ -18,6 +18,7 @@ package com.android.server.power.stats;  import android.annotation.NonNull;  import android.annotation.Nullable; +import android.os.UserHandle;  import android.util.IndentingPrintWriter;  import android.util.SparseArray; @@ -29,7 +30,10 @@ import org.xmlpull.v1.XmlPullParser;  import org.xmlpull.v1.XmlPullParserException;  import java.io.IOException; +import java.io.StringWriter; +import java.util.Arrays;  import java.util.Collection; +import java.util.function.IntConsumer;  /**   * Aggregated power stats for a specific power component (e.g. CPU, WiFi, etc). This class @@ -41,22 +45,28 @@ class PowerComponentAggregatedPowerStats {      static final String XML_TAG_POWER_COMPONENT = "power_component";      static final String XML_ATTR_ID = "id";      private static final String XML_TAG_DEVICE_STATS = "device-stats"; +    private static final String XML_TAG_STATE_STATS = "state-stats"; +    private static final String XML_ATTR_KEY = "key";      private static final String XML_TAG_UID_STATS = "uid-stats";      private static final String XML_ATTR_UID = "uid";      private static final long UNKNOWN = -1;      public final int powerComponentId; -    private final MultiStateStats.States[] mDeviceStateConfig; -    private final MultiStateStats.States[] mUidStateConfig; +    @NonNull +    private final AggregatedPowerStats mAggregatedPowerStats;      @NonNull      private final AggregatedPowerStatsConfig.PowerComponent mConfig; +    private final MultiStateStats.States[] mDeviceStateConfig; +    private final MultiStateStats.States[] mUidStateConfig;      private final int[] mDeviceStates;      private MultiStateStats.Factory mStatsFactory; +    private MultiStateStats.Factory mStateStatsFactory;      private MultiStateStats.Factory mUidStatsFactory;      private PowerStats.Descriptor mPowerStatsDescriptor;      private long mPowerStatsTimestamp;      private MultiStateStats mDeviceStats; +    private final SparseArray<MultiStateStats> mStateStats = new SparseArray<>();      private final SparseArray<UidStats> mUidStats = new SparseArray<>();      private static class UidStats { @@ -64,7 +74,9 @@ class PowerComponentAggregatedPowerStats {          public MultiStateStats stats;      } -    PowerComponentAggregatedPowerStats(AggregatedPowerStatsConfig.PowerComponent config) { +    PowerComponentAggregatedPowerStats(@NonNull AggregatedPowerStats aggregatedPowerStats, +            @NonNull AggregatedPowerStatsConfig.PowerComponent config) { +        mAggregatedPowerStats = aggregatedPowerStats;          mConfig = config;          powerComponentId = config.getPowerComponentId();          mDeviceStateConfig = config.getDeviceStateConfig(); @@ -74,6 +86,11 @@ class PowerComponentAggregatedPowerStats {      }      @NonNull +    AggregatedPowerStats getAggregatedPowerStats() { +        return mAggregatedPowerStats; +    } + +    @NonNull      public AggregatedPowerStatsConfig.PowerComponent getConfig() {          return mConfig;      } @@ -83,16 +100,25 @@ class PowerComponentAggregatedPowerStats {          return mPowerStatsDescriptor;      } -    void setState(@AggregatedPowerStatsConfig.TrackedState int stateId, int state, long time) { +    public void setPowerStatsDescriptor(PowerStats.Descriptor powerStatsDescriptor) { +        mPowerStatsDescriptor = powerStatsDescriptor; +    } + +    void setState(@AggregatedPowerStatsConfig.TrackedState int stateId, int state, +            long timestampMs) {          if (mDeviceStats == null) { -            createDeviceStats(); +            createDeviceStats(timestampMs);          }          mDeviceStates[stateId] = state;          if (mDeviceStateConfig[stateId].isTracked()) {              if (mDeviceStats != null) { -                mDeviceStats.setState(stateId, state, time); +                mDeviceStats.setState(stateId, state, timestampMs); +            } +            for (int i = mStateStats.size() - 1; i >= 0; i--) { +                MultiStateStats stateStats = mStateStats.valueAt(i); +                stateStats.setState(stateId, state, timestampMs);              }          } @@ -100,36 +126,39 @@ class PowerComponentAggregatedPowerStats {              for (int i = mUidStats.size() - 1; i >= 0; i--) {                  PowerComponentAggregatedPowerStats.UidStats uidStats = mUidStats.valueAt(i);                  if (uidStats.stats == null) { -                    createUidStats(uidStats); +                    createUidStats(uidStats, timestampMs);                  }                  uidStats.states[stateId] = state;                  if (uidStats.stats != null) { -                    uidStats.stats.setState(stateId, state, time); +                    uidStats.stats.setState(stateId, state, timestampMs);                  }              }          }      }      void setUidState(int uid, @AggregatedPowerStatsConfig.TrackedState int stateId, int state, -            long time) { +            long timestampMs) {          if (!mUidStateConfig[stateId].isTracked()) {              return;          }          UidStats uidStats = getUidStats(uid);          if (uidStats.stats == null) { -            createUidStats(uidStats); +            createUidStats(uidStats, timestampMs);          }          uidStats.states[stateId] = state;          if (uidStats.stats != null) { -            uidStats.stats.setState(stateId, state, time); +            uidStats.stats.setState(stateId, state, timestampMs);          }      }      void setDeviceStats(@AggregatedPowerStatsConfig.TrackedState int[] states, long[] values) { +        if (mDeviceStats == null) { +            createDeviceStats(0); +        }          mDeviceStats.setStats(states, values);      } @@ -147,16 +176,24 @@ class PowerComponentAggregatedPowerStats {          mPowerStatsDescriptor = powerStats.descriptor;          if (mDeviceStats == null) { -            createDeviceStats(); +            createDeviceStats(timestampMs);          } +        for (int i = powerStats.stateStats.size() - 1; i >= 0; i--) { +            int key = powerStats.stateStats.keyAt(i); +            MultiStateStats stateStats = mStateStats.get(key); +            if (stateStats == null) { +                stateStats = createStateStats(key, timestampMs); +            } +            stateStats.increment(powerStats.stateStats.valueAt(i), timestampMs); +        }          mDeviceStats.increment(powerStats.stats, timestampMs);          for (int i = powerStats.uidStats.size() - 1; i >= 0; i--) {              int uid = powerStats.uidStats.keyAt(i);              PowerComponentAggregatedPowerStats.UidStats uidStats = getUidStats(uid);              if (uidStats.stats == null) { -                createUidStats(uidStats); +                createUidStats(uidStats, timestampMs);              }              uidStats.stats.increment(powerStats.uidStats.valueAt(i), timestampMs);          } @@ -168,6 +205,7 @@ class PowerComponentAggregatedPowerStats {          mStatsFactory = null;          mUidStatsFactory = null;          mDeviceStats = null; +        mStateStats.clear();          for (int i = mUidStats.size() - 1; i >= 0; i--) {              mUidStats.valueAt(i).stats = null;          } @@ -178,6 +216,13 @@ class PowerComponentAggregatedPowerStats {          if (uidStats == null) {              uidStats = new UidStats();              uidStats.states = new int[mUidStateConfig.length]; +            for (int stateId = 0; stateId < mUidStateConfig.length; stateId++) { +                if (mUidStateConfig[stateId].isTracked() +                        && stateId < mDeviceStateConfig.length +                        && mDeviceStateConfig[stateId].isTracked()) { +                    uidStats.states[stateId] = mDeviceStates[stateId]; +                } +            }              mUidStats.put(uid, uidStats);          }          return uidStats; @@ -204,6 +249,26 @@ class PowerComponentAggregatedPowerStats {          return false;      } +    boolean getStateStats(long[] outValues, int key, int[] deviceStates) { +        if (deviceStates.length != mDeviceStateConfig.length) { +            throw new IllegalArgumentException( +                    "Invalid number of tracked states: " + deviceStates.length +                            + " expected: " + mDeviceStateConfig.length); +        } +        MultiStateStats stateStats = mStateStats.get(key); +        if (stateStats != null) { +            stateStats.getStats(outValues, deviceStates); +            return true; +        } +        return false; +    } + +    void forEachStateStatsKey(IntConsumer consumer) { +        for (int i = mStateStats.size() - 1; i >= 0; i--) { +            consumer.accept(mStateStats.keyAt(i)); +        } +    } +      boolean getUidStats(long[] outValues, int uid, int[] uidStates) {          if (uidStates.length != mUidStateConfig.length) {              throw new IllegalArgumentException( @@ -218,7 +283,7 @@ class PowerComponentAggregatedPowerStats {          return false;      } -    private void createDeviceStats() { +    private void createDeviceStats(long timestampMs) {          if (mStatsFactory == null) {              if (mPowerStatsDescriptor == null) {                  return; @@ -229,13 +294,39 @@ class PowerComponentAggregatedPowerStats {          mDeviceStats = mStatsFactory.create();          if (mPowerStatsTimestamp != UNKNOWN) { +            timestampMs = mPowerStatsTimestamp; +        } +        if (timestampMs != UNKNOWN) {              for (int stateId = 0; stateId < mDeviceStateConfig.length; stateId++) { -                mDeviceStats.setState(stateId, mDeviceStates[stateId], mPowerStatsTimestamp); +                int state = mDeviceStates[stateId]; +                mDeviceStats.setState(stateId, state, timestampMs); +                for (int i = mStateStats.size() - 1; i >= 0; i--) { +                    MultiStateStats stateStats = mStateStats.valueAt(i); +                    stateStats.setState(stateId, state, timestampMs); +                } +            } +        } +    } + +    private MultiStateStats createStateStats(int key, long timestampMs) { +        if (mStateStatsFactory == null) { +            if (mPowerStatsDescriptor == null) { +                return null;              } +            mStateStatsFactory = new MultiStateStats.Factory( +                    mPowerStatsDescriptor.stateStatsArrayLength, mDeviceStateConfig);          } + +        MultiStateStats stateStats = mStateStatsFactory.create(); +        mStateStats.put(key, stateStats); +        if (mDeviceStats != null) { +            stateStats.copyStatesFrom(mDeviceStats); +        } + +        return stateStats;      } -    private void createUidStats(UidStats uidStats) { +    private void createUidStats(UidStats uidStats, long timestampMs) {          if (mUidStatsFactory == null) {              if (mPowerStatsDescriptor == null) {                  return; @@ -245,9 +336,13 @@ class PowerComponentAggregatedPowerStats {          }          uidStats.stats = mUidStatsFactory.create(); -        for (int stateId = 0; stateId < mUidStateConfig.length; stateId++) { -            if (mPowerStatsTimestamp != UNKNOWN) { -                uidStats.stats.setState(stateId, uidStats.states[stateId], mPowerStatsTimestamp); + +        if (mPowerStatsTimestamp != UNKNOWN) { +            timestampMs = mPowerStatsTimestamp; +        } +        if (timestampMs != UNKNOWN) { +            for (int stateId = 0; stateId < mUidStateConfig.length; stateId++) { +                uidStats.stats.setState(stateId, uidStats.states[stateId], timestampMs);              }          }      } @@ -268,6 +363,13 @@ class PowerComponentAggregatedPowerStats {              serializer.endTag(null, XML_TAG_DEVICE_STATS);          } +        for (int i = 0; i < mStateStats.size(); i++) { +            serializer.startTag(null, XML_TAG_STATE_STATS); +            serializer.attributeInt(null, XML_ATTR_KEY, mStateStats.keyAt(i)); +            mStateStats.valueAt(i).writeXml(serializer); +            serializer.endTag(null, XML_TAG_STATE_STATS); +        } +          for (int i = mUidStats.size() - 1; i >= 0; i--) {              int uid = mUidStats.keyAt(i);              UidStats uidStats = mUidStats.valueAt(i); @@ -285,8 +387,10 @@ class PowerComponentAggregatedPowerStats {      public boolean readFromXml(TypedXmlPullParser parser) throws XmlPullParserException,              IOException { +        String outerTag = parser.getName();          int eventType = parser.getEventType(); -        while (eventType != XmlPullParser.END_DOCUMENT) { +        while (eventType != XmlPullParser.END_DOCUMENT +                && !(eventType == XmlPullParser.END_TAG && parser.getName().equals(outerTag))) {              if (eventType == XmlPullParser.START_TAG) {                  switch (parser.getName()) {                      case PowerStats.Descriptor.XML_TAG_DESCRIPTOR: @@ -297,17 +401,27 @@ class PowerComponentAggregatedPowerStats {                          break;                      case XML_TAG_DEVICE_STATS:                          if (mDeviceStats == null) { -                            createDeviceStats(); +                            createDeviceStats(UNKNOWN);                          }                          if (!mDeviceStats.readFromXml(parser)) {                              return false;                          }                          break; +                    case XML_TAG_STATE_STATS: +                        int key = parser.getAttributeInt(null, XML_ATTR_KEY); +                        MultiStateStats stats = mStateStats.get(key); +                        if (stats == null) { +                            stats = createStateStats(key, UNKNOWN); +                        } +                        if (!stats.readFromXml(parser)) { +                            return false; +                        } +                        break;                      case XML_TAG_UID_STATS:                          int uid = parser.getAttributeInt(null, XML_ATTR_UID);                          UidStats uidStats = getUidStats(uid);                          if (uidStats.stats == null) { -                            createUidStats(uidStats); +                            createUidStats(uidStats, UNKNOWN);                          }                          if (!uidStats.stats.readFromXml(parser)) {                              return false; @@ -328,6 +442,21 @@ class PowerComponentAggregatedPowerStats {                      mConfig.getProcessor().deviceStatsToString(mPowerStatsDescriptor, stats));              ipw.decreaseIndent();          } + +        if (mStateStats.size() != 0) { +            ipw.increaseIndent(); +            ipw.println(mPowerStatsDescriptor.name + " states"); +            ipw.increaseIndent(); +            for (int i = 0; i < mStateStats.size(); i++) { +                int key = mStateStats.keyAt(i); +                MultiStateStats stateStats = mStateStats.valueAt(i); +                stateStats.dump(ipw, stats -> +                        mConfig.getProcessor().stateStatsToString(mPowerStatsDescriptor, key, +                                stats)); +            } +            ipw.decreaseIndent(); +            ipw.decreaseIndent(); +        }      }      void dumpUid(IndentingPrintWriter ipw, int uid) { @@ -340,4 +469,29 @@ class PowerComponentAggregatedPowerStats {              ipw.decreaseIndent();          }      } + +    @Override +    public String toString() { +        StringWriter sw = new StringWriter(); +        IndentingPrintWriter ipw = new IndentingPrintWriter(sw); +        ipw.increaseIndent(); +        dumpDevice(ipw); +        ipw.decreaseIndent(); + +        int[] uids = new int[mUidStats.size()]; +        for (int i = uids.length - 1; i >= 0; i--) { +            uids[i] = mUidStats.keyAt(i); +        } +        Arrays.sort(uids); +        for (int uid : uids) { +            ipw.println(UserHandle.formatUid(uid)); +            ipw.increaseIndent(); +            dumpUid(ipw, uid); +            ipw.decreaseIndent(); +        } + +        ipw.flush(); + +        return sw.toString(); +    }  } diff --git a/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java index ba4c127ac3d0..6a4c1f0406a9 100644 --- a/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java +++ b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java @@ -32,7 +32,7 @@ public class PowerStatsAggregator {      private static final long UNINITIALIZED = -1;      private final AggregatedPowerStatsConfig mAggregatedPowerStatsConfig;      private final BatteryStatsHistory mHistory; -    private final SparseArray<AggregatedPowerStatsProcessor> mProcessors = new SparseArray<>(); +    private final SparseArray<PowerStatsProcessor> mProcessors = new SparseArray<>();      private AggregatedPowerStats mStats;      private int mCurrentBatteryState = AggregatedPowerStatsConfig.POWER_STATE_BATTERY;      private int mCurrentScreenState = AggregatedPowerStatsConfig.SCREEN_STATE_OTHER; @@ -43,7 +43,7 @@ public class PowerStatsAggregator {          mHistory = history;          for (AggregatedPowerStatsConfig.PowerComponent powerComponentsConfig :                  aggregatedPowerStatsConfig.getPowerComponentsAggregatedStatsConfigs()) { -            AggregatedPowerStatsProcessor processor = powerComponentsConfig.getProcessor(); +            PowerStatsProcessor processor = powerComponentsConfig.getProcessor();              mProcessors.put(powerComponentsConfig.getPowerComponentId(), processor);          }      } diff --git a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java index c76797bad66d..5dd11db2a2fc 100644 --- a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java +++ b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java @@ -17,9 +17,12 @@  package com.android.server.power.stats;  import android.annotation.Nullable; +import android.hardware.power.stats.EnergyConsumer; +import android.hardware.power.stats.EnergyConsumerResult; +import android.hardware.power.stats.EnergyConsumerType;  import android.os.ConditionVariable;  import android.os.Handler; -import android.os.PersistableBundle; +import android.power.PowerStatsInternal;  import android.util.IndentingPrintWriter;  import android.util.Slog; @@ -30,7 +33,12 @@ import com.android.internal.os.PowerStats;  import java.io.PrintWriter;  import java.util.ArrayList;  import java.util.Collections; +import java.util.Comparator;  import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException;  import java.util.function.Consumer;  /** @@ -43,6 +51,7 @@ import java.util.function.Consumer;  public abstract class PowerStatsCollector {      private static final String TAG = "PowerStatsCollector";      private static final int MILLIVOLTS_PER_VOLT = 1000; +    private static final long POWER_STATS_ENERGY_CONSUMERS_TIMEOUT = 20000;      private final Handler mHandler;      protected final Clock mClock;      private final long mThrottlePeriodMs; @@ -50,200 +59,6 @@ public abstract class PowerStatsCollector {      private boolean mEnabled;      private long mLastScheduledUpdateMs = -1; -    /** -     * Captures the positions and lengths of sections of the stats array, such as usage duration, -     * power usage estimates etc. -     */ -    public static class StatsArrayLayout { -        private static final String EXTRA_DEVICE_POWER_POSITION = "dp"; -        private static final String EXTRA_DEVICE_DURATION_POSITION = "dd"; -        private static final String EXTRA_DEVICE_ENERGY_CONSUMERS_POSITION = "de"; -        private static final String EXTRA_DEVICE_ENERGY_CONSUMERS_COUNT = "dec"; -        private static final String EXTRA_UID_POWER_POSITION = "up"; - -        protected static final double MILLI_TO_NANO_MULTIPLIER = 1000000.0; - -        private int mDeviceStatsArrayLength; -        private int mUidStatsArrayLength; - -        protected int mDeviceDurationPosition; -        private int mDeviceEnergyConsumerPosition; -        private int mDeviceEnergyConsumerCount; -        private int mDevicePowerEstimatePosition; -        private int mUidPowerEstimatePosition; - -        public int getDeviceStatsArrayLength() { -            return mDeviceStatsArrayLength; -        } - -        public int getUidStatsArrayLength() { -            return mUidStatsArrayLength; -        } - -        protected int addDeviceSection(int length) { -            int position = mDeviceStatsArrayLength; -            mDeviceStatsArrayLength += length; -            return position; -        } - -        protected int addUidSection(int length) { -            int position = mUidStatsArrayLength; -            mUidStatsArrayLength += length; -            return position; -        } - -        /** -         * Declare that the stats array has a section capturing usage duration -         */ -        public void addDeviceSectionUsageDuration() { -            mDeviceDurationPosition = addDeviceSection(1); -        } - -        /** -         * Saves the usage duration in the corresponding <code>stats</code> element. -         */ -        public void setUsageDuration(long[] stats, long value) { -            stats[mDeviceDurationPosition] = value; -        } - -        /** -         * Extracts the usage duration from the corresponding <code>stats</code> element. -         */ -        public long getUsageDuration(long[] stats) { -            return stats[mDeviceDurationPosition]; -        } - -        /** -         * Declares that the stats array has a section capturing EnergyConsumer data from -         * PowerStatsService. -         */ -        public void addDeviceSectionEnergyConsumers(int energyConsumerCount) { -            mDeviceEnergyConsumerPosition = addDeviceSection(energyConsumerCount); -            mDeviceEnergyConsumerCount = energyConsumerCount; -        } - -        public int getEnergyConsumerCount() { -            return mDeviceEnergyConsumerCount; -        } - -        /** -         * Saves the accumulated energy for the specified rail the corresponding -         * <code>stats</code> element. -         */ -        public void setConsumedEnergy(long[] stats, int index, long energy) { -            stats[mDeviceEnergyConsumerPosition + index] = energy; -        } - -        /** -         * Extracts the EnergyConsumer data from a device stats array for the specified -         * EnergyConsumer. -         */ -        public long getConsumedEnergy(long[] stats, int index) { -            return stats[mDeviceEnergyConsumerPosition + index]; -        } - -        /** -         * Declare that the stats array has a section capturing a power estimate -         */ -        public void addDeviceSectionPowerEstimate() { -            mDevicePowerEstimatePosition = addDeviceSection(1); -        } - -        /** -         * Converts the supplied mAh power estimate to a long and saves it in the corresponding -         * element of <code>stats</code>. -         */ -        public void setDevicePowerEstimate(long[] stats, double power) { -            stats[mDevicePowerEstimatePosition] = (long) (power * MILLI_TO_NANO_MULTIPLIER); -        } - -        /** -         * Extracts the power estimate from a device stats array and converts it to mAh. -         */ -        public double getDevicePowerEstimate(long[] stats) { -            return stats[mDevicePowerEstimatePosition] / MILLI_TO_NANO_MULTIPLIER; -        } - -        /** -         * Declare that the UID stats array has a section capturing a power estimate -         */ -        public void addUidSectionPowerEstimate() { -            mUidPowerEstimatePosition = addUidSection(1); -        } - -        /** -         * Converts the supplied mAh power estimate to a long and saves it in the corresponding -         * element of <code>stats</code>. -         */ -        public void setUidPowerEstimate(long[] stats, double power) { -            stats[mUidPowerEstimatePosition] = (long) (power * MILLI_TO_NANO_MULTIPLIER); -        } - -        /** -         * Extracts the power estimate from a UID stats array and converts it to mAh. -         */ -        public double getUidPowerEstimate(long[] stats) { -            return stats[mUidPowerEstimatePosition] / MILLI_TO_NANO_MULTIPLIER; -        } - -        /** -         * Copies the elements of the stats array layout into <code>extras</code> -         */ -        public void toExtras(PersistableBundle extras) { -            extras.putInt(EXTRA_DEVICE_DURATION_POSITION, mDeviceDurationPosition); -            extras.putInt(EXTRA_DEVICE_ENERGY_CONSUMERS_POSITION, -                    mDeviceEnergyConsumerPosition); -            extras.putInt(EXTRA_DEVICE_ENERGY_CONSUMERS_COUNT, -                    mDeviceEnergyConsumerCount); -            extras.putInt(EXTRA_DEVICE_POWER_POSITION, mDevicePowerEstimatePosition); -            extras.putInt(EXTRA_UID_POWER_POSITION, mUidPowerEstimatePosition); -        } - -        /** -         * Retrieves elements of the stats array layout from <code>extras</code> -         */ -        public void fromExtras(PersistableBundle extras) { -            mDeviceDurationPosition = extras.getInt(EXTRA_DEVICE_DURATION_POSITION); -            mDeviceEnergyConsumerPosition = extras.getInt(EXTRA_DEVICE_ENERGY_CONSUMERS_POSITION); -            mDeviceEnergyConsumerCount = extras.getInt(EXTRA_DEVICE_ENERGY_CONSUMERS_COUNT); -            mDevicePowerEstimatePosition = extras.getInt(EXTRA_DEVICE_POWER_POSITION); -            mUidPowerEstimatePosition = extras.getInt(EXTRA_UID_POWER_POSITION); -        } - -        protected void putIntArray(PersistableBundle extras, String key, int[] array) { -            if (array == null) { -                return; -            } - -            StringBuilder sb = new StringBuilder(); -            for (int value : array) { -                if (!sb.isEmpty()) { -                    sb.append(','); -                } -                sb.append(value); -            } -            extras.putString(key, sb.toString()); -        } - -        protected int[] getIntArray(PersistableBundle extras, String key) { -            String string = extras.getString(key); -            if (string == null) { -                return null; -            } -            String[] values = string.trim().split(","); -            int[] result = new int[values.length]; -            for (int i = 0; i < values.length; i++) { -                try { -                    result[i] = Integer.parseInt(values[i]); -                } catch (NumberFormatException e) { -                    Slog.wtf(TAG, "Invalid CSV format: " + string); -                    return null; -                } -            } -            return result; -        } -    } -      @GuardedBy("this")      @SuppressWarnings("unchecked")      private volatile List<Consumer<PowerStats>> mConsumerList = Collections.emptyList(); @@ -389,9 +204,83 @@ public abstract class PowerStatsCollector {      }      /** Calculate charge consumption (in microcoulombs) from a given energy and voltage */ -    protected long uJtoUc(long deltaEnergyUj, int avgVoltageMv) { +    protected static long uJtoUc(long deltaEnergyUj, int avgVoltageMv) {          // To overflow, a 3.7V 10000mAh battery would need to completely drain 69244 times          // since the last snapshot. Round off to the nearest whole long.          return (deltaEnergyUj * MILLIVOLTS_PER_VOLT + (avgVoltageMv / 2)) / avgVoltageMv;      } + +    interface ConsumedEnergyRetriever { +        int[] getEnergyConsumerIds(@EnergyConsumerType int energyConsumerType); + +        @Nullable +        long[] getConsumedEnergyUws(int[] energyConsumerIds); +    } + +    static class ConsumedEnergyRetrieverImpl implements ConsumedEnergyRetriever { +        private final PowerStatsInternal mPowerStatsInternal; + +        ConsumedEnergyRetrieverImpl(PowerStatsInternal powerStatsInternal) { +            mPowerStatsInternal = powerStatsInternal; +        } + +        @Override +        public int[] getEnergyConsumerIds(int energyConsumerType) { +            if (mPowerStatsInternal == null) { +                return new int[0]; +            } + +            EnergyConsumer[] energyConsumerInfo = mPowerStatsInternal.getEnergyConsumerInfo(); +            if (energyConsumerInfo == null) { +                return new int[0]; +            } + +            List<EnergyConsumer> energyConsumers = new ArrayList<>(); +            for (EnergyConsumer energyConsumer : energyConsumerInfo) { +                if (energyConsumer.type == energyConsumerType) { +                    energyConsumers.add(energyConsumer); +                } +            } +            if (energyConsumers.isEmpty()) { +                return new int[0]; +            } + +            energyConsumers.sort(Comparator.comparing(c -> c.ordinal)); + +            int[] ids = new int[energyConsumers.size()]; +            for (int i = 0; i < ids.length; i++) { +                ids[i] = energyConsumers.get(i).id; +            } +            return ids; +        } + +        @Override +        public long[] getConsumedEnergyUws(int[] energyConsumerIds) { +            CompletableFuture<EnergyConsumerResult[]> future = +                    mPowerStatsInternal.getEnergyConsumedAsync(energyConsumerIds); +            EnergyConsumerResult[] results = null; +            try { +                results = future.get( +                        POWER_STATS_ENERGY_CONSUMERS_TIMEOUT, TimeUnit.MILLISECONDS); +            } catch (InterruptedException | ExecutionException | TimeoutException e) { +                Slog.e(TAG, "Could not obtain energy consumers from PowerStatsService", e); +            } + +            if (results == null) { +                return null; +            } + +            long[] energy = new long[energyConsumerIds.length]; +            for (int i = 0; i < energyConsumerIds.length; i++) { +                int id = energyConsumerIds[i]; +                for (EnergyConsumerResult result : results) { +                    if (result.id == id) { +                        energy[i] = result.energyUWs; +                        break; +                    } +                } +            } +            return energy; +        } +    }  } diff --git a/services/core/java/com/android/server/power/stats/PowerStatsExporter.java b/services/core/java/com/android/server/power/stats/PowerStatsExporter.java index 4f4ddca6c3fc..f6b198a88fc2 100644 --- a/services/core/java/com/android/server/power/stats/PowerStatsExporter.java +++ b/services/core/java/com/android/server/power/stats/PowerStatsExporter.java @@ -139,7 +139,7 @@ public class PowerStatsExporter {              return;          } -        PowerStatsCollector.StatsArrayLayout layout = new PowerStatsCollector.StatsArrayLayout(); +        PowerStatsLayout layout = new PowerStatsLayout();          layout.fromExtras(descriptor.extras);          long[] deviceStats = new long[descriptor.statsArrayLength]; @@ -164,9 +164,20 @@ public class PowerStatsExporter {          deviceScope.addConsumedPower(powerComponentId,                  totalPower[0], BatteryConsumer.POWER_MODEL_UNDEFINED); +        if (layout.isUidPowerAttributionSupported()) { +            populateUidBatteryConsumers(batteryUsageStatsBuilder, powerComponent, +                    powerComponentStats, layout); +        } +    } + +    private static void populateUidBatteryConsumers( +            BatteryUsageStats.Builder batteryUsageStatsBuilder, +            AggregatedPowerStatsConfig.PowerComponent powerComponent, +            PowerComponentAggregatedPowerStats powerComponentStats, +            PowerStatsLayout layout) { +        int powerComponentId = powerComponent.getPowerComponentId(); +        PowerStats.Descriptor descriptor = powerComponentStats.getPowerStatsDescriptor();          long[] uidStats = new long[descriptor.uidStatsArrayLength]; -        ArrayList<Integer> uids = new ArrayList<>(); -        powerComponentStats.collectUids(uids);          boolean breakDownByProcState =                  batteryUsageStatsBuilder.isProcessStateDataNeeded() @@ -177,6 +188,8 @@ public class PowerStatsExporter {          double[] powerByProcState =                  new double[breakDownByProcState ? BatteryConsumer.PROCESS_STATE_COUNT : 1];          double powerAllApps = 0; +        ArrayList<Integer> uids = new ArrayList<>(); +        powerComponentStats.collectUids(uids);          for (int uid : uids) {              UidBatteryConsumer.Builder builder =                      batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uid); diff --git a/services/core/java/com/android/server/power/stats/PowerStatsLayout.java b/services/core/java/com/android/server/power/stats/PowerStatsLayout.java new file mode 100644 index 000000000000..aa96409e85e9 --- /dev/null +++ b/services/core/java/com/android/server/power/stats/PowerStatsLayout.java @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.power.stats; + +import android.os.PersistableBundle; +import android.util.Slog; + +import com.android.internal.os.PowerStats; + +/** + * Captures the positions and lengths of sections of the stats array, such as usage duration, + * power usage estimates etc. + */ +public class PowerStatsLayout { +    private static final String TAG = "PowerStatsLayout"; +    private static final String EXTRA_DEVICE_POWER_POSITION = "dp"; +    private static final String EXTRA_DEVICE_DURATION_POSITION = "dd"; +    private static final String EXTRA_DEVICE_ENERGY_CONSUMERS_POSITION = "de"; +    private static final String EXTRA_DEVICE_ENERGY_CONSUMERS_COUNT = "dec"; +    private static final String EXTRA_UID_POWER_POSITION = "up"; + +    protected static final double MILLI_TO_NANO_MULTIPLIER = 1000000.0; +    protected static final int UNSUPPORTED = -1; + +    private int mDeviceStatsArrayLength; +    private int mStateStatsArrayLength; +    private int mUidStatsArrayLength; + +    protected int mDeviceDurationPosition = UNSUPPORTED; +    private int mDeviceEnergyConsumerPosition; +    private int mDeviceEnergyConsumerCount; +    private int mDevicePowerEstimatePosition = UNSUPPORTED; +    private int mUidPowerEstimatePosition = UNSUPPORTED; + +    public PowerStatsLayout() { +    } + +    public PowerStatsLayout(PowerStats.Descriptor descriptor) { +        fromExtras(descriptor.extras); +    } + +    public int getDeviceStatsArrayLength() { +        return mDeviceStatsArrayLength; +    } + +    public int getStateStatsArrayLength() { +        return mStateStatsArrayLength; +    } + +    public int getUidStatsArrayLength() { +        return mUidStatsArrayLength; +    } + +    protected int addDeviceSection(int length) { +        int position = mDeviceStatsArrayLength; +        mDeviceStatsArrayLength += length; +        return position; +    } + +    protected int addStateSection(int length) { +        int position = mStateStatsArrayLength; +        mStateStatsArrayLength += length; +        return position; +    } + +    protected int addUidSection(int length) { +        int position = mUidStatsArrayLength; +        mUidStatsArrayLength += length; +        return position; +    } + +    /** +     * Declare that the stats array has a section capturing usage duration +     */ +    public void addDeviceSectionUsageDuration() { +        mDeviceDurationPosition = addDeviceSection(1); +    } + +    /** +     * Saves the usage duration in the corresponding <code>stats</code> element. +     */ +    public void setUsageDuration(long[] stats, long value) { +        stats[mDeviceDurationPosition] = value; +    } + +    /** +     * Extracts the usage duration from the corresponding <code>stats</code> element. +     */ +    public long getUsageDuration(long[] stats) { +        return stats[mDeviceDurationPosition]; +    } + +    /** +     * Declares that the stats array has a section capturing EnergyConsumer data from +     * PowerStatsService. +     */ +    public void addDeviceSectionEnergyConsumers(int energyConsumerCount) { +        mDeviceEnergyConsumerPosition = addDeviceSection(energyConsumerCount); +        mDeviceEnergyConsumerCount = energyConsumerCount; +    } + +    public int getEnergyConsumerCount() { +        return mDeviceEnergyConsumerCount; +    } + +    /** +     * Saves the accumulated energy for the specified rail the corresponding +     * <code>stats</code> element. +     */ +    public void setConsumedEnergy(long[] stats, int index, long energy) { +        stats[mDeviceEnergyConsumerPosition + index] = energy; +    } + +    /** +     * Extracts the EnergyConsumer data from a device stats array for the specified +     * EnergyConsumer. +     */ +    public long getConsumedEnergy(long[] stats, int index) { +        return stats[mDeviceEnergyConsumerPosition + index]; +    } + +    /** +     * Declare that the stats array has a section capturing a power estimate +     */ +    public void addDeviceSectionPowerEstimate() { +        mDevicePowerEstimatePosition = addDeviceSection(1); +    } + +    /** +     * Converts the supplied mAh power estimate to a long and saves it in the corresponding +     * element of <code>stats</code>. +     */ +    public void setDevicePowerEstimate(long[] stats, double power) { +        stats[mDevicePowerEstimatePosition] = (long) (power * MILLI_TO_NANO_MULTIPLIER); +    } + +    /** +     * Extracts the power estimate from a device stats array and converts it to mAh. +     */ +    public double getDevicePowerEstimate(long[] stats) { +        return stats[mDevicePowerEstimatePosition] / MILLI_TO_NANO_MULTIPLIER; +    } + +    /** +     * Declare that the UID stats array has a section capturing a power estimate +     */ +    public void addUidSectionPowerEstimate() { +        mUidPowerEstimatePosition = addUidSection(1); +    } + +    /** +     * Returns true if power for this component is attributed to UIDs (apps). +     */ +    public boolean isUidPowerAttributionSupported() { +        return mUidPowerEstimatePosition != UNSUPPORTED; +    } + +    /** +     * Converts the supplied mAh power estimate to a long and saves it in the corresponding +     * element of <code>stats</code>. +     */ +    public void setUidPowerEstimate(long[] stats, double power) { +        stats[mUidPowerEstimatePosition] = (long) (power * MILLI_TO_NANO_MULTIPLIER); +    } + +    /** +     * Extracts the power estimate from a UID stats array and converts it to mAh. +     */ +    public double getUidPowerEstimate(long[] stats) { +        return stats[mUidPowerEstimatePosition] / MILLI_TO_NANO_MULTIPLIER; +    } + +    /** +     * Copies the elements of the stats array layout into <code>extras</code> +     */ +    public void toExtras(PersistableBundle extras) { +        extras.putInt(EXTRA_DEVICE_DURATION_POSITION, mDeviceDurationPosition); +        extras.putInt(EXTRA_DEVICE_ENERGY_CONSUMERS_POSITION, +                mDeviceEnergyConsumerPosition); +        extras.putInt(EXTRA_DEVICE_ENERGY_CONSUMERS_COUNT, +                mDeviceEnergyConsumerCount); +        extras.putInt(EXTRA_DEVICE_POWER_POSITION, mDevicePowerEstimatePosition); +        extras.putInt(EXTRA_UID_POWER_POSITION, mUidPowerEstimatePosition); +    } + +    /** +     * Retrieves elements of the stats array layout from <code>extras</code> +     */ +    public void fromExtras(PersistableBundle extras) { +        mDeviceDurationPosition = extras.getInt(EXTRA_DEVICE_DURATION_POSITION); +        mDeviceEnergyConsumerPosition = extras.getInt(EXTRA_DEVICE_ENERGY_CONSUMERS_POSITION); +        mDeviceEnergyConsumerCount = extras.getInt(EXTRA_DEVICE_ENERGY_CONSUMERS_COUNT); +        mDevicePowerEstimatePosition = extras.getInt(EXTRA_DEVICE_POWER_POSITION); +        mUidPowerEstimatePosition = extras.getInt(EXTRA_UID_POWER_POSITION); +    } + +    protected void putIntArray(PersistableBundle extras, String key, int[] array) { +        if (array == null) { +            return; +        } + +        StringBuilder sb = new StringBuilder(); +        for (int value : array) { +            if (!sb.isEmpty()) { +                sb.append(','); +            } +            sb.append(value); +        } +        extras.putString(key, sb.toString()); +    } + +    protected int[] getIntArray(PersistableBundle extras, String key) { +        String string = extras.getString(key); +        if (string == null) { +            return null; +        } +        String[] values = string.trim().split(","); +        int[] result = new int[values.length]; +        for (int i = 0; i < values.length; i++) { +            try { +                result[i] = Integer.parseInt(values[i]); +            } catch (NumberFormatException e) { +                Slog.wtf(TAG, "Invalid CSV format: " + string); +                return null; +            } +        } +        return result; +    } +} diff --git a/services/core/java/com/android/server/power/stats/AggregatedPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/PowerStatsProcessor.java index 7feb9643fb8f..0d5c5422b45c 100644 --- a/services/core/java/com/android/server/power/stats/AggregatedPowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/PowerStatsProcessor.java @@ -27,7 +27,7 @@ import java.util.Collections;  import java.util.List;  /* - * The power estimation algorithm used by AggregatedPowerStatsProcessor can roughly be + * The power estimation algorithm used by PowerStatsProcessor can roughly be   * described like this:   *   * 1. Estimate power usage for each state combination (e.g. power-battery/screen-on) using @@ -39,8 +39,8 @@ import java.util.List;   * 2. For each UID, compute the proportion of the combined estimates in each state   * and attribute the corresponding portion of the total power estimate in that state to the UID.   */ -abstract class AggregatedPowerStatsProcessor { -    private static final String TAG = "AggregatedPowerStatsProcessor"; +abstract class PowerStatsProcessor { +    private static final String TAG = "PowerStatsProcessor";      private static final int INDEX_DOES_NOT_EXIST = -1;      private static final double MILLIAMPHOUR_PER_MICROCOULOMB = 1.0 / 1000.0 / 60.0 / 60.0; @@ -49,6 +49,8 @@ abstract class AggregatedPowerStatsProcessor {      abstract String deviceStatsToString(PowerStats.Descriptor descriptor, long[] stats); +    abstract String stateStatsToString(PowerStats.Descriptor descriptor, int key, long[] stats); +      abstract String uidStatsToString(PowerStats.Descriptor descriptor, long[] stats);      protected static class PowerEstimationPlan { diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 2a9325544833..c8bcc5128c3a 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -54,8 +54,10 @@ import android.os.UserHandle;  import android.os.UserManager;  import android.os.ext.SdkExtensions;  import android.provider.DeviceConfig; +import android.util.ArrayMap;  import android.util.Log;  import android.util.LongArrayQueue; +import android.util.Pair;  import android.util.Slog;  import android.util.SparseBooleanArray;  import android.util.SparseIntArray; @@ -173,6 +175,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba      // Accessed on the handler thread only.      private long  mRelativeBootTime = calculateRelativeBootTime(); +    private final ArrayMap<Integer, Pair<Context, BroadcastReceiver>> mUserBroadcastReceivers; +      RollbackManagerServiceImpl(Context context) {          mContext = context;          // Note that we're calling onStart here because this object is only constructed on @@ -210,6 +214,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba              }          }); +        mUserBroadcastReceivers = new ArrayMap<>(); +          UserManager userManager = mContext.getSystemService(UserManager.class);          for (UserHandle user : userManager.getUserHandles(true)) {              registerUserCallbacks(user); @@ -275,7 +281,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba              }          }, enableRollbackTimedOutFilter, null, getHandler()); -        IntentFilter userAddedIntentFilter = new IntentFilter(Intent.ACTION_USER_ADDED); +        IntentFilter userIntentFilter = new IntentFilter(); +        userIntentFilter.addAction(Intent.ACTION_USER_ADDED); +        userIntentFilter.addAction(Intent.ACTION_USER_REMOVED);          mContext.registerReceiver(new BroadcastReceiver() {              @Override              public void onReceive(Context context, Intent intent) { @@ -287,9 +295,15 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba                          return;                      }                      registerUserCallbacks(UserHandle.of(newUserId)); +                } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { +                    final int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); +                    if (newUserId == -1) { +                        return; +                    } +                    unregisterUserCallbacks(UserHandle.of(newUserId));                  }              } -        }, userAddedIntentFilter, null, getHandler()); +        }, userIntentFilter, null, getHandler());          registerTimeChangeReceiver();      } @@ -335,7 +349,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba          filter.addAction(Intent.ACTION_PACKAGE_REPLACED);          filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);          filter.addDataScheme("package"); -        context.registerReceiver(new BroadcastReceiver() { +        BroadcastReceiver receiver = new BroadcastReceiver() {              @Override              public void onReceive(Context context, Intent intent) {                  assertInWorkerThread(); @@ -354,7 +368,21 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba                      onPackageFullyRemoved(packageName);                  }              } -        }, filter, null, getHandler()); +        }; +        context.registerReceiver(receiver, filter, null, getHandler()); +        mUserBroadcastReceivers.put(user.getIdentifier(), new Pair(context, receiver)); +    } + +    @AnyThread +    private void unregisterUserCallbacks(UserHandle user) { +        Pair<Context, BroadcastReceiver> pair = mUserBroadcastReceivers.get(user.getIdentifier()); +        if (pair == null || pair.first == null || pair.second == null) { +            Slog.e(TAG, "No receiver found for the user" + user); +            return; +        } + +        pair.first.unregisterReceiver(pair.second); +        mUserBroadcastReceivers.remove(user.getIdentifier());      }      @ExtThread diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index 2ff38616fce5..e4f60ec2cdb8 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -22,6 +22,7 @@ import android.content.ComponentName;  import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;  import android.os.Bundle;  import android.os.IBinder; +import android.os.UserHandle;  import android.view.WindowInsets.Type.InsetsType;  import android.view.WindowInsetsController.Appearance;  import android.view.WindowInsetsController.Behavior; @@ -248,10 +249,10 @@ public interface StatusBarManagerInternal {      /**       * Shows the media output switcher dialog.       * -     * @param packageName of the session for which the output switcher is shown. +     * @param targetPackageName of the session for which the output switcher is shown.       * @see com.android.internal.statusbar.IStatusBar#showMediaOutputSwitcher       */ -    void showMediaOutputSwitcher(String packageName); +    void showMediaOutputSwitcher(String targetPackageName, UserHandle targetUserHandle);      /**       * Add a tile to the Quick Settings Panel diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index cca5beb13405..2c67207f407c 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -850,11 +850,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D          }          @Override -        public void showMediaOutputSwitcher(String packageName) { +        public void showMediaOutputSwitcher(String targetPackageName, UserHandle targetUserHandle) {              IStatusBar bar = mBar;              if (bar != null) {                  try { -                    bar.showMediaOutputSwitcher(packageName); +                    bar.showMediaOutputSwitcher(targetPackageName, targetUserHandle);                  } catch (RemoteException ex) {                  }              } diff --git a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java index 58c31d565cf3..ad2c3e83b041 100644 --- a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java +++ b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java @@ -39,6 +39,9 @@ import android.content.Intent;  import android.content.IntentFilter;  import android.content.pm.PackageManager;  import android.database.ContentObserver; +import android.os.Bundle; +import android.os.Handler; +import android.os.IUserRestrictionsListener;  import android.os.UserHandle;  import android.os.UserManager;  import android.provider.Settings; @@ -136,9 +139,11 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {              }          }, filter, null, null /* main thread */); +        Handler mainThreadHandler = mContext.getMainThreadHandler(); +          // Add async callbacks for global settings being changed.          ContentResolver contentResolver = mContext.getContentResolver(); -        ContentObserver contentObserver = new ContentObserver(mContext.getMainThreadHandler()) { +        ContentObserver contentObserver = new ContentObserver(mainThreadHandler) {              @Override              public void onChange(boolean selfChange) {                  handleConfigurationInternalChangeOnMainThread(); @@ -150,6 +155,20 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {          // Watch server flags.          mServerFlags.addListener(this::handleConfigurationInternalChangeOnMainThread,                  SERVER_FLAGS_KEYS_TO_WATCH); + +        // Watch for policy changes that affect what the user is permitted to do. +        mUserManager.addUserRestrictionsListener( +                new IUserRestrictionsListener.Stub() { +                    @Override +                    public void onUserRestrictionsChanged( +                            int userId, Bundle newRestrictions, Bundle prevRestrictions) { +                        // This callback currently delivered on main thread, but this post() is +                        // defensive and doesn't rely on that in case it changes. +                        mainThreadHandler.post( +                                () -> handleUserRestrictionsChangeOnMainThread( +                                        userId, newRestrictions, prevRestrictions)); +                    } +                });      }      /** Returns the singleton instance. */ @@ -174,6 +193,13 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {          }      } +    private void handleUserRestrictionsChangeOnMainThread( +            int userId, Bundle newRestrictions, Bundle prevRestrictions) { +        // No attempt at optimisation here. If the policy changes in any way for any user, just +        // notify. +        handleConfigurationInternalChangeOnMainThread(); +    } +      @Override      public synchronized void addConfigurationInternalChangeListener(              @NonNull StateChangeListener listener) { diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java index a71f9c7f9086..40353a2d2353 100644 --- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java +++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java @@ -32,6 +32,9 @@ import android.content.pm.PackageManager;  import android.content.res.Resources;  import android.database.ContentObserver;  import android.location.LocationManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.IUserRestrictionsListener;  import android.os.UserHandle;  import android.os.UserManager;  import android.provider.Settings; @@ -175,9 +178,11 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {              }          }, filter, null, null /* main thread */); +        Handler mainThreadHandler = mContext.getMainThreadHandler(); +          // Add async callbacks for changes to global settings that influence behavior.          ContentResolver contentResolver = mContext.getContentResolver(); -        ContentObserver contentObserver = new ContentObserver(mContext.getMainThreadHandler()) { +        ContentObserver contentObserver = new ContentObserver(mainThreadHandler) {              @Override              public void onChange(boolean selfChange) {                  handleConfigurationInternalChangeOnMainThread(); @@ -197,6 +202,20 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {          // Watch server flags.          mServerFlags.addListener(this::handleConfigurationInternalChangeOnMainThread,                  CONFIGURATION_INTERNAL_SERVER_FLAGS_KEYS_TO_WATCH); + +        // Watch for policy changes that affect what the user is permitted to do. +        mUserManager.addUserRestrictionsListener( +                new IUserRestrictionsListener.Stub() { +                    @Override +                    public void onUserRestrictionsChanged( +                            int userId, Bundle newRestrictions, Bundle prevRestrictions) { +                        // This callback currently delivered on main thread, but this post() is +                        // defensive and doesn't rely on that in case it changes. +                        mainThreadHandler.post( +                                () -> handleUserRestrictionsChangeOnMainThread( +                                        userId, newRestrictions, prevRestrictions)); +                    } +                });      }      /** Returns the singleton instance. */ @@ -221,6 +240,13 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {          }      } +    private void handleUserRestrictionsChangeOnMainThread( +            int userId, Bundle newRestrictions, Bundle prevRestrictions) { +        // No attempt at optimisation here. If the policy changes in any way for any user, just +        // notify. +        handleConfigurationInternalChangeOnMainThread(); +    } +      @Override      public synchronized void addConfigurationInternalChangeListener(              @NonNull StateChangeListener listener) { diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java index 96f045d7e258..8138168f609e 100644 --- a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java +++ b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java @@ -44,6 +44,8 @@ public final class HapticFeedbackVibrationProvider {              VibrationAttributes.createForUsage(VibrationAttributes.USAGE_PHYSICAL_EMULATION);      private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =              VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK); +    private static final VibrationAttributes COMMUNICATION_REQUEST_VIBRATION_ATTRIBUTES = +            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_COMMUNICATION_REQUEST);      private final VibratorInfo mVibratorInfo;      private final boolean mHapticTextHandleEnabled; @@ -120,7 +122,6 @@ public final class HapticFeedbackVibrationProvider {                  return getKeyboardVibration(effectId);              case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE: -            case HapticFeedbackConstants.ENTRY_BUMP:              case HapticFeedbackConstants.DRAG_CROSSING:                  return getVibration(                          effectId, @@ -131,6 +132,7 @@ public final class HapticFeedbackVibrationProvider {              case HapticFeedbackConstants.EDGE_RELEASE:              case HapticFeedbackConstants.CALENDAR_DATE:              case HapticFeedbackConstants.CONFIRM: +            case HapticFeedbackConstants.BIOMETRIC_CONFIRM:              case HapticFeedbackConstants.GESTURE_START:              case HapticFeedbackConstants.SCROLL_ITEM_FOCUS:              case HapticFeedbackConstants.SCROLL_LIMIT: @@ -143,6 +145,7 @@ public final class HapticFeedbackVibrationProvider {                  return getVibration(effectId, VibrationEffect.EFFECT_HEAVY_CLICK);              case HapticFeedbackConstants.REJECT: +            case HapticFeedbackConstants.BIOMETRIC_REJECT:                  return getVibration(effectId, VibrationEffect.EFFECT_DOUBLE_CLICK);              case HapticFeedbackConstants.SAFE_MODE_ENABLED: @@ -207,6 +210,10 @@ public final class HapticFeedbackVibrationProvider {              case HapticFeedbackConstants.KEYBOARD_RELEASE:                  attrs = createKeyboardVibrationAttributes(fromIme);                  break; +            case HapticFeedbackConstants.BIOMETRIC_CONFIRM: +            case HapticFeedbackConstants.BIOMETRIC_REJECT: +                attrs = COMMUNICATION_REQUEST_VIBRATION_ATTRIBUTES; +                break;              default:                  attrs = TOUCH_VIBRATION_ATTRIBUTES;          } @@ -225,6 +232,23 @@ public final class HapticFeedbackVibrationProvider {          return flags == 0 ? attrs : new VibrationAttributes.Builder(attrs).setFlags(flags).build();      } +    /** +     * Returns true if given haptic feedback is restricted to system apps with permission +     * {@code android.permission.VIBRATE_SYSTEM_CONSTANTS}. +     * +     * @param effectId the haptic feedback effect ID to check. +     * @return true if the haptic feedback is restricted, false otherwise. +     */ +    public boolean isRestrictedHapticFeedback(int effectId) { +        switch (effectId) { +            case HapticFeedbackConstants.BIOMETRIC_CONFIRM: +            case HapticFeedbackConstants.BIOMETRIC_REJECT: +                return true; +            default: +                return false; +        } +    } +      /** Dumps relevant state. */      public void dump(String prefix, PrintWriter pw) {          pw.print("mHapticTextHandleEnabled="); pw.println(mHapticTextHandleEnabled); diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index 9e9025e35e60..8281ac1c9d28 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -439,6 +439,11 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {              Slog.w(TAG, "performHapticFeedback; haptic vibration provider not ready.");              return null;          } +        if (hapticVibrationProvider.isRestrictedHapticFeedback(constant) +                && !hasPermission(android.Manifest.permission.VIBRATE_SYSTEM_CONSTANTS)) { +            Slog.w(TAG, "performHapticFeedback; no permission for effect " + constant); +            return null; +        }          VibrationEffect effect = hapticVibrationProvider.getVibrationForHapticFeedback(constant);          if (effect == null) {              Slog.w(TAG, "performHapticFeedback; vibration absent for effect " + constant); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java index 6905802809c3..f6e0168fd236 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java @@ -137,6 +137,27 @@ public class WallpaperCropper {                  // This will fall into "Case 4" of this function and center the folded screen                  return getCrop(displaySize, bitmapSize, newSuggestedCrops, rtl);              } + +            // The second exception is if we're on tablet and we're on portrait mode. +            // In that case, center the wallpaper relatively to landscape and put some parallax. +            boolean isTablet = mWallpaperDisplayHelper.isLargeScreen() +                    && !mWallpaperDisplayHelper.isFoldable(); +            if (isTablet && displaySize.x < displaySize.y) { +                Point rotatedDisplaySize = new Point(displaySize.y, displaySize.x); +                // compute the crop on landscape (without parallax) +                Rect landscapeCrop = getCrop(rotatedDisplaySize, bitmapSize, suggestedCrops, rtl); +                landscapeCrop = noParallax(landscapeCrop, rotatedDisplaySize, bitmapSize, rtl); +                // compute the crop on portrait at the center of the landscape crop +                crop = getAdjustedCrop(landscapeCrop, bitmapSize, displaySize, false, rtl, ADD); + +                // add some parallax (until the border of the landscape crop without parallax) +                if (rtl) { +                    crop.left = landscapeCrop.left; +                } else { +                    crop.right = landscapeCrop.right; +                } +            } +              return getAdjustedCrop(crop, bitmapSize, displaySize, true, rtl, ADD);          } @@ -472,6 +493,7 @@ public class WallpaperCropper {                  }              }              final Rect cropHint; +            final SparseArray<Rect> defaultCrops;              // A wallpaper with cropHints = Map.of(ORIENTATION_UNKNOWN, rect) is treated like              // a wallpaper with cropHints = null and  cropHint = rect. @@ -483,7 +505,7 @@ public class WallpaperCropper {              if (multiCrop() && wallpaper.mCropHints.size() > 0) {                  // Some suggested crops per screen orientation were provided,                  // use them to compute the default crops for this device -                SparseArray<Rect> defaultCrops = getDefaultCrops(wallpaper.mCropHints, bitmapSize); +                defaultCrops = getDefaultCrops(wallpaper.mCropHints, bitmapSize);                  // Adapt the provided crops to match the actual crops for the default display                  SparseArray<Rect> updatedCropHints = new SparseArray<>();                  for (int i = 0; i < wallpaper.mCropHints.size(); i++) { @@ -514,7 +536,7 @@ public class WallpaperCropper {                      wallpaper.cropHint.set(bitmapRect);                  }                  Point cropSize = new Point(wallpaper.cropHint.width(), wallpaper.cropHint.height()); -                SparseArray<Rect> defaultCrops = getDefaultCrops(new SparseArray<>(), cropSize); +                defaultCrops = getDefaultCrops(new SparseArray<>(), cropSize);                  cropHint = getTotalCrop(defaultCrops);                  cropHint.offset(wallpaper.cropHint.left, wallpaper.cropHint.top);                  wallpaper.cropHint.set(cropHint); @@ -523,6 +545,7 @@ public class WallpaperCropper {                  }              } else {                  cropHint = new Rect(wallpaper.cropHint); +                defaultCrops = null;              }              if (DEBUG) { @@ -563,6 +586,33 @@ public class WallpaperCropper {                      || cropHint.height() > GLHelper.getMaxTextureSize()                      || cropHint.width() > GLHelper.getMaxTextureSize(); +            float sampleSize = Float.MAX_VALUE; +            if (multiCrop()) { +                // If all crops for all orientations have more width and height in pixel +                // than the display for this orientation, downsample the image +                for (int i = 0; i < defaultCrops.size(); i++) { +                    int orientation = defaultCrops.keyAt(i); +                    Rect crop = defaultCrops.valueAt(i); +                    Point displayForThisOrientation = mWallpaperDisplayHelper +                            .getDefaultDisplaySizes().get(orientation); +                    if (displayForThisOrientation == null) continue; +                    float sampleSizeForThisOrientation = Math.max(1f, Math.min( +                            crop.width() / displayForThisOrientation.x, +                            crop.height() / displayForThisOrientation.y)); +                    sampleSize = Math.min(sampleSize, sampleSizeForThisOrientation); +                } +                // If the total crop has more width or height than either the max texture size +                // or twice the largest display dimension, downsample the image +                int maxCropSize = Math.min( +                        2 * mWallpaperDisplayHelper.getDefaultDisplayLargestDimension(), +                        GLHelper.getMaxTextureSize()); +                float minimumSampleSize = Math.max(1f, Math.max( +                        (float) cropHint.height() / maxCropSize, +                        (float) cropHint.width()) / maxCropSize); +                sampleSize = Math.max(sampleSize, minimumSampleSize); +                needScale = sampleSize > 1f; +            } +              //make sure screen aspect ratio is preserved if width is scaled under screen size              if (needScale && !multiCrop()) {                  final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height(); @@ -577,7 +627,8 @@ public class WallpaperCropper {              if (DEBUG_CROP) {                  Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height()); -                Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight); +                if (multiCrop()) Slog.v(TAG, "defaultCrops: " + defaultCrops); +                if (!multiCrop()) Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight);                  Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);                  Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);              } @@ -620,28 +671,17 @@ public class WallpaperCropper {                      options.inJustDecodeBounds = false;                      final Rect estimateCrop = new Rect(cropHint); -                    estimateCrop.scale(1f / options.inSampleSize); +                    if (!multiCrop()) estimateCrop.scale(1f / options.inSampleSize); +                    else estimateCrop.scale(1f / sampleSize);                      float hRatio = (float) wpData.mHeight / estimateCrop.height(); -                    if (multiCrop()) { -                        // make sure the crop height is at most the display largest dimension -                        hRatio = (float) mWallpaperDisplayHelper.getDefaultDisplayLargestDimension() -                                / estimateCrop.height(); -                        hRatio = Math.min(hRatio, 1f); -                    }                      final int destHeight = (int) (estimateCrop.height() * hRatio);                      final int destWidth = (int) (estimateCrop.width() * hRatio);                      // We estimated an invalid crop, try to adjust the cropHint to get a valid one. -                    if (destWidth > GLHelper.getMaxTextureSize()) { +                    if (!multiCrop() && destWidth > GLHelper.getMaxTextureSize()) {                          if (DEBUG) {                              Slog.w(TAG, "Invalid crop dimensions, trying to adjust.");                          } -                        if (multiCrop()) { -                            // clear custom crop guidelines, fallback to system default -                            wallpaper.mCropHints.clear(); -                            generateCropInternal(wallpaper); -                            return; -                        }                          int newHeight = (int) (wpData.mHeight / hRatio);                          int newWidth = (int) (wpData.mWidth / hRatio); @@ -658,16 +698,27 @@ public class WallpaperCropper {                      // We've got the safe cropHint; now we want to scale it properly to                      // the desired rectangle.                      // That's a height-biased operation: make it fit the hinted height. -                    final int safeHeight = (int) (estimateCrop.height() * hRatio + 0.5f); -                    final int safeWidth = (int) (estimateCrop.width() * hRatio + 0.5f); +                    final int safeHeight = !multiCrop() +                            ? (int) (estimateCrop.height() * hRatio + 0.5f) +                            : (int) (cropHint.height() / sampleSize + 0.5f); +                    final int safeWidth = !multiCrop() +                            ? (int) (estimateCrop.width() * hRatio + 0.5f) +                            : (int) (cropHint.width() / sampleSize + 0.5f);                      if (DEBUG_CROP) {                          Slog.v(TAG, "Decode parameters:"); -                        Slog.v(TAG, "  cropHint=" + cropHint + ", estimateCrop=" + estimateCrop); -                        Slog.v(TAG, "  down sampling=" + options.inSampleSize -                                + ", hRatio=" + hRatio); -                        Slog.v(TAG, "  dest=" + destWidth + "x" + destHeight); -                        Slog.v(TAG, "  safe=" + safeWidth + "x" + safeHeight); +                        if (!multiCrop()) { +                            Slog.v(TAG, +                                    "  cropHint=" + cropHint + ", estimateCrop=" + estimateCrop); +                            Slog.v(TAG, "  down sampling=" + options.inSampleSize +                                    + ", hRatio=" + hRatio); +                            Slog.v(TAG, "  dest=" + destWidth + "x" + destHeight); +                        } +                        if (multiCrop()) { +                            Slog.v(TAG, "  cropHint=" + cropHint); +                            Slog.v(TAG, "  sampleSize=" + sampleSize); +                        } +                        Slog.v(TAG, "  targetSize=" + safeWidth + "x" + safeHeight);                          Slog.v(TAG, "  maxTextureSize=" + GLHelper.getMaxTextureSize());                      } @@ -682,24 +733,28 @@ public class WallpaperCropper {                      final ImageDecoder.Source srcData =                              ImageDecoder.createSource(wallpaper.getWallpaperFile()); -                    final int sampleSize = scale; +                    final int finalScale = scale; +                    final int rescaledBitmapWidth = (int) (0.5f + bitmapSize.x / sampleSize); +                    final int rescaledBitmapHeight = (int) (0.5f + bitmapSize.y / sampleSize);                      Bitmap cropped = ImageDecoder.decodeBitmap(srcData, (decoder, info, src) -> { -                        decoder.setTargetSampleSize(sampleSize); +                        if (!multiCrop()) decoder.setTargetSampleSize(finalScale); +                        if (multiCrop()) { +                            decoder.setTargetSize(rescaledBitmapWidth, rescaledBitmapHeight); +                        }                          decoder.setCrop(estimateCrop);                      });                      record.delete(); -                    if (cropped == null) { +                    if (!multiCrop() && cropped == null) {                          Slog.e(TAG, "Could not decode new wallpaper");                      } else {                          // We are safe to create final crop with safe dimensions now. -                        final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped, -                                safeWidth, safeHeight, true); +                        final Bitmap finalCrop = multiCrop() ? cropped +                                : Bitmap.createScaledBitmap(cropped, safeWidth, safeHeight, true);                          if (multiCrop()) { -                            wallpaper.mSampleSize = -                                    ((float) cropHint.height()) / finalCrop.getHeight(); +                            wallpaper.mSampleSize = sampleSize;                          }                          if (DEBUG) { @@ -718,9 +773,7 @@ public class WallpaperCropper {                          success = true;                      }                  } catch (Exception e) { -                    if (DEBUG) { -                        Slog.e(TAG, "Error decoding crop", e); -                    } +                    Slog.e(TAG, "Error decoding crop", e);                  } finally {                      IoUtils.closeQuietly(bos);                      IoUtils.closeQuietly(f); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java b/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java index 9e1b5d238d48..3636f5aa8f27 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperDisplayHelper.java @@ -59,6 +59,8 @@ class WallpaperDisplayHelper {      }      private static final String TAG = WallpaperDisplayHelper.class.getSimpleName(); +    private static final float LARGE_SCREEN_MIN_DP = 600f; +      private final SparseArray<DisplayData> mDisplayDatas = new SparseArray<>();      private final DisplayManager mDisplayManager;      private final WindowManagerInternal mWindowManagerInternal; @@ -67,7 +69,8 @@ class WallpaperDisplayHelper {      // related orientations pairs for foldable (folded orientation, unfolded orientation)      private final List<Pair<Integer, Integer>> mFoldableOrientationPairs = new ArrayList<>(); -    private boolean mIsFoldable; +    private final boolean mIsFoldable; +    private boolean mIsLargeScreen = false;      WallpaperDisplayHelper(              DisplayManager displayManager, @@ -94,6 +97,9 @@ class WallpaperDisplayHelper {                      mDefaultDisplaySizes.put(orientation, point);                  }              } + +            mIsLargeScreen |= (displaySize.x / metric.getDensity() >= LARGE_SCREEN_MIN_DP); +              if (populateOrientationPairs) {                  int orientation = WallpaperManager.getOrientation(displaySize);                  float newSurface = displaySize.x * displaySize.y @@ -215,6 +221,13 @@ class WallpaperDisplayHelper {      }      /** +     * Return true if any of the screens of the default display is considered large (DP >= 600) +     */ +    boolean isLargeScreen() { +        return mIsLargeScreen; +    } + +    /**       * If a given orientation corresponds to an unfolded orientation on foldable, return the       * corresponding folded orientation. Otherwise, return UNKNOWN. Always return UNKNOWN if the       * device is not a foldable. diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 9a5961af6083..f1ba755836b2 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -2269,6 +2269,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub              Point croppedBitmapSize = new Point(                      (int) (0.5f + wallpaper.cropHint.width() / wallpaper.mSampleSize),                      (int) (0.5f + wallpaper.cropHint.height() / wallpaper.mSampleSize)); +            if (croppedBitmapSize.equals(0, 0)) { +                // There is an ImageWallpaper, but there are no crop hints and the bitmap size is +                // unknown (e.g. the default wallpaper). Return a special "null" value that will be +                // handled by WallpaperManager, which will fetch the dimensions of the wallpaper. +                return null; +            }              SparseArray<Rect> relativeDefaultCrops =                      mWallpaperCropper.getDefaultCrops(relativeSuggestedCrops, croppedBitmapSize);              SparseArray<Rect> adjustedRelativeSuggestedCrops = new SparseArray<>(); diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java index eb170b702eb9..36e52008f223 100644 --- a/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java +++ b/services/core/java/com/android/server/wearable/WearableSensingManagerPerUserService.java @@ -17,6 +17,9 @@  package com.android.server.wearable;  import static android.service.wearable.WearableSensingService.HOTWORD_AUDIO_STREAM_BUNDLE_KEY; +import static android.system.OsConstants.F_GETFL; +import static android.system.OsConstants.O_ACCMODE; +import static android.system.OsConstants.O_RDONLY;  import android.Manifest;  import android.annotation.NonNull; @@ -42,6 +45,8 @@ import android.os.SharedMemory;  import android.service.voice.HotwordAudioStream;  import android.service.voice.VoiceInteractionManagerInternal;  import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback; +import android.system.ErrnoException; +import android.system.Os;  import android.system.OsConstants;  import android.util.IndentingPrintWriter;  import android.util.Slog; @@ -276,7 +281,10 @@ final class WearableSensingManagerPerUserService extends              ParcelFileDescriptor parcelFileDescriptor,              @Nullable IWearableSensingCallback wearableSensingCallback,              RemoteCallback statusCallback) { -        Slog.i(TAG, "onProvideDataStream in per user service."); +        Slog.i( +                TAG, +                "onProvideDataStream in per user service. Is data stream read-only? " +                        + isReadOnly(parcelFileDescriptor));          synchronized (mLock) {              if (!setUpServiceIfNeeded()) {                  Slog.w(TAG, "Detection service is not available at this moment."); @@ -505,10 +513,53 @@ final class WearableSensingManagerPerUserService extends                      String filename,                      AndroidFuture<ParcelFileDescriptor> futureFromWearableSensingService)                      throws RemoteException { -                // TODO(b/331395522): Intercept the PFD received from the app process and verify it -                // is read-only -                callbackFromAppProcess.openFile(filename, futureFromWearableSensingService); +                AndroidFuture<ParcelFileDescriptor> futureFromSystemServer = +                        new AndroidFuture<ParcelFileDescriptor>() +                                .whenComplete( +                                        (pfdFromApp, throwable) -> { +                                            if (throwable != null) { +                                                Slog.e( +                                                        TAG, +                                                        "Error when reading file " + filename, +                                                        throwable); +                                                futureFromWearableSensingService.complete(null); +                                                return; +                                            } +                                            if (pfdFromApp == null) { +                                                futureFromWearableSensingService.complete(null); +                                                return; +                                            } +                                            if (isReadOnly(pfdFromApp)) { +                                                futureFromWearableSensingService.complete( +                                                        pfdFromApp); +                                            } else { +                                                Slog.w( +                                                        TAG, +                                                        "Received writable ParcelFileDescriptor" +                                                            + " from app process. To prevent" +                                                            + " arbitrary data egress, sending null" +                                                            + " to WearableSensingService" +                                                            + " instead."); +                                                futureFromWearableSensingService.complete(null); +                                            } +                                        }); +                callbackFromAppProcess.openFile(filename, futureFromSystemServer);              }          };      } + +    private static boolean isReadOnly(ParcelFileDescriptor parcelFileDescriptor) { +        try { +            int readMode = +                    Os.fcntlInt(parcelFileDescriptor.getFileDescriptor(), F_GETFL, 0) & O_ACCMODE; +            return readMode == O_RDONLY; +        } catch (ErrnoException ex) { +            Slog.w( +                    TAG, +                    "Error encountered when trying to determine if the parcelFileDescriptor is" +                        + " read-only. Treating it as not read-only", +                    ex); +        } +        return false; +    }  } diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 2b43326f4c51..e280bdc7780b 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -466,20 +466,17 @@ final class AccessibilityController {          }      } -    void drawMagnifiedRegionBorderIfNeeded(int displayId) { -        if (Flags.alwaysDrawMagnificationFullscreenBorder()) { -            return; -        } - +    void recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded(int displayId) {          if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {              mAccessibilityTracing.logTrace( -                    TAG + ".drawMagnifiedRegionBorderIfNeeded", +                    TAG + ".recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded",                      FLAGS_MAGNIFICATION_CALLBACK,                      "displayId=" + displayId);          } +          final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);          if (displayMagnifier != null) { -            displayMagnifier.drawMagnifiedRegionBorderIfNeeded(); +            displayMagnifier.recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded();          }          // Not relevant for the window observer.      } @@ -936,11 +933,13 @@ final class AccessibilityController {              }          } -        void drawMagnifiedRegionBorderIfNeeded() { +        void recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded() {              if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) { -                mAccessibilityTracing.logTrace(LOG_TAG + ".drawMagnifiedRegionBorderIfNeeded", +                mAccessibilityTracing.logTrace(LOG_TAG +                                + ".recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded",                          FLAGS_MAGNIFICATION_CALLBACK);              } +            recomputeBounds();              if (!Flags.alwaysDrawMagnificationFullscreenBorder()) {                  mMagnifiedViewport.drawWindowIfNeeded(); @@ -1245,7 +1244,6 @@ final class AccessibilityController {              }              void drawWindowIfNeeded() { -                recomputeBounds();                  mWindow.postDrawIfNeeded();              } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 207d42b6b58d..42373aa85053 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1312,6 +1312,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A                  pw.println(prefix + "supportsPictureInPicture=" + info.supportsPictureInPicture());                  pw.println(prefix + "supportsEnterPipOnTaskSwitch: "                          + supportsEnterPipOnTaskSwitch); +                pw.println(prefix + "mPauseSchedulePendingForPip=" + mPauseSchedulePendingForPip);              }              if (getMaxAspectRatio() != 0) {                  pw.println(prefix + "maxAspectRatio=" + getMaxAspectRatio()); @@ -4259,7 +4260,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A                  PendingIntentRecord rec = apr.get();                  if (rec != null) {                      mAtmService.mPendingIntentController.cancelIntentSender(rec, -                            false /* cleanActivity */); +                            false /* cleanActivity */, +                            PendingIntentRecord.CANCEL_REASON_HOSTING_ACTIVITY_DESTROYED);                  }              }              pendingResults = null; @@ -8544,7 +8546,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A              }          // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds          // are already calculated in resolveFixedOrientationConfiguration. -        } else if (!isLetterboxedForFixedOrientationAndAspectRatio()) { +        // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer. +        } else if (!isLetterboxedForFixedOrientationAndAspectRatio() +                && !mLetterboxUiController.hasFullscreenOverride()) {              resolveAspectRatioRestriction(newParentConfiguration);          } @@ -8965,8 +8969,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A                  : mDisplayContent.getDisplayInfo();          final Task task = getTask();          task.calculateInsetFrames(mTmpBounds /* outNonDecorBounds */, -                outStableBounds /* outStableBounds */, parentBounds /* bounds */, di, -                true /* useLegacyInsetsForStableBounds */); +                outStableBounds /* outStableBounds */, parentBounds /* bounds */, di);          final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width()                  ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;          // If orientation does not match the orientation with insets applied, then a @@ -9060,8 +9063,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A              // vertically centered within parent bounds with insets, so position vertical bounds              // within parent bounds with insets to prevent insets from unnecessarily trimming              // vertical bounds. -            final int bottom = Math.min(parentBoundsWithInsets.top + parentBounds.width() - 1, -                    parentBoundsWithInsets.bottom); +            final int bottom = Math.min(parentBoundsWithInsets.top +                            + parentBoundsWithInsets.width() - 1, parentBoundsWithInsets.bottom);              containingBounds.set(parentBounds.left, parentBoundsWithInsets.top, parentBounds.right,                      bottom);              containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top, @@ -9072,8 +9075,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A              // horizontally centered within parent bounds with insets, so position horizontal bounds              // within parent bounds with insets to prevent insets from unnecessarily trimming              // horizontal bounds. -            final int right = Math.min(parentBoundsWithInsets.left + parentBounds.height(), -                    parentBoundsWithInsets.right); +            final int right = Math.min(parentBoundsWithInsets.left +                            + parentBoundsWithInsets.height(), parentBoundsWithInsets.right);              containingBounds.set(parentBoundsWithInsets.left, parentBounds.top, right,                      parentBounds.bottom);              containingBoundsWithInsets.set(parentBoundsWithInsets.left, parentBoundsWithInsets.top, diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 354cab364ec1..a0f615b1ea58 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -3732,16 +3732,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {              return false;          } -        // If PiP2 flag is on and client-request to enter PiP comes in, -        // we request a direct transition from Shell to TRANSIT_PIP to get the startWct -        // with the right entry bounds. So PiP activity isn't moved to a pinned task until after -        // Shell calls back into Core with the entry bounds passed through.          if (isPip2ExperimentEnabled()) { -            final Transition legacyEnterPipTransition = new Transition(TRANSIT_PIP, +            // If PiP2 flag is on and request to enter PiP comes in, +            // we request a direct transition TRANSIT_PIP from Shell to get the right entry bounds. +            // So PiP activity isn't moved to a pinned task until after +            // Shell calls back into Core with the entry bounds to be applied with startWCT. +            final Transition enterPipTransition = new Transition(TRANSIT_PIP,                      0 /* flags */, getTransitionController(), mWindowManager.mSyncEngine); -            legacyEnterPipTransition.setPipActivity(r); -            getTransitionController().startCollectOrQueue(legacyEnterPipTransition, (deferred) -> { -                getTransitionController().requestStartTransition(legacyEnterPipTransition, +            enterPipTransition.setPipActivity(r); +            r.mAutoEnteringPip = isAutoEnter; +            getTransitionController().startCollectOrQueue(enterPipTransition, (deferred) -> { +                getTransitionController().requestStartTransition(enterPipTransition,                          r.getTask(), null /* remoteTransition */, null /* displayChange */);              });              return true; @@ -3778,17 +3779,25 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {                  }                  EventLogTags.writeWmEnterPip(r.mUserId, System.identityHashCode(r),                          r.shortComponentName, Boolean.toString(isAutoEnter)); -                r.setPictureInPictureParams(params); -                r.mAutoEnteringPip = isAutoEnter; -                mRootWindowContainer.moveActivityToPinnedRootTask(r, -                        null /* launchIntoPipHostActivity */, "enterPictureInPictureMode", -                        transition); -                // Continue the pausing process after entering pip. -                if (r.isState(PAUSING) && r.mPauseSchedulePendingForPip) { -                    r.getTask().schedulePauseActivity(r, false /* userLeaving */, -                            false /* pauseImmediately */, true /* autoEnteringPip */, "auto-pip"); -                } -                r.mAutoEnteringPip = false; + +                // Ensure the ClientTransactionItems are bundled for this operation. +                deferWindowLayout(); +                try { +                    r.setPictureInPictureParams(params); +                    r.mAutoEnteringPip = isAutoEnter; +                    mRootWindowContainer.moveActivityToPinnedRootTask(r, +                            null /* launchIntoPipHostActivity */, "enterPictureInPictureMode", +                            transition); +                    // Continue the pausing process after entering pip. +                    if (r.isState(PAUSING) && r.mPauseSchedulePendingForPip) { +                        r.getTask().schedulePauseActivity(r, false /* userLeaving */, +                                false /* pauseImmediately */, true /* autoEnteringPip */, +                                "auto-pip"); +                    } +                    r.mAutoEnteringPip = false; +                } finally { +                    continueWindowLayout(); +                }              }          }; diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index f7b4a6748411..d709fa5726f1 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -174,27 +174,6 @@ class BackNavigationController {                  }              } -            // This is needed to bridge the old and new back behavior with recents.  While in -            // Overview with live tile enabled, the previous app is technically focused but we -            // add an input consumer to capture all input that would otherwise go to the apps -            // being controlled by the animation. This means that the window resolved is not -            // the right window to consume back while in overview, so we need to route it to -            // launcher and use the legacy behavior of injecting KEYCODE_BACK since the existing -            // compat callback in VRI only works when the window is focused. -            // This symptom also happen while shell transition enabled, we can check that by -            // isTransientLaunch to know whether the focus window is point to live tile. -            final RecentsAnimationController recentsAnimationController = -                    wmService.getRecentsAnimationController(); -            final ActivityRecord tmpAR = window.mActivityRecord; -            if ((tmpAR != null && tmpAR.isActivityTypeHomeOrRecents() -                    && tmpAR.mTransitionController.isTransientLaunch(tmpAR)) -                    || (recentsAnimationController != null -                    && recentsAnimationController.shouldApplyInputConsumer(tmpAR))) { -                ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Current focused window being animated by " -                        + "recents. Overriding back callback to recents controller callback."); -                return null; -            } -              if (!window.isDrawn()) {                  ProtoLog.d(WM_DEBUG_BACK_PREVIEW,                          "Focused window didn't have a valid surface drawn."); @@ -1783,18 +1762,39 @@ class BackNavigationController {      }      private void onBackNavigationDone(Bundle result, int backType) { -        boolean triggerBack = result != null && result.getBoolean( -                BackNavigationInfo.KEY_TRIGGER_BACK); -        ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, " -                + "triggerBack=%b", backType, triggerBack); - -        synchronized (mWindowManagerService.mGlobalLock) { -            mNavigationMonitor.stopMonitorForRemote(); -            mBackAnimationInProgress = false; -            mShowWallpaper = false; -            // All animation should be done, clear any un-send animation. -            mPendingAnimation = null; -            mPendingAnimationBuilder = null; +        if (result == null) { +            return; +        } +        if (result.containsKey(BackNavigationInfo.KEY_NAVIGATION_FINISHED)) { +            final boolean triggerBack = result.getBoolean( +                    BackNavigationInfo.KEY_NAVIGATION_FINISHED); +            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, " +                    + "triggerBack=%b", backType, triggerBack); + +            synchronized (mWindowManagerService.mGlobalLock) { +                mNavigationMonitor.stopMonitorForRemote(); +                mBackAnimationInProgress = false; +                mShowWallpaper = false; +                // All animation should be done, clear any un-send animation. +                mPendingAnimation = null; +                mPendingAnimationBuilder = null; +            } +        } +        if (result.getBoolean(BackNavigationInfo.KEY_GESTURE_FINISHED)) { +            synchronized (mWindowManagerService.mGlobalLock) { +                final AnimationHandler ah = mAnimationHandler; +                if (!ah.mComposed || ah.mWaitTransition || ah.mOpenActivities == null +                        || (ah.mSwitchType != AnimationHandler.TASK_SWITCH +                        && ah.mSwitchType != AnimationHandler.ACTIVITY_SWITCH)) { +                    return; +                } +                for (int i = mAnimationHandler.mOpenActivities.length - 1; i >= 0; --i) { +                    final ActivityRecord preDrawActivity = mAnimationHandler.mOpenActivities[i]; +                    if (!preDrawActivity.mLaunchTaskBehind) { +                        setLaunchBehind(preDrawActivity); +                    } +                } +            }          }      } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 00dc3ec4f4d0..739f76e2bdc7 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1007,8 +1007,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp      private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {          final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked; -        final boolean obscuredChanged = w.mObscured != -                mTmpApplySurfaceChangesTransactionState.obscured;          final RootWindowContainer root = mWmService.mRoot;          if (w.mHasSurface) { @@ -1107,12 +1105,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp              }          } -        if (obscuredChanged && w.isVisible() && mWallpaperController.isWallpaperTarget(w)) { -            // This is the wallpaper target and its obscured state changed... make sure the -            // current wallpaper's visibility has been updated accordingly. -            mWallpaperController.updateWallpaperTokens(mDisplayContent.isKeyguardLocked()); -        } -          w.handleWindowMovedIfNeeded();          //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index a8cbc621d966..88587666e321 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -519,8 +519,17 @@ class InsetsSourceProvider {          final SurfaceControl leash = mAdapter.mCapturedLeash;          mControlTarget = target;          updateVisibility(); +        boolean initiallyVisible = mClientVisible; +        if (mSource.getType() == WindowInsets.Type.ime()) { +            // The IME cannot be initially visible, see ControlAdapter#startAnimation below. +            // Also, the ImeInsetsSourceConsumer clears the client visibility upon losing control, +            // but this won't have reached here yet by the time the new control is created. +            // Note: The DisplayImeController needs the correct previous client's visibility, so we +            // only override the initiallyVisible here. +            initiallyVisible = false; +        }          mControl = new InsetsSourceControl(mSource.getId(), mSource.getType(), leash, -                mClientVisible, surfacePosition, getInsetsHint()); +                initiallyVisible, surfacePosition, getInsetsHint());          ProtoLog.d(WM_DEBUG_WINDOW_INSETS,                  "InsetsSource Control %s for target %s", mControl, mControlTarget); diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index 45cf10bd3f5e..5aa0ed7ce76c 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -327,14 +327,14 @@ final class LetterboxConfiguration {                  R.dimen.config_letterboxBackgroundWallpaperBlurRadius);          mLetterboxBackgroundWallpaperDarkScrimAlpha = mContext.getResources().getFloat(                  R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha); -        mLetterboxHorizontalPositionMultiplier = mContext.getResources().getFloat( -                R.dimen.config_letterboxHorizontalPositionMultiplier); -        mLetterboxVerticalPositionMultiplier = mContext.getResources().getFloat( -                R.dimen.config_letterboxVerticalPositionMultiplier); -        mLetterboxBookModePositionMultiplier = mContext.getResources().getFloat( -                R.dimen.config_letterboxBookModePositionMultiplier); -        mLetterboxTabletopModePositionMultiplier = mContext.getResources().getFloat( -                R.dimen.config_letterboxTabletopModePositionMultiplier); +        setLetterboxHorizontalPositionMultiplier(mContext.getResources().getFloat( +                R.dimen.config_letterboxHorizontalPositionMultiplier)); +        setLetterboxVerticalPositionMultiplier(mContext.getResources().getFloat( +                R.dimen.config_letterboxVerticalPositionMultiplier)); +        setLetterboxBookModePositionMultiplier(mContext.getResources().getFloat( +                R.dimen.config_letterboxBookModePositionMultiplier)); +        setLetterboxTabletopModePositionMultiplier(mContext.getResources() +                .getFloat(R.dimen.config_letterboxTabletopModePositionMultiplier));          mIsHorizontalReachabilityEnabled = mContext.getResources().getBoolean(                  R.bool.config_letterboxIsHorizontalReachabilityEnabled);          mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean( @@ -657,29 +657,8 @@ final class LetterboxConfiguration {       * right side.       */      float getLetterboxHorizontalPositionMultiplier(boolean isInBookMode) { -        if (isInBookMode) { -            if (mLetterboxBookModePositionMultiplier < 0.0f -                    || mLetterboxBookModePositionMultiplier > 1.0f) { -                Slog.w(TAG, -                        "mLetterboxBookModePositionMultiplier out of bounds (isInBookMode=true): " -                        + mLetterboxBookModePositionMultiplier); -                // Default to left position if invalid value is provided. -                return 0.0f; -            } else { -                return mLetterboxBookModePositionMultiplier; -            } -        } else { -            if (mLetterboxHorizontalPositionMultiplier < 0.0f -                    || mLetterboxHorizontalPositionMultiplier > 1.0f) { -                Slog.w(TAG, -                        "mLetterboxBookModePositionMultiplier out of bounds (isInBookMode=false):" -                        + mLetterboxBookModePositionMultiplier); -                // Default to central position if invalid value is provided. -                return 0.5f; -            } else { -                return mLetterboxHorizontalPositionMultiplier; -            } -        } +        return isInBookMode ? mLetterboxBookModePositionMultiplier +                : mLetterboxHorizontalPositionMultiplier;      }      /* @@ -689,37 +668,28 @@ final class LetterboxConfiguration {       * bottom side.       */      float getLetterboxVerticalPositionMultiplier(boolean isInTabletopMode) { -        if (isInTabletopMode) { -            return (mLetterboxTabletopModePositionMultiplier < 0.0f -                    || mLetterboxTabletopModePositionMultiplier > 1.0f) -                    // Default to top position if invalid value is provided. -                    ? 0.0f : mLetterboxTabletopModePositionMultiplier; -        } else { -            return (mLetterboxVerticalPositionMultiplier < 0.0f -                    || mLetterboxVerticalPositionMultiplier > 1.0f) -                    // Default to central position if invalid value is provided. -                    ? 0.5f : mLetterboxVerticalPositionMultiplier; -        } +        return isInTabletopMode ? mLetterboxTabletopModePositionMultiplier +                : mLetterboxVerticalPositionMultiplier;      }      /** -     * Overrides horizontal position of a center of the letterboxed app window. If given value < 0 -     * or > 1, then it and a value of {@link -     * com.android.internal.R.dimen.config_letterboxHorizontalPositionMultiplier} are ignored and -     * central position (0.5) is used. +     * Overrides horizontal position of a center of the letterboxed app window. +     * +     * @throws IllegalArgumentException If given value < 0 or > 1.       */      void setLetterboxHorizontalPositionMultiplier(float multiplier) { -        mLetterboxHorizontalPositionMultiplier = multiplier; +        mLetterboxHorizontalPositionMultiplier = assertValidMultiplier(multiplier, +                "mLetterboxHorizontalPositionMultiplier");      }      /** -     * Overrides vertical position of a center of the letterboxed app window. If given value < 0 -     * or > 1, then it and a value of {@link -     * com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier} are ignored and -     * central position (0.5) is used. +     * Overrides vertical position of a center of the letterboxed app window. +     * +     * @throws IllegalArgumentException If given value < 0 or > 1.       */      void setLetterboxVerticalPositionMultiplier(float multiplier) { -        mLetterboxVerticalPositionMultiplier = multiplier; +        mLetterboxVerticalPositionMultiplier = assertValidMultiplier(multiplier, +                "mLetterboxVerticalPositionMultiplier");      }      /** @@ -740,6 +710,28 @@ final class LetterboxConfiguration {                  com.android.internal.R.dimen.config_letterboxVerticalPositionMultiplier);      } +    /** +     * Sets tabletop mode position multiplier. +     * +     * @throws IllegalArgumentException If given value < 0 or > 1. +     */ +    @VisibleForTesting +    void setLetterboxTabletopModePositionMultiplier(float multiplier) { +        mLetterboxTabletopModePositionMultiplier = assertValidMultiplier(multiplier, +                "mLetterboxTabletopModePositionMultiplier"); +    } + +    /** +     * Sets tabletop mode position multiplier. +     * +     * @throws IllegalArgumentException If given value < 0 or > 1. +     */ +    @VisibleForTesting +    void setLetterboxBookModePositionMultiplier(float multiplier) { +        mLetterboxBookModePositionMultiplier = assertValidMultiplier(multiplier, +                "mLetterboxBookModePositionMultiplier"); +    } +      /*       * Whether horizontal reachability repositioning is allowed for letterboxed fullscreen apps in       * landscape device orientation. @@ -1356,4 +1348,21 @@ final class LetterboxConfiguration {      void resetUserAppAspectRatioFullscreenEnabled() {          setUserAppAspectRatioFullscreenOverrideEnabled(false);      } + +    /** +     * Checks whether the multiplier is between [0,1]. +     * +     * @param multiplierName sent in the exception if multiplier is invalid, for easier debugging. +     * +     * @return multiplier, if valid +     * @throws IllegalArgumentException if outside bounds. +     */ +    private float assertValidMultiplier(float multiplier, String multiplierName) +            throws IllegalArgumentException { +        if (multiplier < 0.0f || multiplier > 1.0f) { +            throw new IllegalArgumentException("Trying to set " + multiplierName +                    + " out of bounds: " + multiplier); +        } +        return multiplier; +    }  } diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 3f245456d849..f220c9d06e14 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -1084,6 +1084,10 @@ final class LetterboxUiController {                      || mUserAspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN);      } +    boolean hasFullscreenOverride() { +        return isSystemOverrideToFullscreenEnabled() || shouldApplyUserFullscreenOverride(); +    } +      float getUserMinAspectRatio() {          switch (mUserAspectRatio) {              case USER_MIN_ASPECT_RATIO_DISPLAY_SIZE: diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 9dba8c6b90c4..e9a877e6013d 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2244,9 +2244,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>              newTransition.setReady(rootTask, true /* ready */);          } -        if (!isPip2ExperimentEnabled()) { -            resumeFocusedTasksTopActivities(); -        } +        resumeFocusedTasksTopActivities();          notifyActivityPipModeChanged(r.getTask(), r);      } @@ -2380,6 +2378,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent>              return false;          } +        return resumeFocusedTasksTopActivitiesUnchecked(targetRootTask, target, targetOptions, +                deferPause); +    } + +    @VisibleForTesting +    boolean resumeFocusedTasksTopActivitiesUnchecked( +            Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions, +            boolean deferPause) {          boolean result = false;          if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()                  || getTopDisplayFocusedRootTask() == targetRootTask)) { diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index e157318543f6..f8aa69b80253 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -912,7 +912,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {      @Override      public void grantInputChannel(int displayId, SurfaceControl surface,              IBinder clientToken, @Nullable InputTransferToken hostInputTransferToken, int flags, -            int privateFlags, int type, int inputFeatures, IBinder windowToken, +            int privateFlags, int inputFeatures, int type, IBinder windowToken,              InputTransferToken inputTransferToken, String inputHandleName,              InputChannel outInputChannel) {          if (hostInputTransferToken == null && !mCanAddInternalSystemWindow) { @@ -925,7 +925,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {          try {              mService.grantInputChannel(this, mUid, mPid, displayId, surface, clientToken,                      hostInputTransferToken, flags, mCanAddInternalSystemWindow ? privateFlags : 0, -                    type, inputFeatures, windowToken, inputTransferToken, inputHandleName, +                    inputFeatures, type, windowToken, inputTransferToken, inputHandleName,                      outInputChannel);          } finally {              Binder.restoreCallingIdentity(identity); diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 129af90793b3..218fb7f6b817 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -2309,8 +2309,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {                  // area, i.e. the screen area without the system bars.                  // The non decor inset are areas that could never be removed in Honeycomb. See                  // {@link WindowManagerPolicy#getNonDecorInsetsLw}. -                calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di, -                        false /* useLegacyInsetsForStableBounds */); +                calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, mTmpFullBounds, di);              } else {                  // Apply the given non-decor and stable insets to calculate the corresponding bounds                  // for screen size of configuration. @@ -2408,11 +2407,9 @@ class TaskFragment extends WindowContainer<WindowContainer> {       * @param outNonDecorBounds where to place bounds with non-decor insets applied.       * @param outStableBounds where to place bounds with stable insets applied.       * @param bounds the bounds to inset. -     * @param useLegacyInsetsForStableBounds {@code true} if we need to use the legacy insets frame -     *                for apps targeting U or before when calculating stable bounds.       */      void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds, -            DisplayInfo displayInfo, boolean useLegacyInsetsForStableBounds) { +            DisplayInfo displayInfo) {          outNonDecorBounds.set(bounds);          outStableBounds.set(bounds);          if (mDisplayContent == null) { @@ -2424,11 +2421,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {          final DisplayPolicy.DecorInsets.Info info = policy.getDecorInsetsInfo(                  displayInfo.rotation, displayInfo.logicalWidth, displayInfo.logicalHeight);          intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, info.mNonDecorInsets); -        if (!useLegacyInsetsForStableBounds) { -            intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mConfigInsets); -        } else { -            intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mOverrideConfigInsets); -        } +        intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mConfigInsets);      }      /** diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 222abc35ee0b..ce53290da49c 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -565,6 +565,9 @@ class TransitionController {          if (isTransientCollect(ar)) {              return true;          } +        for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) { +            if (mWaitingTransitions.get(i).isTransientLaunch(ar)) return true; +        }          for (int i = mPlayingTransitions.size() - 1; i >= 0; --i) {              if (mPlayingTransitions.get(i).isTransientLaunch(ar)) return true;          } diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 59bda54eb089..65e17615f775 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -856,11 +856,6 @@ class WallpaperController {          result.setWallpaperTarget(wallpaperTarget);      } -    public void updateWallpaperTokens(boolean keyguardLocked) { -        updateWallpaperTokens(mWallpaperTarget != null || mPrevWallpaperTarget != null, -                keyguardLocked); -    } -      /**       * Change the visibility of the top wallpaper to {@param visibility} and hide all the others.       */ diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index b43a4540bbde..8afcf0e1e05a 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -150,7 +150,9 @@ public class WindowAnimator {                      dc.checkAppWindowsReadyToShow();                  }                  if (accessibilityController.hasCallbacks()) { -                    accessibilityController.drawMagnifiedRegionBorderIfNeeded(dc.mDisplayId); +                    accessibilityController +                            .recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded( +                                    dc.mDisplayId);                  }                  if (dc.isAnimating(animationFlags, ANIMATION_TYPE_ALL)) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 74616acf0325..ed88b5a7c449 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -241,6 +241,7 @@ import android.util.ArrayMap;  import android.util.ArraySet;  import android.util.DisplayMetrics;  import android.util.EventLog; +import android.util.IntArray;  import android.util.MergedConfiguration;  import android.util.Pair;  import android.util.Slog; @@ -1106,6 +1107,14 @@ public class WindowManagerService extends IWindowManager.Stub      @GuardedBy("mGlobalLock")      final SensitiveContentPackages mSensitiveContentPackages = new SensitiveContentPackages(); +    /** +     * UIDs for which a Toast has been shown to indicate +     * {@link LocalService#addBlockScreenCaptureForApps(ArraySet) screen capture blocking}. This is +     * used to ensure we don't keep re-showing the Toast every time the window becomes visible. +     * UIDs are removed when the app is removed from the block list. +     */ +    @GuardedBy("mGlobalLock") +    private final IntArray mCaptureBlockedToastShownUids = new IntArray();      /** Listener to notify activity manager about app transitions. */      final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier @@ -8746,6 +8755,15 @@ public class WindowManagerService extends IWindowManager.Stub                  if (modified) {                      WindowManagerService.this.refreshScreenCaptureDisabled();                  } +                if (sensitiveContentImprovements()) { +                    for (int i = 0; i < packageInfos.size(); i++) { +                        int uid = packageInfos.valueAt(i).getUid(); +                        if (mCaptureBlockedToastShownUids.contains(uid)) { +                            mCaptureBlockedToastShownUids.remove( +                                    mCaptureBlockedToastShownUids.indexOf(uid)); +                        } +                    } +                }              }          } @@ -8756,6 +8774,9 @@ public class WindowManagerService extends IWindowManager.Stub                  if (modified) {                      WindowManagerService.this.refreshScreenCaptureDisabled();                  } +                if (sensitiveContentImprovements()) { +                    mCaptureBlockedToastShownUids.clear(); +                }              }          } @@ -10157,9 +10178,13 @@ public class WindowManagerService extends IWindowManager.Stub       * on sensitive content protections.       */      private void showToastIfBlockingScreenCapture(@NonNull WindowState w) { -        // TODO(b/323580163): Check if already shown and update shown state. -        if (mSensitiveContentPackages.shouldBlockScreenCaptureForApp(w.getOwningPackage(), -                w.getOwningUid(), w.getWindowToken())) { +        int uid = w.getOwningUid(); +        if (mCaptureBlockedToastShownUids.contains(uid)) { +            return; +        } +        if (mSensitiveContentPackages.shouldBlockScreenCaptureForApp(w.getOwningPackage(), uid, +                w.getWindowToken())) { +            mCaptureBlockedToastShownUids.add(uid);              mH.post(() -> {                  Toast.makeText(mContext, Looper.getMainLooper(),                                  mContext.getString(R.string.screen_not_shared_sensitive_content), diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 731184fbc39c..d340272ee2c7 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -848,7 +848,12 @@ public class WindowManagerShellCommand extends ShellCommand {              return -1;          }          synchronized (mInternal.mGlobalLock) { -            mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(multiplier); +            try { +                mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(multiplier); +            } catch (IllegalArgumentException  e) { +                getErrPrintWriter().println("Error: invalid multiplier value " + e); +                return -1; +            }          }          return 0;      } @@ -867,7 +872,12 @@ public class WindowManagerShellCommand extends ShellCommand {              return -1;          }          synchronized (mInternal.mGlobalLock) { -            mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(multiplier); +            try { +                mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(multiplier); +            } catch (IllegalArgumentException  e) { +                getErrPrintWriter().println("Error: invalid multiplier value " + e); +                return -1; +            }          }          return 0;      } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 55da37931e15..8c9317a32483 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -67,7 +67,9 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP  import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;  import static com.android.server.wm.ActivityRecord.State.PAUSING; +import static com.android.server.wm.ActivityRecord.State.RESUMED;  import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission; +import static com.android.server.wm.ActivityTaskManagerService.isPip2ExperimentEnabled;  import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;  import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;  import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG; @@ -828,18 +830,20 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub      }      private int applyTaskChanges(Task tr, WindowContainerTransaction.Change c) { +        final boolean wasPrevFocusableAndVisible = tr.isFocusableAndVisible(); +          int effects = applyChanges(tr, c);          final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();          if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) {              if (tr.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, c.getHidden())) { -                effects = TRANSACT_EFFECTS_LIFECYCLE; +                effects |= TRANSACT_EFFECTS_LIFECYCLE;              }          }          if ((c.getChangeMask() & CHANGE_FORCE_TRANSLUCENT) != 0) {              tr.setForceTranslucent(c.getForceTranslucent()); -            effects = TRANSACT_EFFECTS_LIFECYCLE; +            effects |= TRANSACT_EFFECTS_LIFECYCLE;          }          if ((c.getChangeMask() & WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING) != 0) { @@ -872,8 +876,17 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub                  boolean canEnterPip = activity.checkEnterPictureInPictureState(                          "applyTaskChanges", true /* beforeStopping */);                  if (canEnterPip) { -                    canEnterPip = mService.mActivityClientController -                            .requestPictureInPictureMode(activity); +                    mService.mTaskSupervisor.beginDeferResume(); +                    try { +                        canEnterPip = mService.mActivityClientController +                                .requestPictureInPictureMode(activity); +                    } finally { +                        mService.mTaskSupervisor.endDeferResume(); +                        if (canEnterPip && !isPip2ExperimentEnabled()) { +                            // Wait until the transaction is applied to only resume once. +                            effects |= TRANSACT_EFFECTS_LIFECYCLE; +                        } +                    }                  }                  if (!canEnterPip) {                      // Restore the flag to its previous state when the activity cannot enter PIP. @@ -882,6 +895,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub              }          } +        // Activity in this Task may resume/pause when enter/exit pip. +        if (wasPrevFocusableAndVisible != tr.isFocusableAndVisible()) { +            effects |= TRANSACT_EFFECTS_LIFECYCLE; +        } +          return effects;      } @@ -947,7 +965,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub          }          if ((c.getChangeMask() & CHANGE_FORCE_TRANSLUCENT) != 0) {              taskFragment.setForceTranslucent(c.getForceTranslucent()); -            effects = TRANSACT_EFFECTS_LIFECYCLE; +            effects |= TRANSACT_EFFECTS_LIFECYCLE;          }          effects |= applyChanges(taskFragment, c); @@ -1225,17 +1243,32 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub                  ActivityRecord pipActivity = pipTask.getActivity(                          (activity) -> activity.pictureInPictureArgs != null); +                if (pipActivity.isState(RESUMED)) { +                    // schedulePauseActivity() call uses this flag when entering PiP after Recents +                    // swipe-up TO_FRONT transition. In this case the state of the activity is +                    // RESUMED until ActivityRecord#makeActiveIfNeeded() makes it PAUSING followed +                    // by the scheduling for PAUSE. See moveActivityToPinnedRootTask()'s call into +                    // resumeFocusedTasksTopActivities(). +                    pipActivity.mAutoEnteringPip = +                            pipActivity.pictureInPictureArgs.isAutoEnterEnabled(); +                }                  Rect entryBounds = hop.getBounds();                  mService.mRootWindowContainer.moveActivityToPinnedRootTask(                          pipActivity, null /* launchIntoPipHostActivity */,                          "moveActivityToPinnedRootTask", null /* transition */, entryBounds); -                // Continue the pausing process after potential task reparenting.                  if (pipActivity.isState(PAUSING) && pipActivity.mPauseSchedulePendingForPip) { +                    // Continue the pausing process. This must be done after moving PiP activity to +                    // a potentially new pinned task (multi-activity case). This case is only +                    // triggered if TaskFragment#startPausing() deems this an auto-enter case; +                    // i.e. we enter this flow during button-nav auto-enter but not gesture-nav +                    // auto-enter PiP for example.                      pipActivity.getTask().schedulePauseActivity(                              pipActivity, false /* userLeaving */,                              false /* pauseImmediately */, true /* autoEnteringPip */, "auto-pip");                  } +                // Reset auto-entering PiP info since any internal state updates are finished. +                pipActivity.mAutoEnteringPip = false;                  effects |= TRANSACT_EFFECTS_LIFECYCLE;                  break; @@ -1367,10 +1400,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub                  final IBinder callerActivityToken = operation.getActivityToken();                  final Intent activityIntent = operation.getActivityIntent();                  final Bundle activityOptions = operation.getBundle(); -                final int result = mService.getActivityStartController() +                final int result = waitAsyncStart(() -> mService.getActivityStartController()                          .startActivityInTaskFragment(taskFragment, activityIntent, activityOptions,                                  callerActivityToken, caller.mUid, caller.mPid, -                                errorCallbackToken); +                                errorCallbackToken));                  if (!isStartResultSuccessful(result)) {                      sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment,                              opType, convertStartFailureToThrowable(result, activityIntent)); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 7a0245bc1acc..4d9fc6c14bc0 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3701,22 +3701,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP          mDragResizingChangeReported = true;          mWindowFrames.clearReportResizeHints(); -        // App window resize may trigger Activity#onConfigurationChanged, so we need to update -        // ActivityWindowInfo as well. -        final IBinder activityToken; -        final ActivityWindowInfo activityWindowInfo; -        if (mLastReportedActivityWindowInfo != null) { -            activityToken = mActivityRecord.token; -            activityWindowInfo = mLastReportedActivityWindowInfo; -        } else { -            activityToken = null; -            activityWindowInfo = null; -        } -          final int prevRotation = mLastReportedConfiguration                  .getMergedConfiguration().windowConfiguration.getRotation();          fillClientWindowFramesAndConfiguration(mClientWindowFrames, mLastReportedConfiguration, -                activityWindowInfo, true /* useLatestConfig */, false /* relayoutVisible */); +                mLastReportedActivityWindowInfo, true /* useLatestConfig */, +                false /* relayoutVisible */);          final boolean syncRedraw = shouldSendRedrawForSync();          final boolean syncWithBuffers = syncRedraw && shouldSyncWithBuffers();          final boolean reportDraw = syncRedraw || drawPending; @@ -3740,14 +3729,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP                              mLastReportedConfiguration, getCompatInsetsState(), forceRelayout,                              alwaysConsumeSystemBars, displayId,                              syncWithBuffers ? mSyncSeqId : -1, isDragResizing, -                            activityToken, activityWindowInfo)); +                            mLastReportedActivityWindowInfo));              onResizePostDispatched(drawPending, prevRotation, displayId);          } else {              // TODO(b/301870955): cleanup after launch              try {                  mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,                          getCompatInsetsState(), forceRelayout, alwaysConsumeSystemBars, displayId, -                        syncWithBuffers ? mSyncSeqId : -1, isDragResizing, activityWindowInfo); +                        syncWithBuffers ? mSyncSeqId : -1, isDragResizing, +                        mLastReportedActivityWindowInfo);                  onResizePostDispatched(drawPending, prevRotation, displayId);              } catch (RemoteException e) {                  // Cancel orientation change of this window to avoid blocking unfreeze display. diff --git a/services/core/jni/com_android_server_am_OomConnection.cpp b/services/core/jni/com_android_server_am_OomConnection.cpp index 054937fc683e..4d07776d8023 100644 --- a/services/core/jni/com_android_server_am_OomConnection.cpp +++ b/services/core/jni/com_android_server_am_OomConnection.cpp @@ -92,9 +92,11 @@ static jobjectArray android_server_am_OomConnection_waitOom(JNIEnv* env, jobject              memevent_listener.deregisterAllEvents();              jniThrowRuntimeException(env, "Failed creating java string for process name");          } -        jobject java_oom_kill = env->NewObject(sOomKillRecordInfo.clazz, sOomKillRecordInfo.ctor, -                                               oom_kill.timestamp_ms, oom_kill.pid, oom_kill.uid, -                                               process_name, oom_kill.oom_score_adj); +        jobject java_oom_kill = +                env->NewObject(sOomKillRecordInfo.clazz, sOomKillRecordInfo.ctor, +                               oom_kill.timestamp_ms, oom_kill.pid, oom_kill.uid, process_name, +                               oom_kill.oom_score_adj, oom_kill.total_vm_kb, oom_kill.anon_rss_kb, +                               oom_kill.file_rss_kb, oom_kill.shmem_rss_kb, oom_kill.pgtables_kb);          if (java_oom_kill == NULL) {              memevent_listener.deregisterAllEvents();              jniThrowRuntimeException(env, "Failed to create OomKillRecord object"); @@ -115,8 +117,8 @@ int register_android_server_am_OomConnection(JNIEnv* env) {      sOomKillRecordInfo.clazz = FindClassOrDie(env, "android/os/OomKillRecord");      sOomKillRecordInfo.clazz = MakeGlobalRefOrDie(env, sOomKillRecordInfo.clazz); -    sOomKillRecordInfo.ctor = -            GetMethodIDOrDie(env, sOomKillRecordInfo.clazz, "<init>", "(JIILjava/lang/String;S)V"); +    sOomKillRecordInfo.ctor = GetMethodIDOrDie(env, sOomKillRecordInfo.clazz, "<init>", +                                               "(JIILjava/lang/String;SJJJJJ)V");      return RegisterMethodsOrDie(env, "com/android/server/am/OomConnection", sOomConnectionMethods,                                  NELEM(sOomConnectionMethods)); diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index f1962cb432aa..6143f1dd5b1c 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -176,7 +176,9 @@                  <xs:element type="idleScreenRefreshRateTimeout" name="idleScreenRefreshRateTimeout" minOccurs="0">                      <xs:annotation name="final"/>                  </xs:element> - +                <xs:element name="supportsVrr" type="xs:boolean" minOccurs="0"> +                    <xs:annotation name="final"/> +                </xs:element>              </xs:sequence>          </xs:complexType>      </xs:element> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index 170434cff3ff..45ec8f250efa 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -152,6 +152,7 @@ package com.android.server.display.config {      method public final java.math.BigDecimal getScreenBrightnessRampSlowIncreaseIdle();      method public final com.android.server.display.config.SensorDetails getScreenOffBrightnessSensor();      method public final com.android.server.display.config.IntegerArray getScreenOffBrightnessSensorValueToLux(); +    method public final boolean getSupportsVrr();      method public final com.android.server.display.config.SensorDetails getTempSensor();      method @NonNull public final com.android.server.display.config.ThermalThrottling getThermalThrottling();      method public final com.android.server.display.config.UsiVersion getUsiVersion(); @@ -188,6 +189,7 @@ package com.android.server.display.config {      method public final void setScreenBrightnessRampSlowIncreaseIdle(java.math.BigDecimal);      method public final void setScreenOffBrightnessSensor(com.android.server.display.config.SensorDetails);      method public final void setScreenOffBrightnessSensorValueToLux(com.android.server.display.config.IntegerArray); +    method public final void setSupportsVrr(boolean);      method public final void setTempSensor(com.android.server.display.config.SensorDetails);      method public final void setThermalThrottling(@NonNull com.android.server.display.config.ThermalThrottling);      method public final void setUsiVersion(com.android.server.display.config.UsiVersion); diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java index f5ba50d7f079..bb46c44c56c4 100644 --- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java @@ -21,6 +21,7 @@ import android.content.ComponentName;  import android.content.Context;  import android.credentials.ClearCredentialStateException;  import android.credentials.ClearCredentialStateRequest; +import android.credentials.CredentialManager;  import android.credentials.CredentialProviderInfo;  import android.credentials.IClearCredentialStateCallback;  import android.credentials.selection.ProviderData; @@ -41,7 +42,7 @@ import java.util.Set;  public final class ClearRequestSession extends RequestSession<ClearCredentialStateRequest,          IClearCredentialStateCallback, Void>          implements ProviderSession.ProviderInternalCallback<Void> { -    private static final String TAG = "GetRequestSession"; +    private static final String TAG = CredentialManager.TAG;      public ClearRequestSession(Context context, RequestSession.SessionLifetime sessionCallback,              Object lock, int userId, int callingUid, diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java index cac42b17553a..3513cb54c9bd 100644 --- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java @@ -50,7 +50,7 @@ import java.util.Set;  public final class CreateRequestSession extends RequestSession<CreateCredentialRequest,          ICreateCredentialCallback, CreateCredentialResponse>          implements ProviderSession.ProviderInternalCallback<CreateCredentialResponse> { -    private static final String TAG = "CreateRequestSession"; +    private static final String TAG = CredentialManager.TAG;      private final Set<ComponentName> mPrimaryProviders;      CreateRequestSession(@NonNull Context context, RequestSession.SessionLifetime sessionCallback, diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 281fb1c4635b..6ef14366b9e7 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -34,6 +34,7 @@ import android.content.pm.PackageManager;  import android.credentials.ClearCredentialStateRequest;  import android.credentials.CreateCredentialException;  import android.credentials.CreateCredentialRequest; +import android.credentials.CredentialManager;  import android.credentials.CredentialOption;  import android.credentials.CredentialProviderInfo;  import android.credentials.GetCandidateCredentialsException; @@ -92,7 +93,7 @@ public final class CredentialManagerService          extends AbstractMasterSystemService<          CredentialManagerService, CredentialManagerServiceImpl> { -    private static final String TAG = "CredManSysService"; +    private static final String TAG = CredentialManager.TAG;      private static final String PERMISSION_DENIED_ERROR = "permission_denied";      private static final String PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR =              "Caller is missing WRITE_SECURE_SETTINGS permission"; diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java index 379800b31597..38ad5b6594b5 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java @@ -21,6 +21,7 @@ import android.annotation.Nullable;  import android.content.ComponentName;  import android.content.pm.PackageManager;  import android.content.pm.ServiceInfo; +import android.credentials.CredentialManager;  import android.credentials.CredentialProviderInfo;  import android.service.credentials.CredentialProviderInfoFactory;  import android.util.Slog; @@ -36,7 +37,7 @@ import java.util.List;   */  public final class CredentialManagerServiceImpl extends          AbstractPerUserSystemService<CredentialManagerServiceImpl, CredentialManagerService> { -    private static final String TAG = "CredManSysServiceImpl"; +    private static final String TAG = CredentialManager.TAG;      @GuardedBy("mLock")      @NonNull @@ -93,7 +94,10 @@ public final class CredentialManagerServiceImpl extends      public ProviderSession initiateProviderSessionForRequestLocked(              RequestSession requestSession, List<String> requestOptions) {          if (!requestOptions.isEmpty() && !isServiceCapableLocked(requestOptions)) { -            Slog.i(TAG, "Service does not have the required capabilities"); +            if (mInfo != null) { +                Slog.i(TAG, "Service does not have the required capabilities: " +                        + mInfo.getComponentName()); +            }              return null;          }          if (mInfo == null) { diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java index 24f66977ee90..bfa2d6138f04 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java @@ -48,7 +48,6 @@ import java.util.UUID;  /** Initiates the Credential Manager UI and receives results. */  public class CredentialManagerUi { -    private static final String TAG = "CredentialManagerUi";      @NonNull      private final CredentialManagerUiCallback mCallbacks;      @NonNull diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java index fd2a9a20640b..69d32a0f8825 100644 --- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java @@ -22,6 +22,7 @@ import android.content.ComponentName;  import android.content.Context;  import android.content.Intent;  import android.credentials.Constants; +import android.credentials.CredentialManager;  import android.credentials.CredentialProviderInfo;  import android.credentials.GetCandidateCredentialsException;  import android.credentials.GetCandidateCredentialsResponse; @@ -54,7 +55,7 @@ import java.util.Set;  public class GetCandidateRequestSession extends RequestSession<GetCredentialRequest,          IGetCandidateCredentialsCallback, GetCandidateCredentialsResponse>          implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> { -    private static final String TAG = "GetCandidateRequestSession"; +    private static final String TAG = CredentialManager.TAG;      private static final String SESSION_ID_KEY = "autofill_session_id";      private static final String REQUEST_ID_KEY = "autofill_request_id"; diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java index d55d8effd381..c26229b75300 100644 --- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java @@ -20,6 +20,7 @@ import android.Manifest;  import android.annotation.Nullable;  import android.content.ComponentName;  import android.content.Context; +import android.credentials.CredentialManager;  import android.credentials.CredentialOption;  import android.credentials.CredentialProviderInfo;  import android.credentials.GetCredentialException; @@ -48,7 +49,7 @@ import java.util.Set;  public class GetRequestSession extends RequestSession<GetCredentialRequest,          IGetCredentialCallback, GetCredentialResponse>          implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> { -    private static final String TAG = "GetRequestSession"; +    private static final String TAG = CredentialManager.TAG;      public GetRequestSession(Context context, RequestSession.SessionLifetime sessionCallback,              Object lock, int userId, int callingUid, diff --git a/services/credentials/java/com/android/server/credentials/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java index 16bf17781eea..ac4aac694c3a 100644 --- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java +++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java @@ -20,6 +20,7 @@ import android.annotation.UserIdInt;  import android.content.ComponentName;  import android.content.Context;  import android.content.pm.PackageManager; +import android.credentials.CredentialManager;  import android.util.Slog;  import com.android.internal.util.FrameworkStatsLog; @@ -44,7 +45,7 @@ import java.util.Map;  public class MetricUtilities {      private static final boolean LOG_FLAG = true; -    private static final String TAG = "MetricUtilities"; +    private static final String TAG = CredentialManager.TAG;      public static final String USER_CANCELED_SUBSTRING = "TYPE_USER_CANCELED";      public static final int MIN_EMIT_WAIT_TIME_MS = 10; diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java index e4b5c776301e..f6b107b60d62 100644 --- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java @@ -21,6 +21,7 @@ import android.annotation.Nullable;  import android.app.PendingIntent;  import android.content.ComponentName;  import android.content.Context; +import android.credentials.CredentialManager;  import android.credentials.CredentialOption;  import android.credentials.GetCredentialRequest;  import android.credentials.IGetCredentialCallback; @@ -44,7 +45,7 @@ import java.util.stream.Collectors;   * responses from providers, and the UX app, and updates the provider(s) state.   */  public class PrepareGetRequestSession extends GetRequestSession { -    private static final String TAG = "PrepareGetRequestSession"; +    private static final String TAG = CredentialManager.TAG;      private final IPrepareGetCredentialCallback mPrepareGetCredentialCallback; diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java index 6a1b1db756b5..6759dbb6f534 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java @@ -20,6 +20,7 @@ import android.annotation.Nullable;  import android.annotation.UserIdInt;  import android.content.Context;  import android.credentials.ClearCredentialStateException; +import android.credentials.CredentialManager;  import android.credentials.CredentialProviderInfo;  import android.credentials.selection.ProviderData;  import android.credentials.selection.ProviderPendingIntentResponse; @@ -37,7 +38,7 @@ public final class ProviderClearSession extends ProviderSession<ClearCredentialS          Void>          implements          RemoteCredentialService.ProviderCallbacks<Void> { -    private static final String TAG = "ProviderClearSession"; +    private static final String TAG = CredentialManager.TAG;      private ClearCredentialStateException mProviderException; diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java index 6361aeb4f0d7..bee7f6c9e908 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java @@ -24,6 +24,7 @@ import android.content.Context;  import android.content.Intent;  import android.credentials.CreateCredentialException;  import android.credentials.CreateCredentialResponse; +import android.credentials.CredentialManager;  import android.credentials.CredentialProviderInfo;  import android.credentials.selection.CreateCredentialProviderData;  import android.credentials.selection.Entry; @@ -51,7 +52,7 @@ import java.util.Map;   */  public final class ProviderCreateSession extends ProviderSession<          BeginCreateCredentialRequest, BeginCreateCredentialResponse> { -    private static final String TAG = "ProviderCreateSession"; +    private static final String TAG = CredentialManager.TAG;      // Key to be used as an entry key for a save entry      public static final String SAVE_ENTRY_KEY = "save_entry_key"; diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index c5f292118030..e18ef2b3230d 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -22,6 +22,7 @@ import android.annotation.UserIdInt;  import android.content.ComponentName;  import android.content.Context;  import android.content.Intent; +import android.credentials.CredentialManager;  import android.credentials.CredentialOption;  import android.credentials.CredentialProviderInfo;  import android.credentials.GetCredentialException; @@ -61,7 +62,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential          BeginGetCredentialResponse>          implements          RemoteCredentialService.ProviderCallbacks<BeginGetCredentialResponse> { -    private static final String TAG = "ProviderGetSession"; +    private static final String TAG = CredentialManager.TAG;      // Key to be used as the entry key for an action entry      public static final String ACTION_ENTRY_KEY = "action_key";      // Key to be used as the entry key for the authentication entry diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java index f162916690fd..83f9c24cdaf4 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java @@ -22,6 +22,7 @@ import android.annotation.UserIdInt;  import android.content.ComponentName;  import android.content.Context;  import android.content.Intent; +import android.credentials.CredentialManager;  import android.credentials.CredentialOption;  import android.credentials.GetCredentialException;  import android.credentials.GetCredentialResponse; @@ -58,7 +59,7 @@ import java.util.stream.Stream;  public class ProviderRegistryGetSession extends ProviderSession<CredentialOption,          Set<CredentialDescriptionRegistry.FilterResult>> { -    private static final String TAG = "ProviderRegistryGetSession"; +    private static final String TAG = CredentialManager.TAG;      @VisibleForTesting      static final String CREDENTIAL_ENTRY_KEY = "credential_key"; diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java index dfc08f04386e..8f0ae9058814 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java @@ -24,6 +24,7 @@ import android.content.Context;  import android.content.pm.ApplicationInfo;  import android.content.pm.PackageManager;  import android.credentials.Credential; +import android.credentials.CredentialManager;  import android.credentials.CredentialProviderInfo;  import android.credentials.selection.ProviderData;  import android.credentials.selection.ProviderPendingIntentResponse; @@ -44,7 +45,7 @@ import java.util.UUID;  public abstract class ProviderSession<T, R>          implements RemoteCredentialService.ProviderCallbacks<R> { -    private static final String TAG = "ProviderSession"; +    private static final String TAG = CredentialManager.TAG;      @NonNull      protected final Context mContext; diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java index 4bcf8be0d21e..c36140685e03 100644 --- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java +++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java @@ -23,6 +23,7 @@ import android.content.Context;  import android.content.Intent;  import android.credentials.ClearCredentialStateException;  import android.credentials.CreateCredentialException; +import android.credentials.CredentialManager;  import android.credentials.GetCredentialException;  import android.os.Binder;  import android.os.Handler; @@ -58,7 +59,7 @@ import java.util.concurrent.atomic.AtomicReference;   */  public class RemoteCredentialService extends ServiceConnector.Impl<ICredentialProviderService> { -    private static final String TAG = "RemoteCredentialService"; +    private static final String TAG = CredentialManager.TAG;      /** Timeout for a single request. */      private static final long TIMEOUT_REQUEST_MILLIS = 3 * DateUtils.SECOND_IN_MILLIS;      /** Timeout to unbind after the task queue is empty. */ diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java index a5b9aa68b22e..054ba2bca71b 100644 --- a/services/credentials/java/com/android/server/credentials/RequestSession.java +++ b/services/credentials/java/com/android/server/credentials/RequestSession.java @@ -23,6 +23,7 @@ import android.app.PendingIntent;  import android.content.ComponentName;  import android.content.Context;  import android.content.Intent; +import android.credentials.CredentialManager;  import android.credentials.CredentialProviderInfo;  import android.credentials.flags.Flags;  import android.credentials.selection.ProviderData; @@ -56,7 +57,7 @@ import java.util.concurrent.ConcurrentHashMap;   * every time a new response type is expected from the providers.   */  abstract class RequestSession<T, U, V> implements CredentialManagerUi.CredentialManagerUiCallback { -    private static final String TAG = "RequestSession"; +    private static final String TAG = CredentialManager.TAG;      public interface SessionLifetime {          /** Called when the user makes a selection. */ diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java index f39d0193f28a..065c14e3f208 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java @@ -103,7 +103,7 @@ final class DevicePolicyEngine {                      UserManager.DISALLOW_CELLULAR_2G);      //TODO(b/295504706) : Speak to security team to decide what to set Policy_Size_Limit -    private static final int DEFAULT_POLICY_SIZE_LIMIT = -1; +    static final int DEFAULT_POLICY_SIZE_LIMIT = -1;      private final Context mContext;      private final UserManager mUserManager; @@ -225,7 +225,7 @@ final class DevicePolicyEngine {          synchronized (mLock) {              PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId); -            if (Flags.devicePolicySizeTrackingInternalEnabled()) { +            if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {                  if (!handleAdminPolicySizeLimit(localPolicyState, enforcingAdmin, value,                          policyDefinition, userId)) {                      return; @@ -350,7 +350,7 @@ final class DevicePolicyEngine {              }              PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId); -            if (Flags.devicePolicySizeTrackingInternalEnabled()) { +            if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {                  decreasePolicySizeForAdmin(localPolicyState, enforcingAdmin);              } @@ -496,7 +496,7 @@ final class DevicePolicyEngine {          synchronized (mLock) {              PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition); -            if (Flags.devicePolicySizeTrackingInternalEnabled()) { +            if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {                  if (!handleAdminPolicySizeLimit(globalPolicyState, enforcingAdmin, value,                          policyDefinition, UserHandle.USER_ALL)) {                      return; @@ -568,7 +568,7 @@ final class DevicePolicyEngine {          synchronized (mLock) {              PolicyState<V> policyState = getGlobalPolicyStateLocked(policyDefinition); -            if (Flags.devicePolicySizeTrackingInternalEnabled()) { +            if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {                  decreasePolicySizeForAdmin(policyState, enforcingAdmin);              } @@ -1598,6 +1598,7 @@ final class DevicePolicyEngine {              existingPolicySize = sizeOf(policyState.getPoliciesSetByAdmins().get(admin));          }          int policySize = sizeOf(value); +          // Policy size limit is disabled if mPolicySizeLimit is -1.          if (mPolicySizeLimit == -1                  || currentAdminPoliciesSize + policySize - existingPolicySize < mPolicySizeLimit) { @@ -1657,10 +1658,6 @@ final class DevicePolicyEngine {       * the limitation.       */      void setMaxPolicyStorageLimit(int storageLimit) { -        if (storageLimit < DEFAULT_POLICY_SIZE_LIMIT && storageLimit != -1) { -            throw new IllegalArgumentException("Can't set a size limit less than the minimum " -                    + "allowed size."); -        }          mPolicySizeLimit = storageLimit;      } @@ -1672,6 +1669,15 @@ final class DevicePolicyEngine {          return mPolicySizeLimit;      } +    int getPolicySizeForAdmin(EnforcingAdmin admin) { +        if (mAdminPolicySize.contains(admin.getUserId()) +                && mAdminPolicySize.get( +                admin.getUserId()).containsKey(admin)) { +            return mAdminPolicySize.get(admin.getUserId()).get(admin); +        } +        return 0; +    } +      public void dump(IndentingPrintWriter pw) {          synchronized (mLock) {              pw.println("Local Policies: "); @@ -1906,7 +1912,7 @@ final class DevicePolicyEngine {          private void writeEnforcingAdminSizeInner(TypedXmlSerializer serializer)                  throws IOException { -            if (Flags.devicePolicySizeTrackingInternalEnabled()) { +            if (Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {                  if (mAdminPolicySize != null) {                      for (int i = 0; i < mAdminPolicySize.size(); i++) {                          int userId = mAdminPolicySize.keyAt(i); @@ -1930,7 +1936,7 @@ final class DevicePolicyEngine {          private void writeMaxPolicySizeInner(TypedXmlSerializer serializer)                  throws IOException { -            if (!Flags.devicePolicySizeTrackingInternalEnabled()) { +            if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {                  return;              }              serializer.startTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT); @@ -2095,7 +2101,7 @@ final class DevicePolicyEngine {          private void readMaxPolicySizeInner(TypedXmlPullParser parser)                  throws XmlPullParserException, IOException { -            if (!Flags.devicePolicySizeTrackingInternalEnabled()) { +            if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {                  return;              }              mPolicySizeLimit = parser.getAttributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 1dd719eb02aa..cb637579d8db 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -88,6 +88,7 @@ import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WALLPAPER;  import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIFI;  import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WINDOWS;  import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIPE_DATA; +import static android.Manifest.permission.MANAGE_DEVICE_POLICY_STORAGE_LIMIT;  import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;  import static android.Manifest.permission.MASTER_CLEAR;  import static android.Manifest.permission.NOTIFY_PENDING_SYSTEM_UPDATE; @@ -268,6 +269,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOM  import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;  import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH;  import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS; +import static com.android.server.devicepolicy.DevicePolicyEngine.DEFAULT_POLICY_SIZE_LIMIT;  import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER;  import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER;  import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; @@ -742,7 +744,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {       * These cannot be set on the managed profile's parent DPM instance       */      private static final int PROFILE_KEYGUARD_FEATURES_PROFILE_ONLY = -            DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; +            DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS +                    | DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL;      /** Keyguard features that are allowed to be set on a managed profile */      private static final int PROFILE_KEYGUARD_FEATURES = @@ -2251,11 +2254,41 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {                  if (userHandle == UserHandle.USER_SYSTEM) {                      mStateCache.setDeviceProvisioned(policy.mUserSetupComplete);                  } +                if (Flags.headlessSingleUserBadDeviceAdminStateFix()) { +                    fixBadDeviceAdminStateForInternalUsers(userHandle, policy); +                }              }              return policy;          }      } +    private void fixBadDeviceAdminStateForInternalUsers(int userId, DevicePolicyData policy) { +        ComponentName component = mOwners.getDeviceOwnerComponent(); +        int doUserId = mOwners.getDeviceOwnerUserId(); +        ComponentName cloudDpc = new ComponentName( +                "com.google.android.apps.work.clouddpc", +                "com.google.android.apps.work.clouddpc.receivers.CloudDeviceAdminReceiver"); +        if (component == null || doUserId != userId || !component.equals(cloudDpc)) { +            return; +        } +        Slogf.i(LOG_TAG, "Attempting to apply a temp fix for cloudpc internal users' bad state."); +        final int n = policy.mAdminList.size(); +        for (int i = 0; i < n; i++) { +            ActiveAdmin admin = policy.mAdminList.get(i); +            if (component.equals(admin.info.getComponent())) { +                Slogf.i(LOG_TAG, "An ActiveAdmin already exists, fix not required."); +                return; +            } +        } +        DeviceAdminInfo dai = findAdmin(component, userId, /* throwForMissingPermission= */ false); +        if (dai != null) { +            ActiveAdmin ap = new ActiveAdmin(dai, /* parent */ false); +            policy.mAdminMap.put(ap.info.getComponent(), ap); +            policy.mAdminList.add(ap); +            Slogf.i(LOG_TAG, "Fix applied, an ActiveAdmin has been added."); +        } +    } +      /**       * Creates and loads the policy data from xml for data that is shared between       * various profiles of a user. In contrast to {@link #getUserData(int)} @@ -12138,7 +12171,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {          }          if (packageList != null) { -            if (!Flags.devicePolicySizeTrackingInternalEnabled()) { +            if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {                  for (String pkg : packageList) {                      PolicySizeVerifier.enforceMaxPackageNameLength(pkg);                  } @@ -13913,7 +13946,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {              return;          } -        if (!Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              PolicySizeVerifier.enforceMaxStringLength(accountType, "account type");          } @@ -14527,7 +14560,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {      public void setLockTaskPackages(ComponentName who, String callerPackageName, String[] packages)              throws SecurityException {          Objects.requireNonNull(packages, "packages is null"); -        if (!Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              for (String pkg : packages) {                  PolicySizeVerifier.enforceMaxPackageNameLength(pkg);              } @@ -24536,19 +24569,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {      @Override      public void setMaxPolicyStorageLimit(String callerPackageName, int storageLimit) { -        if (!Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              return;          }          CallerIdentity caller = getCallerIdentity(callerPackageName);          enforcePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, caller.getPackageName(),                  caller.getUserId()); +        if (storageLimit < DEFAULT_POLICY_SIZE_LIMIT && storageLimit != -1) { +            throw new IllegalArgumentException("Can't set a size limit less than the minimum " +                    + "allowed size."); +        }          mDevicePolicyEngine.setMaxPolicyStorageLimit(storageLimit);      }      @Override      public int getMaxPolicyStorageLimit(String callerPackageName) { -        if (!Flags.devicePolicySizeTrackingInternalEnabled()) { +        if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) {              return -1;          }          CallerIdentity caller = getCallerIdentity(callerPackageName); @@ -24559,6 +24596,32 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {      }      @Override +    public void forceSetMaxPolicyStorageLimit(String callerPackageName, int storageLimit) { +        if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) { +            return; +        } +        CallerIdentity caller = getCallerIdentity(callerPackageName); +        enforcePermission(MANAGE_DEVICE_POLICY_STORAGE_LIMIT, caller.getPackageName(), +                caller.getUserId()); + +        mDevicePolicyEngine.setMaxPolicyStorageLimit(storageLimit); +    } + +    @Override +    public int getPolicySizeForAdmin( +            String callerPackageName, android.app.admin.EnforcingAdmin admin) { +        if (!Flags.devicePolicySizeTrackingInternalBugFixEnabled()) { +            return -1; +        } +        CallerIdentity caller = getCallerIdentity(callerPackageName); +        enforcePermission(MANAGE_DEVICE_POLICY_STORAGE_LIMIT, caller.getPackageName(), +                caller.getUserId()); + +        return mDevicePolicyEngine.getPolicySizeForAdmin( +                EnforcingAdmin.createEnforcingAdmin(admin)); +    } + +    @Override      public int getHeadlessDeviceOwnerMode(String callerPackageName) {          final CallerIdentity caller = getCallerIdentity(callerPackageName);          enforcePermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, caller.getPackageName(), diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java index d234dee3c8f7..02590f97ab6b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java @@ -21,6 +21,7 @@ import android.annotation.Nullable;  import android.app.admin.Authority;  import android.app.admin.DeviceAdminAuthority;  import android.app.admin.DpcAuthority; +import android.app.admin.PackagePermissionPolicyKey;  import android.app.admin.RoleAuthority;  import android.app.admin.UnknownAuthority;  import android.content.ComponentName; @@ -105,6 +106,32 @@ final class EnforcingAdmin {                  userId, activeAdmin);      } +    static EnforcingAdmin createEnforcingAdmin(android.app.admin.EnforcingAdmin admin) { +        Objects.requireNonNull(admin); +        Authority authority = admin.getAuthority(); +        Set<String> internalAuthorities = new HashSet<>(); +        if (DpcAuthority.DPC_AUTHORITY.equals(authority)) { +            return new EnforcingAdmin( +                    admin.getPackageName(), admin.getComponentName(), +                    Set.of(DPC_AUTHORITY), admin.getUserHandle().getIdentifier(), +                    /* activeAdmin = */ null); +        } else if (DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY.equals(authority)) { +            return new EnforcingAdmin( +                    admin.getPackageName(), admin.getComponentName(), +                    Set.of(DEVICE_ADMIN_AUTHORITY), admin.getUserHandle().getIdentifier(), +                    /* activeAdmin = */ null); +        } else if (authority instanceof RoleAuthority roleAuthority) { +            return new EnforcingAdmin( +                    admin.getPackageName(), admin.getComponentName(), +                    Set.of(DEVICE_ADMIN_AUTHORITY), admin.getUserHandle().getIdentifier(), +                    /* activeAdmin = */ null, +                    /* isRoleAuthority = */ true); +        } +        return new EnforcingAdmin(admin.getPackageName(), admin.getComponentName(), +                Set.of(), admin.getUserHandle().getIdentifier(), +                /* activeAdmin = */ null); +    } +      static String getRoleAuthorityOf(String roleName) {          return ROLE_AUTHORITY_PREFIX + roleName;      } @@ -154,6 +181,20 @@ final class EnforcingAdmin {          mActiveAdmin = activeAdmin;      } +    private EnforcingAdmin( +            String packageName, @Nullable ComponentName componentName, Set<String> authorities, +            int userId, @Nullable ActiveAdmin activeAdmin, boolean isRoleAuthority) { +        Objects.requireNonNull(packageName); +        Objects.requireNonNull(authorities); + +        mIsRoleAuthority = isRoleAuthority; +        mPackageName = packageName; +        mComponentName = componentName; +        mAuthorities = new HashSet<>(authorities); +        mUserId = userId; +        mActiveAdmin = activeAdmin; +    } +      private static Set<String> getRoleAuthoritiesOrDefault(String packageName, int userId) {          Set<String> roles = getRoles(packageName, userId);          Set<String> authorities = new HashSet<>(); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 3c6b500d9ced..648b8100cd36 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -313,8 +313,8 @@ public final class SystemServer implements Dumpable {      private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;      /* -     * Implementation class names. TODO: Move them to a codegen class or load -     * them from the build system somehow. +     * Implementation class names for services in the {@code SYSTEMSERVERCLASSPATH} +     * from {@code PRODUCT_SYSTEM_SERVER_JARS} that are *not* in {@code services.jar}.       */      private static final String ARC_NETWORK_SERVICE_CLASS =              "com.android.server.arc.net.ArcNetworkService"; @@ -322,26 +322,6 @@ public final class SystemServer implements Dumpable {              "com.android.server.arc.persistent_data_block.ArcPersistentDataBlockService";      private static final String ARC_SYSTEM_HEALTH_SERVICE =              "com.android.server.arc.health.ArcSystemHealthService"; -    private static final String STATS_COMPANION_APEX_PATH = -            "/apex/com.android.os.statsd/javalib/service-statsd.jar"; -    private static final String STATS_COMPANION_LIFECYCLE_CLASS = -            "com.android.server.stats.StatsCompanion$Lifecycle"; -    private static final String SCHEDULING_APEX_PATH = -            "/apex/com.android.scheduling/javalib/service-scheduling.jar"; -    private static final String REBOOT_READINESS_LIFECYCLE_CLASS = -            "com.android.server.scheduling.RebootReadinessManagerService$Lifecycle"; -    private static final String WIFI_APEX_SERVICE_JAR_PATH = -            "/apex/com.android.wifi/javalib/service-wifi.jar"; -    private static final String WIFI_SERVICE_CLASS = -            "com.android.server.wifi.WifiService"; -    private static final String WIFI_SCANNING_SERVICE_CLASS = -            "com.android.server.wifi.scanner.WifiScanningService"; -    private static final String WIFI_RTT_SERVICE_CLASS = -            "com.android.server.wifi.rtt.RttService"; -    private static final String WIFI_AWARE_SERVICE_CLASS = -            "com.android.server.wifi.aware.WifiAwareService"; -    private static final String WIFI_P2P_SERVICE_CLASS = -            "com.android.server.wifi.p2p.WifiP2pService";      private static final String LOWPAN_SERVICE_CLASS =              "com.android.server.lowpan.LowpanService";      private static final String THERMAL_OBSERVER_CLASS = @@ -368,21 +348,19 @@ public final class SystemServer implements Dumpable {              "com.android.clockwork.settings.WearSettingsService";      private static final String WRIST_ORIENTATION_SERVICE_CLASS =              "com.android.clockwork.wristorientation.WristOrientationService"; -      private static final String IOT_SERVICE_CLASS =              "com.android.things.server.IoTSystemService";      private static final String CAR_SERVICE_HELPER_SERVICE_CLASS =              "com.android.internal.car.CarServiceHelperService"; + +    /* +     * Implementation class names for services in the {@code SYSTEMSERVERCLASSPATH} +     * from {@code PRODUCT_APEX_SYSTEM_SERVER_JARS}. +     */      private static final String APPSEARCH_MODULE_LIFECYCLE_CLASS =              "com.android.server.appsearch.AppSearchModule$Lifecycle";      private static final String ISOLATED_COMPILATION_SERVICE_CLASS =              "com.android.server.compos.IsolatedCompilationService"; -    private static final String CONNECTIVITY_SERVICE_APEX_PATH = -            "/apex/com.android.tethering/javalib/service-connectivity.jar"; -    private static final String CONNECTIVITY_SERVICE_INITIALIZER_CLASS = -            "com.android.server.ConnectivityServiceInitializer"; -    private static final String NETWORK_STATS_SERVICE_INITIALIZER_CLASS = -            "com.android.server.NetworkStatsServiceInitializer";      private static final String MEDIA_COMMUNICATION_SERVICE_CLASS =              "com.android.server.media.MediaCommunicationService";      private static final String HEALTHCONNECT_MANAGER_SERVICE_CLASS = @@ -390,17 +368,8 @@ public final class SystemServer implements Dumpable {      private static final String ROLE_SERVICE_CLASS = "com.android.role.RoleService";      private static final String ENHANCED_CONFIRMATION_SERVICE_CLASS =              "com.android.ecm.EnhancedConfirmationService"; - -    private static final String UWB_APEX_SERVICE_JAR_PATH = -            "/apex/com.android.uwb/javalib/service-uwb.jar"; -    private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService"; -    private static final String BLUETOOTH_APEX_SERVICE_JAR_PATH = -            "/apex/com.android.btservices/javalib/service-bluetooth.jar"; -    private static final String BLUETOOTH_SERVICE_CLASS = -            "com.android.server.bluetooth.BluetoothService";      private static final String SAFETY_CENTER_SERVICE_CLASS =              "com.android.safetycenter.SafetyCenterService"; -      private static final String SDK_SANDBOX_MANAGER_SERVICE_CLASS =              "com.android.server.sdksandbox.SdkSandboxManagerService$Lifecycle";      private static final String AD_SERVICES_MANAGER_SERVICE_CLASS = @@ -411,11 +380,47 @@ public final class SystemServer implements Dumpable {      private static final String UPDATABLE_DEVICE_CONFIG_SERVICE_CLASS =              "com.android.server.deviceconfig.DeviceConfigInit$Lifecycle"; +    /* +     * Implementation class names and jar locations for services in +     * {@code STANDALONE_SYSTEMSERVER_JARS}. +     */ +    private static final String STATS_COMPANION_APEX_PATH = +            "/apex/com.android.os.statsd/javalib/service-statsd.jar"; +    private static final String STATS_COMPANION_LIFECYCLE_CLASS = +            "com.android.server.stats.StatsCompanion$Lifecycle"; +    private static final String SCHEDULING_APEX_PATH = +            "/apex/com.android.scheduling/javalib/service-scheduling.jar"; +    private static final String REBOOT_READINESS_LIFECYCLE_CLASS = +            "com.android.server.scheduling.RebootReadinessManagerService$Lifecycle"; +    private static final String WIFI_APEX_SERVICE_JAR_PATH = +            "/apex/com.android.wifi/javalib/service-wifi.jar"; +    private static final String WIFI_SERVICE_CLASS = +            "com.android.server.wifi.WifiService"; +    private static final String WIFI_SCANNING_SERVICE_CLASS = +            "com.android.server.wifi.scanner.WifiScanningService"; +    private static final String WIFI_RTT_SERVICE_CLASS = +            "com.android.server.wifi.rtt.RttService"; +    private static final String WIFI_AWARE_SERVICE_CLASS = +            "com.android.server.wifi.aware.WifiAwareService"; +    private static final String WIFI_P2P_SERVICE_CLASS = +            "com.android.server.wifi.p2p.WifiP2pService"; +    private static final String CONNECTIVITY_SERVICE_APEX_PATH = +            "/apex/com.android.tethering/javalib/service-connectivity.jar"; +    private static final String CONNECTIVITY_SERVICE_INITIALIZER_CLASS = +            "com.android.server.ConnectivityServiceInitializer"; +    private static final String NETWORK_STATS_SERVICE_INITIALIZER_CLASS = +            "com.android.server.NetworkStatsServiceInitializer"; +    private static final String UWB_APEX_SERVICE_JAR_PATH = +            "/apex/com.android.uwb/javalib/service-uwb.jar"; +    private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService"; +    private static final String BLUETOOTH_APEX_SERVICE_JAR_PATH = +            "/apex/com.android.btservices/javalib/service-bluetooth.jar"; +    private static final String BLUETOOTH_SERVICE_CLASS = +            "com.android.server.bluetooth.BluetoothService";      private static final String DEVICE_LOCK_SERVICE_CLASS =              "com.android.server.devicelock.DeviceLockService";      private static final String DEVICE_LOCK_APEX_PATH =              "/apex/com.android.devicelock/javalib/service-devicelock.jar"; -      private static final String PROFILING_SERVICE_LIFECYCLE_CLASS =              "android.os.profiling.ProfilingService$Lifecycle";      private static final String PROFILING_SERVICE_JAR_PATH = diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt index 36758341d4d7..69a88e982f96 100644 --- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt +++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt @@ -16,7 +16,6 @@  package com.android.server.permission.access -import android.permission.flags.Flags  import android.util.Slog  import com.android.modules.utils.BinaryXmlPullParser  import com.android.modules.utils.BinaryXmlSerializer @@ -79,7 +78,7 @@ private constructor(              setPackageStates(packageStates)              setDisabledSystemPackageStates(disabledSystemPackageStates)              packageStates.forEach { (_, packageState) -> -                if (Flags.ignoreApexPermissions() && packageState.isApex) { +                if (packageState.isApex) {                      return@forEach                  }                  mutateAppIdPackageNames() @@ -107,7 +106,7 @@ private constructor(          newState.mutateUserStatesNoWrite()[userId] = MutableUserState()          forEachSchemePolicy { with(it) { onUserAdded(userId) } }          newState.externalState.packageStates.forEach { (_, packageState) -> -            if (Flags.ignoreApexPermissions() && packageState.isApex) { +            if (packageState.isApex) {                  return@forEach              }              upgradePackageVersion(packageState, userId) @@ -133,7 +132,7 @@ private constructor(              setPackageStates(packageStates)              setDisabledSystemPackageStates(disabledSystemPackageStates)              packageStates.forEach { (packageName, packageState) -> -                if (Flags.ignoreApexPermissions() && packageState.isApex) { +                if (packageState.isApex) {                      return@forEach                  }                  if (packageState.volumeUuid == volumeUuid) { @@ -161,7 +160,7 @@ private constructor(              with(it) { onStorageVolumeMounted(volumeUuid, packageNames, isSystemUpdated) }          }          packageStates.forEach { (_, packageState) -> -            if (Flags.ignoreApexPermissions() && packageState.isApex) { +            if (packageState.isApex) {                  return@forEach              }              if (packageState.volumeUuid == volumeUuid) { diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt index 63fb468c8f54..87af841b901c 100644 --- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt +++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt @@ -81,7 +81,7 @@ class AppIdPermissionPolicy : SchemePolicy() {      override fun MutateStateScope.onUserAdded(userId: Int) {          newState.externalState.packageStates.forEach { (_, packageState) -> -            if (Flags.ignoreApexPermissions() && packageState.isApex) { +            if (packageState.isApex) {                  return@forEach              }              evaluateAllPermissionStatesForPackageAndUser(packageState, userId, null) diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt index 44ed3df34f24..65feeb027b3e 100644 --- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt +++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt @@ -1445,7 +1445,7 @@ class PermissionService(private val service: AccessCheckingService) :          val packageStates = packageManagerLocal.withUnfilteredSnapshot().use { it.packageStates }          service.mutateState {              packageStates.forEach { (packageName, packageState) -> -                if (Flags.ignoreApexPermissions() && packageState.isApex) { +                if (packageState.isApex) {                      return@forEach                  }                  val androidPackage = packageState.androidPackage ?: return@forEach @@ -1880,7 +1880,7 @@ class PermissionService(private val service: AccessCheckingService) :          packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->              service.mutateState {                  snapshot.packageStates.forEach { (_, packageState) -> -                    if (Flags.ignoreApexPermissions() && packageState.isApex) { +                    if (packageState.isApex) {                          return@forEach                      }                      with(policy) { resetRuntimePermissions(packageState.packageName, userId) } @@ -1925,7 +1925,7 @@ class PermissionService(private val service: AccessCheckingService) :          packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->              snapshot.packageStates.forEach { (_, packageState) -> -                if (Flags.ignoreApexPermissions() && packageState.isApex) { +                if (packageState.isApex) {                      return@forEach                  }                  val androidPackage = packageState.androidPackage ?: return@forEach @@ -1943,7 +1943,7 @@ class PermissionService(private val service: AccessCheckingService) :          val permissions = service.getState { with(policy) { getPermissions() } }          packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->              snapshot.packageStates.forEach packageStates@{ (_, packageState) -> -                if (Flags.ignoreApexPermissions() && packageState.isApex) { +                if (packageState.isApex) {                      return@packageStates                  }                  val androidPackage = packageState.androidPackage ?: return@packageStates @@ -2072,7 +2072,7 @@ class PermissionService(private val service: AccessCheckingService) :          val appIdPackageNames = MutableIndexedMap<Int, MutableIndexedSet<String>>()          packageStates.forEach { (_, packageState) -> -            if (Flags.ignoreApexPermissions() && packageState.isApex) { +            if (packageState.isApex) {                  return@forEach              }              appIdPackageNames @@ -2328,7 +2328,7 @@ class PermissionService(private val service: AccessCheckingService) :          isInstantApp: Boolean,          oldPackage: AndroidPackage?      ) { -        if (Flags.ignoreApexPermissions() && packageState.isApex) { +        if (packageState.isApex) {              return          } @@ -2358,7 +2358,7 @@ class PermissionService(private val service: AccessCheckingService) :          params: PermissionManagerServiceInternal.PackageInstalledParams,          userId: Int      ) { -        if (Flags.ignoreApexPermissions() && androidPackage.isApex) { +        if (androidPackage.isApex) {              return          } @@ -2414,7 +2414,7 @@ class PermissionService(private val service: AccessCheckingService) :          sharedUserPkgs: List<AndroidPackage>,          userId: Int      ) { -        if (Flags.ignoreApexPermissions() && packageState.isApex) { +        if (packageState.isApex) {              return          } diff --git a/services/proguard.flags b/services/proguard.flags index f84eff79bb15..bf30781b434e 100644 --- a/services/proguard.flags +++ b/services/proguard.flags @@ -29,11 +29,6 @@    public protected *;  } -# Derivatives of SystemService and other services created via reflection --keep,allowoptimization,allowaccessmodification class * extends com.android.server.SystemService { -  public <methods>; -} -  # Accessed from com.android.compos APEX  -keep,allowoptimization,allowaccessmodification class com.android.internal.art.ArtStatsLog {     public static void write(...); diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java index 94ee0a871448..a547d0f94ea3 100644 --- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java +++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java @@ -17,9 +17,7 @@  package com.android.server.backup;  import static android.Manifest.permission.BACKUP; -import static android.Manifest.permission.DUMP;  import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; -import static android.Manifest.permission.PACKAGE_USAGE_STATS;  import static com.android.server.backup.testing.TransportData.backupTransport; @@ -73,10 +71,7 @@ import org.robolectric.shadow.api.Shadow;  import org.robolectric.shadows.ShadowContextWrapper;  import java.io.File; -import java.io.FileDescriptor;  import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter;  /** Tests for {@link BackupManagerService}. */  @RunWith(RobolectricTestRunner.class) @@ -1461,67 +1456,12 @@ public class BackupManagerServiceRoboTest {      //  Service tests      // --------------------------------------------- -    /** Test that the backup service routes methods correctly to the user that requests it. */ -    @Test -    public void testDump_onRegisteredUser_callsMethodForUser() throws Exception { -        grantDumpPermissions(); -        BackupManagerService backupManagerService = createSystemRegisteredService(); -        File testFile = createTestFile(); -        FileDescriptor fileDescriptor = new FileDescriptor(); -        PrintWriter printWriter = new PrintWriter(testFile); -        String[] args = {"1", "2"}; -        ShadowBinder.setCallingUserHandle(UserHandle.of(UserHandle.USER_SYSTEM)); - -        backupManagerService.dump(fileDescriptor, printWriter, args); - -        verify(mUserSystemService).dump(fileDescriptor, printWriter, args); -    } - -    /** Test that the backup service does not route methods for non-registered users. */ -    @Test -    public void testDump_onUnknownUser_doesNotPropagateCall() throws Exception { -        grantDumpPermissions(); -        BackupManagerService backupManagerService = createService(); -        File testFile = createTestFile(); -        FileDescriptor fileDescriptor = new FileDescriptor(); -        PrintWriter printWriter = new PrintWriter(testFile); -        String[] args = {"1", "2"}; - -        backupManagerService.dump(fileDescriptor, printWriter, args); - -        verify(mUserOneService, never()).dump(fileDescriptor, printWriter, args); -    } - -    /** Test that 'dumpsys backup users' dumps the list of users registered in backup service*/ -    @Test -    public void testDump_users_dumpsListOfRegisteredUsers() { -        grantDumpPermissions(); -        BackupManagerService backupManagerService = createSystemRegisteredService(); -        registerUser(backupManagerService, mUserOneId, mUserOneService); -        StringWriter out = new StringWriter(); -        PrintWriter writer = new PrintWriter(out); -        String[] args = {"users"}; - -        backupManagerService.dump(null, writer, args); - -        writer.flush(); -        assertEquals( -                String.format("%s %d %d\n", BackupManagerService.DUMP_RUNNING_USERS_MESSAGE, -                        UserHandle.USER_SYSTEM, mUserOneId), -                out.toString()); -    } -      private File createTestFile() throws IOException {          File testFile = new File(mContext.getFilesDir(), "test");          testFile.createNewFile();          return testFile;      } -    private void grantDumpPermissions() { -        mShadowContext.grantPermissions(DUMP); -        mShadowContext.grantPermissions(PACKAGE_USAGE_STATS); -    } -      /**       * Test that the backup services throws a {@link SecurityException} if the caller does not have       * INTERACT_ACROSS_USERS_FULL permission and passes a different user id. diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index 66dd43a19859..1666fef13685 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -133,8 +133,8 @@ import androidx.test.runner.AndroidJUnit4;  import com.android.internal.R;  import com.android.internal.util.test.FakeSettingsProvider;  import com.android.internal.util.test.FakeSettingsProviderRule; +import com.android.internal.util.test.LocalServiceKeeperRule;  import com.android.modules.utils.testing.ExtendedMockitoRule; -import com.android.server.LocalServices;  import com.android.server.SystemService;  import com.android.server.companion.virtual.VirtualDeviceManagerInternal;  import com.android.server.display.DisplayManagerService.DeviceStateListener; @@ -218,6 +218,9 @@ public class DisplayManagerServiceTest {      @Rule      public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); +    @Rule(order = 2) +    public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule(); +      private Context mContext;      private Resources mResources; @@ -354,6 +357,7 @@ public class DisplayManagerServiceTest {      @Mock SensorManager mSensorManager;      @Mock DisplayDeviceConfig mMockDisplayDeviceConfig;      @Mock PackageManagerInternal mMockPackageManagerInternal; +    @Mock DisplayManagerInternal mMockDisplayManagerInternal;      @Mock DisplayAdapter mMockDisplayAdapter;      @Captor ArgumentCaptor<ContentRecordingSession> mContentRecordingSessionCaptor; @@ -371,20 +375,20 @@ public class DisplayManagerServiceTest {          when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(false);          mSetFlagsRule.disableFlags(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR); -        LocalServices.removeServiceForTest(InputManagerInternal.class); -        LocalServices.addService(InputManagerInternal.class, mMockInputManagerInternal); -        LocalServices.removeServiceForTest(WindowManagerInternal.class); -        LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerInternal); -        LocalServices.removeServiceForTest(LightsManager.class); -        LocalServices.addService(LightsManager.class, mMockLightsManager); -        LocalServices.removeServiceForTest(SensorManagerInternal.class); -        LocalServices.addService(SensorManagerInternal.class, mMockSensorManagerInternal); -        LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class); -        LocalServices.addService( +        mLocalServiceKeeperRule.overrideLocalService( +                InputManagerInternal.class, mMockInputManagerInternal); +        mLocalServiceKeeperRule.overrideLocalService( +                WindowManagerInternal.class, mMockWindowManagerInternal); +        mLocalServiceKeeperRule.overrideLocalService( +                LightsManager.class, mMockLightsManager); +        mLocalServiceKeeperRule.overrideLocalService( +                SensorManagerInternal.class, mMockSensorManagerInternal); +        mLocalServiceKeeperRule.overrideLocalService(                  VirtualDeviceManagerInternal.class, mMockVirtualDeviceManagerInternal); -        LocalServices.removeServiceForTest(PackageManagerInternal.class); -        LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal); -        // TODO: b/287945043 +        mLocalServiceKeeperRule.overrideLocalService( +                PackageManagerInternal.class, mMockPackageManagerInternal); +        mLocalServiceKeeperRule.overrideLocalService( +                DisplayManagerInternal.class, mMockDisplayManagerInternal);          Display display = mock(Display.class);          when(display.getDisplayAdjustments()).thenReturn(new DisplayAdjustments());          when(display.getBrightnessInfo()).thenReturn(mock(BrightnessInfo.class)); @@ -1704,7 +1708,6 @@ public class DisplayManagerServiceTest {       * {@link VirtualDisplayConfig.Builder#setSurface(Surface)}       */      @Test -    @FlakyTest(bugId = 127687569)      public void testCreateVirtualDisplay_setSurface() throws Exception {          DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);          registerDefaultDisplays(displayManager); @@ -2629,11 +2632,19 @@ public class DisplayManagerServiceTest {          // Create default display device          createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);          callback.waitForExpectedEvent(); + +        callback.expectsEvent(EVENT_DISPLAY_ADDED);          FakeDisplayDevice displayDevice =                  createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL); +        callback.waitForExpectedEvent(); + +        callback.expectsEvent(EVENT_DISPLAY_REMOVED); +        displayManager.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); +        callback.waitForExpectedEvent(); + +        callback.expectsEvent(EVENT_DISPLAY_ADDED);          LogicalDisplay display =                  logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true); -        callback.expectsEvent(EVENT_DISPLAY_ADDED);          logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ true);          logicalDisplayMapper.updateLogicalDisplays();          callback.waitForExpectedEvent(); @@ -2656,6 +2667,7 @@ public class DisplayManagerServiceTest {          LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();          FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();          bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS); +        displayManager.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);          callback.expectsEvent(EVENT_DISPLAY_ADDED);          // Create default display device          createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL); @@ -2669,7 +2681,6 @@ public class DisplayManagerServiceTest {          logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ true);          logicalDisplayMapper.updateLogicalDisplays();          callback.waitForExpectedEvent(); -        callback.clear();          assertThrows(SecurityException.class, () -> bs.disableConnectedDisplay(displayId));      } @@ -2840,6 +2851,7 @@ public class DisplayManagerServiceTest {          float brightness1 = 0.3f;          float brightness2 = 0.45f; +        waitForIdleHandler(mPowerHandler);          int userId1 = 123;          int userId2 = 456; @@ -2849,8 +2861,8 @@ public class DisplayManagerServiceTest {          userInfo2.id = userId2;          when(mUserManager.getUserSerialNumber(userId1)).thenReturn(12345);          when(mUserManager.getUserSerialNumber(userId2)).thenReturn(45678); -        final SystemService.TargetUser from = new SystemService.TargetUser(userInfo1); -        final SystemService.TargetUser to = new SystemService.TargetUser(userInfo2); +        final SystemService.TargetUser user1 = new SystemService.TargetUser(userInfo1); +        final SystemService.TargetUser user2 = new SystemService.TargetUser(userInfo2);          // The same brightness will be restored for a user only if auto-brightness is off,          // otherwise the current lux will be used to determine the brightness. @@ -2858,20 +2870,20 @@ public class DisplayManagerServiceTest {                  Settings.System.SCREEN_BRIGHTNESS_MODE,                  Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); -        displayManager.onUserSwitching(to, from); +        displayManager.onUserSwitching(/* from= */ user2, /* to= */ user1);          waitForIdleHandler(mPowerHandler);          displayManagerBinderService.setBrightness(Display.DEFAULT_DISPLAY, brightness1); -        displayManager.onUserSwitching(from, to); +        displayManager.onUserSwitching(/* from= */ user1, /* to= */ user2);          waitForIdleHandler(mPowerHandler);          displayManagerBinderService.setBrightness(Display.DEFAULT_DISPLAY, brightness2); -        displayManager.onUserSwitching(to, from); +        displayManager.onUserSwitching(/* from= */ user2, /* to= */ user1);          waitForIdleHandler(mPowerHandler);          assertEquals(brightness1,                  displayManagerBinderService.getBrightness(Display.DEFAULT_DISPLAY),                  FLOAT_TOLERANCE); -        displayManager.onUserSwitching(from, to); +        displayManager.onUserSwitching(/* from= */ user1, /* to= */ user2);          waitForIdleHandler(mPowerHandler);          assertEquals(brightness2,                  displayManagerBinderService.getBrightness(Display.DEFAULT_DISPLAY), @@ -3005,6 +3017,7 @@ public class DisplayManagerServiceTest {                  new DisplayManagerService(mContext, mBasicInjector);          displayManager.systemReady(false /* safeMode */); +        displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);          ArgumentMatcher<IntentFilter> matchesFilter =                  (filter) -> Intent.ACTION_SETTING_RESTORED.equals(filter.getAction(0));          verify(mContext, times(0)).registerReceiver(any(BroadcastReceiver.class), @@ -3370,7 +3383,7 @@ public class DisplayManagerServiceTest {          void waitForExpectedEvent(Duration timeout) {              try { -                assertWithMessage("Event '" + mExpectedEvent + "' is received.") +                assertWithMessage("Expected '" + mExpectedEvent + "'")                          .that(mLatch.await(timeout.toMillis(), TimeUnit.MILLISECONDS)).isTrue();              } catch (InterruptedException ex) {                  throw new AssertionError("Waiting for expected event interrupted", ex); diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt index b182ccef091e..0cf0850f0882 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/BrightnessObserverTest.kt @@ -19,6 +19,7 @@ package com.android.server.display.mode  import android.content.Context  import android.content.ContextWrapper  import android.hardware.display.BrightnessInfo +import android.util.SparseBooleanArray  import android.view.Display  import androidx.test.core.app.ApplicationProvider  import androidx.test.filters.SmallTest @@ -62,8 +63,11 @@ class BrightnessObserverTest {          whenever(mockFlags.isVsyncLowLightVoteEnabled).thenReturn(testCase.vsyncLowLightVoteEnabled)          val displayModeDirector = DisplayModeDirector(                  spyContext, testHandler, mockInjector, mockFlags) +        val vrrByDisplay = SparseBooleanArray() +        vrrByDisplay.put(Display.DEFAULT_DISPLAY, testCase.vrrSupported) +        displayModeDirector.injectVrrByDisplay(vrrByDisplay)          val brightnessObserver = displayModeDirector.BrightnessObserver( -                spyContext, testHandler, mockInjector, testCase.vrrSupported, mockFlags) +                spyContext, testHandler, mockInjector, mockFlags)          brightnessObserver.onRefreshRateSettingChangedLocked(0.0f, 120.0f)          brightnessObserver.updateBlockingZoneThresholds(mockDeviceConfig, false) diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java index fbc38a24b8a5..0efd04657033 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java @@ -338,8 +338,6 @@ public class DisplayModeDirectorTest {                  .thenReturn(false);          when(resources.getBoolean(R.bool.config_refreshRateSynchronizationEnabled))                  .thenReturn(false); -        when(resources.getBoolean(R.bool.config_supportsDvrr)) -                .thenReturn(false);          when(resources.getInteger(R.integer.config_displayWhiteBalanceBrightnessFilterHorizon))                  .thenReturn(10000);          when(resources.getInteger(R.integer.config_defaultPeakRefreshRate)) @@ -393,41 +391,87 @@ public class DisplayModeDirectorTest {      private DisplayModeDirector createDirectorFromRefreshRateArray(              float[] refreshRates, int baseModeId, float defaultRefreshRate) { -        Display.Mode[] modes = new Display.Mode[refreshRates.length]; -        Display.Mode defaultMode = null; -        for (int i = 0; i < refreshRates.length; i++) { -            modes[i] = new Display.Mode( -                    /*modeId=*/baseModeId + i, /*width=*/1000, /*height=*/1000, refreshRates[i]); -            if (refreshRates[i] == defaultRefreshRate) { -                defaultMode = modes[i]; -            } -        } +        return createDirectorFromRefreshRateArray(refreshRates, baseModeId, defaultRefreshRate, +                new int[]{DISPLAY_ID}); +    } + +    private DisplayModeDirector createDirectorFromRefreshRateArray( +            float[] refreshRates, int baseModeId, float defaultRefreshRate, int[] displayIds) { +        Display.Mode[] modes = createDisplayModes(refreshRates, baseModeId); +        Display.Mode defaultMode = getDefaultMode(modes, defaultRefreshRate); +          assertThat(defaultMode).isNotNull(); -        return createDirectorFromModeArray(modes, defaultMode); +        return createDirectorFromModeArray(modes, defaultMode, displayIds);      }      private DisplayModeDirector createDirectorFromModeArray(Display.Mode[] modes,              Display.Mode defaultMode) { +        return createDirectorFromModeArray(modes, defaultMode, new int[]{DISPLAY_ID}); +    } + +    private DisplayModeDirector createDirectorFromModeArray(Display.Mode[] modes, +            Display.Mode defaultMode, int[] displayIds) {          DisplayModeDirector director =                  new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags);          director.setLoggingEnabled(true); +        setupModesForDisplays(director, displayIds , modes, defaultMode); +        return director; +    } + +    private DisplayModeDirector createDirectorFromFpsRange(int minFps, int maxFps) { +        return createDirectorFromRefreshRateArray( +                createRefreshRateRanges(minFps, maxFps), +                /*baseModeId=*/minFps, +                /*defaultRefreshRate=*/minFps, +                new int[]{DISPLAY_ID}); +    } + +    private DisplayModeDirector createDirectorFromFpsRange( +            int minFps, int maxFps, int[] displayIds) { +        return createDirectorFromRefreshRateArray( +                createRefreshRateRanges(minFps, maxFps), +                /*baseModeId=*/minFps, +                /*defaultRefreshRate=*/minFps, +                displayIds); +    } + +    private void setupModesForDisplays(DisplayModeDirector director, int[] displayIds, +            Display.Mode[] modes, Display.Mode defaultMode) {          SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>(); -        supportedModesByDisplay.put(DISPLAY_ID, modes); -        director.injectSupportedModesByDisplay(supportedModesByDisplay);          SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<>(); -        defaultModesByDisplay.put(DISPLAY_ID, defaultMode); +        for (int displayId: displayIds) { +            supportedModesByDisplay.put(displayId, modes); +            defaultModesByDisplay.put(displayId, defaultMode); +        } +        director.injectSupportedModesByDisplay(supportedModesByDisplay);          director.injectDefaultModeByDisplay(defaultModesByDisplay); -        return director;      } -    private DisplayModeDirector createDirectorFromFpsRange(int minFps, int maxFps) { +    private Display.Mode[] createDisplayModes(float[] refreshRates, int baseModeId) { +        Display.Mode[] modes = new Display.Mode[refreshRates.length]; +        for (int i = 0; i < refreshRates.length; i++) { +            modes[i] = new Display.Mode( +                    /*modeId=*/baseModeId + i, /*width=*/1000, /*height=*/1000, refreshRates[i]); +        } +        return modes; +    } + +    private Display.Mode getDefaultMode(Display.Mode[] modes, float defaultRefreshRate) { +        for (Display.Mode mode : modes) { +            if (mode.getRefreshRate() == defaultRefreshRate) { +                return mode; +            } +        } +        return null; +    } + +    private float[] createRefreshRateRanges(int minFps, int maxFps) {          int numRefreshRates = maxFps - minFps + 1;          float[] refreshRates = new float[numRefreshRates];          for (int i = 0; i < numRefreshRates; i++) {              refreshRates[i] = minFps + i;          } -        return createDirectorFromRefreshRateArray(refreshRates, /*baseModeId=*/minFps, -                /*defaultRefreshRate=*/minFps); +        return refreshRates;      }      @Test @@ -1893,6 +1937,7 @@ public class DisplayModeDirectorTest {          mInjector.mDisplayInfo.displayId = DISPLAY_ID_2;          DisplayModeDirector director = createDirectorFromModeArray(TEST_MODES, DEFAULT_MODE_60); +        director.start(createMockSensorManager());          SparseArray<Vote> votes = new SparseArray<>();          votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRenderFrameRates(0, 50f)); diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java index 92016dfc631b..d0dd9218eb17 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java @@ -39,6 +39,7 @@ import android.content.Context;  import android.content.ContextWrapper;  import android.content.res.Resources;  import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManagerInternal;  import android.os.Handler;  import android.os.Looper;  import android.provider.DeviceConfigInterface; @@ -426,8 +427,12 @@ public class DisplayObserverTest {              return true;          }).when(mInjector).getDisplayInfo(eq(EXTERNAL_DISPLAY), /*displayInfo=*/ any()); -        doAnswer(c -> mock(SensorManagerInternal.class)).when(mInjector).getSensorManagerInternal(); +        doAnswer(c -> mock(SensorManagerInternal.class)) +                .when(mInjector).getSensorManagerInternal();          doAnswer(c -> mock(DeviceConfigInterface.class)).when(mInjector).getDeviceConfig(); +        doAnswer(c -> mock(DisplayManagerInternal.class)) +                .when(mInjector).getDisplayManagerInternal(); +          mDefaultDisplay = mock(Display.class);          when(mDefaultDisplay.getDisplayId()).thenReturn(DEFAULT_DISPLAY); diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt index 230317ba738b..196a20231fbb 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SettingsObserverTest.kt @@ -19,6 +19,8 @@ package com.android.server.display.mode  import android.content.Context  import android.content.ContextWrapper  import android.provider.Settings +import android.util.SparseBooleanArray +import android.view.Display  import androidx.test.core.app.ApplicationProvider  import androidx.test.filters.SmallTest  import com.android.internal.util.test.FakeSettingsProvider @@ -39,7 +41,6 @@ import org.mockito.kotlin.whenever  @SmallTest  @RunWith(TestParameterInjector::class)  class SettingsObserverTest { -      @get:Rule      val mockitoRule = MockitoJUnit.rule() @@ -68,8 +69,11 @@ class SettingsObserverTest {          val displayModeDirector = DisplayModeDirector(                  spyContext, testHandler, mockInjector, mockFlags) +        val vrrByDisplay = SparseBooleanArray() +        vrrByDisplay.put(Display.DEFAULT_DISPLAY, testCase.vrrSupported) +        displayModeDirector.injectVrrByDisplay(vrrByDisplay)          val settingsObserver = displayModeDirector.SettingsObserver( -                spyContext, testHandler, testCase.dvrrSupported, mockFlags) +                spyContext, testHandler, mockFlags)          settingsObserver.onChange(                  false, Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE), 1) @@ -79,7 +83,7 @@ class SettingsObserverTest {      }      enum class SettingsObserverTestCase( -            val dvrrSupported: Boolean, +            val vrrSupported: Boolean,              val vsyncLowPowerVoteEnabled: Boolean,              val lowPowerModeEnabled: Boolean,              internal val expectedVote: Vote? diff --git a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java index 783971a1afe4..89b48bad2358 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java @@ -16,9 +16,18 @@  package com.android.server.am; +import static android.os.Process.INVALID_UID; +  import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;  import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;  import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_NULL; +import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_ONE_SHOT_SENT; +import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_OWNER_CANCELED; +import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_OWNER_FORCE_STOPPED; +import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_SUPERSEDED; +import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_USER_STOPPED; +import static com.android.server.am.PendingIntentRecord.cancelReasonToString;  import static org.junit.Assert.assertEquals;  import static org.mockito.ArgumentMatchers.anyInt; @@ -34,6 +43,7 @@ import android.app.PendingIntent;  import android.content.Intent;  import android.content.pm.IPackageManager;  import android.os.Looper; +import android.os.UserHandle;  import androidx.test.runner.AndroidJUnit4; @@ -54,6 +64,7 @@ public class PendingIntentControllerTest {      private static final String TEST_PACKAGE_NAME = "test-package-1";      private static final String TEST_FEATURE_ID = "test-feature-1";      private static final int TEST_CALLING_UID = android.os.Process.myUid(); +    private static final int TEST_USER_ID = 0;      private static final Intent[] TEST_INTENTS = new Intent[]{new Intent("com.test.intent")};      @Mock @@ -92,7 +103,7 @@ public class PendingIntentControllerTest {      private PendingIntentRecord createPendingIntentRecord(int flags) {          return mPendingIntentController.getIntentSender(ActivityManager.INTENT_SENDER_BROADCAST, -                TEST_PACKAGE_NAME, TEST_FEATURE_ID, TEST_CALLING_UID, 0, null, null, 0, +                TEST_PACKAGE_NAME, TEST_FEATURE_ID, TEST_CALLING_UID, TEST_USER_ID, null, null, 0,                  TEST_INTENTS, null, flags, null);      } @@ -126,6 +137,54 @@ public class PendingIntentControllerTest {                  piCaptor.getValue().getTarget());      } +    @Test +    public void testCancellationReason() { +        { +            final PendingIntentRecord pir = createPendingIntentRecord(0); +            assertCancelReason(CANCEL_REASON_NULL, pir.cancelReason); +        } + +        { +            final PendingIntentRecord pir = createPendingIntentRecord(0); +            mPendingIntentController.cancelIntentSender(pir); +            assertCancelReason(CANCEL_REASON_OWNER_CANCELED, pir.cancelReason); +        } + +        { +            final PendingIntentRecord pir = createPendingIntentRecord(0); +            createPendingIntentRecord(PendingIntent.FLAG_CANCEL_CURRENT); +            assertCancelReason(CANCEL_REASON_SUPERSEDED, pir.cancelReason); +        } + +        { +            final PendingIntentRecord pir = createPendingIntentRecord(PendingIntent.FLAG_ONE_SHOT); +            pir.send(0, null, null, null, null, null, null); +            assertCancelReason(CANCEL_REASON_ONE_SHOT_SENT, pir.cancelReason); +        } + +        { +            final PendingIntentRecord pir = createPendingIntentRecord(0); +            mPendingIntentController.removePendingIntentsForPackage(TEST_PACKAGE_NAME, +                    TEST_USER_ID, UserHandle.getAppId(TEST_CALLING_UID), true, +                    CANCEL_REASON_OWNER_FORCE_STOPPED); +            assertCancelReason(CANCEL_REASON_OWNER_FORCE_STOPPED, pir.cancelReason); +        } + +        { +            final PendingIntentRecord pir = createPendingIntentRecord(0); +            mPendingIntentController.removePendingIntentsForPackage(null, +                    TEST_USER_ID, INVALID_UID, true, +                    CANCEL_REASON_USER_STOPPED); +            assertCancelReason(CANCEL_REASON_USER_STOPPED, pir.cancelReason); +        } +    } + +    private void assertCancelReason(int expectedReason, int actualReason) { +        final String errMsg = "Expected: " + cancelReasonToString(expectedReason) +                + "; Actual: " + cancelReasonToString(actualReason); +        assertEquals(errMsg, expectedReason, actualReason); +    } +      @After      public void tearDown() {          if (mMockingSession != null) { diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java index b203cf640097..c4a042370de5 100644 --- a/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/backup/BackupManagerServiceTest.java @@ -38,7 +38,6 @@ import static org.mockito.Mockito.verify;  import static org.mockito.Mockito.when;  import android.Manifest; -import android.annotation.UserIdInt;  import android.app.backup.BackupManager;  import android.app.backup.ISelectBackupTransportCallback;  import android.app.job.JobScheduler; @@ -59,10 +58,12 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;  import androidx.test.filters.SmallTest;  import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.internal.util.DumpUtils;  import com.android.server.SystemService;  import com.android.server.backup.utils.RandomAccessFileUtils;  import org.junit.After; +import org.junit.Assert;  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith; @@ -74,6 +75,7 @@ import org.mockito.quality.Strictness;  import java.io.File;  import java.io.FileDescriptor;  import java.io.PrintWriter; +import java.io.Writer;  import java.util.concurrent.CompletableFuture;  import java.util.concurrent.TimeUnit; @@ -85,8 +87,6 @@ public class BackupManagerServiceTest {              "class");      private static final int NON_SYSTEM_USER = UserHandle.USER_SYSTEM + 1; -    @UserIdInt -    private int mUserId;      @Mock      private UserBackupManagerService mSystemUserBackupManagerService;      @Mock @@ -94,8 +94,6 @@ public class BackupManagerServiceTest {      @Mock      private Context mContextMock;      @Mock -    private PrintWriter mPrintWriterMock; -    @Mock      private UserManager mUserManagerMock;      @Mock      private UserInfo mUserInfoMock; @@ -104,6 +102,7 @@ public class BackupManagerServiceTest {      private BackupManagerServiceTestable mService;      private BackupManagerService.Lifecycle mServiceLifecycle; +    private FakePrintWriter mFakePrintWriter;      private static File sTestDir;      private MockitoSession mSession; @@ -114,6 +113,7 @@ public class BackupManagerServiceTest {                                  this)                          .strictness(Strictness.LENIENT)                          .spyStatic(UserBackupManagerService.class) +                        .spyStatic(DumpUtils.class)                          .startMocking();          doReturn(mSystemUserBackupManagerService).when(                  () -> UserBackupManagerService.createAndInitializeService( @@ -122,8 +122,7 @@ public class BackupManagerServiceTest {                  () -> UserBackupManagerService.createAndInitializeService(eq(NON_SYSTEM_USER),                          any(), any(), any())); -        mUserId = UserHandle.USER_SYSTEM; - +        when(mNonSystemUserBackupManagerService.getUserId()).thenReturn(NON_SYSTEM_USER);          when(mUserManagerMock.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(mUserInfoMock);          when(mUserManagerMock.getUserInfo(NON_SYSTEM_USER)).thenReturn(mUserInfoMock);          // Null main user means there is no main user on the device. @@ -139,6 +138,8 @@ public class BackupManagerServiceTest {          when(mContextMock.getSystemService(Context.JOB_SCHEDULER_SERVICE))                  .thenReturn(mock(JobScheduler.class)); + +        mFakePrintWriter = new FakePrintWriter();      }      @After @@ -552,7 +553,8 @@ public class BackupManagerServiceTest {                      }                  }; -        mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener); +        mService.selectBackupTransportAsyncForUser( +                UserHandle.USER_SYSTEM, TRANSPORT_COMPONENT_NAME, listener);          assertEquals(BackupManager.ERROR_BACKUP_NOT_ALLOWED, (int) future.get(5, TimeUnit.SECONDS));      } @@ -560,9 +562,10 @@ public class BackupManagerServiceTest {      @Test      public void selectBackupTransportAsyncForUser_beforeUserUnlockedWithNullListener_doesNotThrow()              throws Exception { -        createBackupManagerServiceAndUnlockSystemUser(); +        mService = new BackupManagerServiceTestable(mContextMock); -        mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null); +        mService.selectBackupTransportAsyncForUser( +                UserHandle.USER_SYSTEM, TRANSPORT_COMPONENT_NAME, null);          // No crash.      } @@ -570,13 +573,11 @@ public class BackupManagerServiceTest {      @Test      public void selectBackupTransportAsyncForUser_beforeUserUnlockedListenerThrowing_doesNotThrow()              throws Exception { -        createBackupManagerServiceAndUnlockSystemUser(); - +        mService = new BackupManagerServiceTestable(mContextMock);          ISelectBackupTransportCallback.Stub listener =                  new ISelectBackupTransportCallback.Stub() {                      @Override -                    public void onSuccess(String transportName) { -                    } +                    public void onSuccess(String transportName) {}                      @Override                      public void onFailure(int reason) throws RemoteException { @@ -584,55 +585,91 @@ public class BackupManagerServiceTest {                      }                  }; -        mService.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, listener); +        mService.selectBackupTransportAsyncForUser( +                UserHandle.USER_SYSTEM, TRANSPORT_COMPONENT_NAME, listener);          // No crash.      }      @Test -    public void dump_callerDoesNotHaveDumpPermission_ignored() { +    public void dump_callerDoesNotHaveDumpOrUsageStatsPermission_ignored() { +        mockDumpPermissionsGranted(false);          createBackupManagerServiceAndUnlockSystemUser(); -        when(mContextMock.checkCallingOrSelfPermission( -                Manifest.permission.DUMP)).thenReturn( -                PackageManager.PERMISSION_DENIED); +        when(mContextMock.checkCallingOrSelfPermission(Manifest.permission.DUMP)) +                .thenReturn(PackageManager.PERMISSION_DENIED); -        mService.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]); +        mService.dump(mFileDescriptorStub, mFakePrintWriter, new String[0]);          verify(mSystemUserBackupManagerService, never()).dump(any(), any(), any());          verify(mNonSystemUserBackupManagerService, never()).dump(any(), any(), any());      }      @Test -    public void dump_callerDoesNotHavePackageUsageStatsPermission_ignored() { +    public void dump_forOneUser_callerDoesNotHaveInteractAcrossUsersFullPermission_ignored() { +        mockDumpPermissionsGranted(true);          createBackupManagerServiceAndUnlockSystemUser(); -        when(mContextMock.checkCallingOrSelfPermission( -                Manifest.permission.PACKAGE_USAGE_STATS)).thenReturn( -                PackageManager.PERMISSION_DENIED); +        mService.setBackupServiceActive(NON_SYSTEM_USER, true); +        simulateUserUnlocked(NON_SYSTEM_USER); +        doThrow(new SecurityException()) +                .when(mContextMock) +                .enforceCallingOrSelfPermission( +                        eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), anyString()); -        mService.dump(mFileDescriptorStub, mPrintWriterMock, new String[0]); +        String[] args = new String[] {"--user", Integer.toString(NON_SYSTEM_USER)}; +        Assert.assertThrows( +                SecurityException.class, +                () -> mService.dump(mFileDescriptorStub, mFakePrintWriter, args)); +        verify(mNonSystemUserBackupManagerService, never()).dump(any(), any(), any()); +    } + +    @Test +    public void dump_forOneUser_callerHasInteractAcrossUsersFullPermission_dumpsSpecifiedUser() { +        mockDumpPermissionsGranted(true); +        createBackupManagerServiceAndUnlockSystemUser(); +        mService.setBackupServiceActive(NON_SYSTEM_USER, true); +        simulateUserUnlocked(NON_SYSTEM_USER); + +        String[] args = new String[] {"--user", Integer.toString(UserHandle.USER_SYSTEM)}; +        mService.dump(mFileDescriptorStub, mFakePrintWriter, args); + +        verify(mSystemUserBackupManagerService).dump(any(), any(), any()); +    } + +    @Test +    public void dump_users_callerHasInteractAcrossUsersFullPermission_dumpsUsers() { +        mockDumpPermissionsGranted(true); +        createBackupManagerServiceAndUnlockSystemUser(); +        mService.setBackupServiceActive(NON_SYSTEM_USER, true); +        simulateUserUnlocked(NON_SYSTEM_USER); + +        String[] args = new String[] {"users"}; +        mService.dump(mFileDescriptorStub, mFakePrintWriter, args); + +        // Check that dump() invocations are not called on user's Backup service, +        // as 'dumpsys backup users' only list users for whom Backup service is running.          verify(mSystemUserBackupManagerService, never()).dump(any(), any(), any());          verify(mNonSystemUserBackupManagerService, never()).dump(any(), any(), any()); +        assertThat(mFakePrintWriter.mPrintedSoFar) +                .isEqualTo("Backup Manager is running for users: 0 1");      } -    /** -     * Test that {@link BackupManagerService#dump(FileDescriptor, PrintWriter, String[])} dumps -     * system user information before non-system user information. -     */      @Test -    public void testDump_systemUserFirst() { +    public void dump_allUsers_dumpsSystemUserFirst() { +        mockDumpPermissionsGranted(true);          createBackupManagerServiceAndUnlockSystemUser();          mService.setBackupServiceActive(NON_SYSTEM_USER, true);          simulateUserUnlocked(NON_SYSTEM_USER); +          String[] args = new String[0]; -        mService.dumpWithoutCheckingPermission(mFileDescriptorStub, mPrintWriterMock, args); +        mService.dump(mFileDescriptorStub, mFakePrintWriter, args);          InOrder inOrder =                  inOrder(mSystemUserBackupManagerService, mNonSystemUserBackupManagerService);          inOrder.verify(mSystemUserBackupManagerService) -                .dump(mFileDescriptorStub, mPrintWriterMock, args); +                .dump(mFileDescriptorStub, mFakePrintWriter, args);          inOrder.verify(mNonSystemUserBackupManagerService) -                .dump(mFileDescriptorStub, mPrintWriterMock, args); +                .dump(mFileDescriptorStub, mFakePrintWriter, args);          inOrder.verifyNoMoreInteractions();      } @@ -753,6 +790,11 @@ public class BackupManagerServiceTest {          return new File(sTestDir, "rememberActivated-" + userId);      } +    private static void mockDumpPermissionsGranted(boolean granted) { +        doReturn(granted) +                .when(() -> DumpUtils.checkDumpAndUsageStatsPermission(any(), any(), any())); +    } +      private static class BackupManagerServiceTestable extends BackupManagerService {          static boolean sBackupDisabled = false;          static int sCallingUserId = -1; @@ -803,4 +845,17 @@ public class BackupManagerServiceTest {              runnable.run();          }      } + +    private static class FakePrintWriter extends PrintWriter { +        String mPrintedSoFar = ""; + +        FakePrintWriter() { +            super(Writer.nullWriter()); +        } + +        @Override +        public void print(String s) { +            mPrintedSoFar = mPrintedSoFar + s; +        } +    }  } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java index 671472d619d7..6df4907af93c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -1978,7 +1978,7 @@ public class QuotaControllerTest {      }      @Test -    public void testIsWithinQuotaLocked_UnderDuration_OverJobCountRateLimitWindow() { +    public void testIsWithinQuotaLocked_UnderDuration_OverJobCount() {          setDischarging();          final long now = JobSchedulerService.sElapsedRealtimeClock.millis();          final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW; @@ -2021,7 +2021,7 @@ public class QuotaControllerTest {      }      @Test -    public void testIsWithinQuotaLocked_OverDuration_OverJobCountRateLimitWindow() { +    public void testIsWithinQuotaLocked_OverDuration_OverJobCount() {          setDischarging();          final long now = JobSchedulerService.sElapsedRealtimeClock.millis();          final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW; @@ -2167,73 +2167,6 @@ public class QuotaControllerTest {      }      @Test -    public void testIsWithinQuotaLocked_UnderDuration_OverJobCountInWindow() { -        setDischarging(); - -        JobStatus jobRunning = createJobStatus( -                "testIsWithinQuotaLocked_UnderDuration_OverJobCountInWindow", 1); -        JobStatus jobPending = createJobStatus( -                "testIsWithinQuotaLocked_UnderDuration_OverJobCountInWindow", 2); -        setStandbyBucket(WORKING_INDEX, jobRunning, jobPending); - -        setDeviceConfigInt(QcConstants.KEY_MAX_JOB_COUNT_WORKING, 10); - -        long now = JobSchedulerService.sElapsedRealtimeClock.millis(); -        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, -                createTimingSession(now - (HOUR_IN_MILLIS), 5 * MINUTE_IN_MILLIS, 9), false); - -        final ExecutionStats stats; -        synchronized (mQuotaController.mLock) { -            stats = mQuotaController.getExecutionStatsLocked( -                    SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX); -            assertTrue(mQuotaController -                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX)); -            assertEquals(10, stats.jobCountLimit); -            assertEquals(9, stats.bgJobCountInWindow); -        } - -        when(mJobSchedulerService.isCurrentlyRunningLocked(jobRunning)).thenReturn(true); -        when(mJobSchedulerService.isCurrentlyRunningLocked(jobPending)).thenReturn(false); - -        InOrder inOrder = inOrder(mJobSchedulerService); -        trackJobs(jobRunning, jobPending); -        // UID in the background. -        setProcessState(ActivityManager.PROCESS_STATE_SERVICE); -        // Start the job. -        synchronized (mQuotaController.mLock) { -            mQuotaController.prepareForExecutionLocked(jobRunning); -        } - -        advanceElapsedClock(MINUTE_IN_MILLIS); -        // Wait for some extra time to allow for job processing. -        ArraySet<JobStatus> expected = new ArraySet<>(); -        expected.add(jobPending); -        inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1)) -                .onControllerStateChanged(eq(expected)); - -        synchronized (mQuotaController.mLock) { -            assertTrue(mQuotaController.isWithinQuotaLocked(jobRunning)); -            assertTrue(jobRunning.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); -            assertTrue(jobRunning.isReady()); -            assertFalse(mQuotaController.isWithinQuotaLocked(jobPending)); -            assertFalse(jobPending.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)); -            assertFalse(jobPending.isReady()); -            assertEquals(10, stats.bgJobCountInWindow); -        } - -        advanceElapsedClock(MINUTE_IN_MILLIS); -        synchronized (mQuotaController.mLock) { -            mQuotaController.maybeStopTrackingJobLocked(jobRunning, null); -        } - -        synchronized (mQuotaController.mLock) { -            assertFalse(mQuotaController -                    .isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX)); -            assertEquals(10, stats.bgJobCountInWindow); -        } -    } - -    @Test      public void testIsWithinQuotaLocked_TimingSession() {          setDischarging();          final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); @@ -4718,7 +4651,7 @@ public class QuotaControllerTest {          // Handler is told to check when the quota will be consumed, not when the initial          // remaining time is over.          verify(handler, atLeast(1)).sendMessageDelayed( -                argThat(msg -> msg.what == QuotaController.MSG_REACHED_TIME_QUOTA), +                argThat(msg -> msg.what == QuotaController.MSG_REACHED_QUOTA),                  eq(10 * SECOND_IN_MILLIS));          verify(handler, never()).sendMessageDelayed(any(), eq(remainingTimeMs)); @@ -6685,7 +6618,7 @@ public class QuotaControllerTest {          // Handler is told to check when the quota will be consumed, not when the initial          // remaining time is over.          verify(handler, atLeast(1)).sendMessageDelayed( -                argThat(msg -> msg.what == QuotaController.MSG_REACHED_EJ_TIME_QUOTA), +                argThat(msg -> msg.what == QuotaController.MSG_REACHED_EJ_QUOTA),                  eq(10 * SECOND_IN_MILLIS));          verify(handler, never()).sendMessageDelayed(any(), eq(remainingTimeMs));      } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java index 759a974bd41f..79f1574105ba 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java @@ -34,6 +34,7 @@ import static com.google.common.truth.Truth.assertWithMessage;  import static org.junit.Assert.assertThrows;  import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue;  import static org.mockito.ArgumentMatchers.anyBoolean;  import static org.mockito.ArgumentMatchers.anyInt;  import static org.mockito.ArgumentMatchers.anyLong; @@ -58,6 +59,7 @@ import android.os.SystemProperties;  import android.os.UserHandle;  import android.os.UserManager;  import android.os.storage.StorageManager; +import android.platform.test.annotations.RequiresFlagsEnabled;  import android.platform.test.flag.junit.SetFlagsRule;  import android.provider.Settings;  import android.util.Log; @@ -139,7 +141,8 @@ public final class UserManagerServiceTest {              .mockStatic(Settings.Secure.class)              .build(); -    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); +    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule( +            SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);      private final Object mPackagesLock = new Object();      private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation() @@ -584,10 +587,12 @@ public final class UserManagerServiceTest {      public void testAutoLockPrivateProfile() {          mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,                  android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); +        int mainUser = mUms.getMainUserId(); +        assumeTrue(mUms.canAddPrivateProfile(mainUser));          UserManagerService mSpiedUms = spy(mUms);          UserInfo privateProfileUser =                  mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME, -                        USER_TYPE_PROFILE_PRIVATE, 0, 0, null); +                        USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);          Mockito.doNothing().when(mSpiedUms).setQuietModeEnabledAsync(                  eq(privateProfileUser.getUserHandle().getIdentifier()), eq(true), any(),                  any()); @@ -604,10 +609,12 @@ public final class UserManagerServiceTest {          mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,                  android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);          mSetFlagsRule.enableFlags(Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); +        int mainUser = mUms.getMainUserId(); +        assumeTrue(mUms.canAddPrivateProfile(mainUser));          UserManagerService mSpiedUms = spy(mUms);          UserInfo privateProfileUser =                  mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME, -                USER_TYPE_PROFILE_PRIVATE, 0, 0, null); +                USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);          mockAutoLockForPrivateSpace(Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK);          Mockito.doNothing().when(mSpiedUms).setQuietModeEnabledAsync(                  eq(privateProfileUser.getUserHandle().getIdentifier()), eq(true), any(), @@ -625,6 +632,7 @@ public final class UserManagerServiceTest {          mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,                  android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);          mSetFlagsRule.enableFlags(Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); +        assumeTrue(mUms.canAddPrivateProfile(0));          UserManagerService mSpiedUms = spy(mUms);          UserInfo privateProfileUser =                  mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME, @@ -644,10 +652,12 @@ public final class UserManagerServiceTest {          mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,                  android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);          mSetFlagsRule.disableFlags(Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); +        int mainUser = mUms.getMainUserId(); +        assumeTrue(mUms.canAddPrivateProfile(mainUser));          UserManagerService mSpiedUms = spy(mUms);          UserInfo privateProfileUser =                  mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME, -                USER_TYPE_PROFILE_PRIVATE, 0, 0, null); +                USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);          mSpiedUms.tryAutoLockingPrivateSpaceOnKeyguardChanged(true); @@ -664,13 +674,15 @@ public final class UserManagerServiceTest {          mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,                  android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);          mSetFlagsRule.enableFlags(Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); +        int mainUser = mUms.getMainUserId(); +        assumeTrue(mUms.canAddPrivateProfile(mainUser));          UserManagerService mSpiedUms = spy(mUms);          mockAutoLockForPrivateSpace(Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY);          when(mPowerManager.isInteractive()).thenReturn(false);          UserInfo privateProfileUser =                  mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME, -                        USER_TYPE_PROFILE_PRIVATE, 0, 0, null); +                        USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);          Mockito.doNothing().when(mSpiedUms).scheduleMessageToAutoLockPrivateSpace(                  eq(privateProfileUser.getUserHandle().getIdentifier()), any(),                  anyLong()); @@ -702,8 +714,10 @@ public final class UserManagerServiceTest {          mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,                  android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);          mSetFlagsRule.enableFlags(Flags.FLAG_SUPPORT_AUTOLOCK_FOR_PRIVATE_SPACE); +        int mainUser = mUms.getMainUserId(); +        assumeTrue(mUms.canAddPrivateProfile(mainUser));          mUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME, -                        USER_TYPE_PROFILE_PRIVATE, 0, 0, null); +                        USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null);          // Set the preference to auto lock on device lock          mUms.setOrUpdateAutoLockPreferenceForPrivateProfile( @@ -754,6 +768,7 @@ public final class UserManagerServiceTest {          mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE,                  android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);          mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_HIDING_PROFILES); +        assumeTrue(mUms.canAddPrivateProfile(0));          UserInfo privateProfileUser =                  mUms.createProfileForUserEvenWhenDisallowedWithThrow("TestPrivateProfile",                          USER_TYPE_PROFILE_PRIVATE, 0, 0, null); @@ -763,23 +778,23 @@ public final class UserManagerServiceTest {      }      @Test +    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, +            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})      public void testCreatePrivateProfileOnHeadlessSystemUser_shouldAllowCreation() { -        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, -                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); -        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION);          UserManagerService mSpiedUms = spy(mUms); +        assumeTrue(mUms.isHeadlessSystemUserMode());          int mainUser = mSpiedUms.getMainUserId(); -        doReturn(true).when(mSpiedUms).isHeadlessSystemUserMode(); -        assertThat(mSpiedUms.canAddPrivateProfile(mainUser)).isTrue(); +        // Check whether private space creation is blocked on the device +        assumeTrue(mSpiedUms.canAddPrivateProfile(mainUser));          assertThat(mSpiedUms.createProfileForUserEvenWhenDisallowedWithThrow(                  PRIVATE_PROFILE_NAME, USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null)).isNotNull();      }      @Test +    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, +            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})      public void testCreatePrivateProfileOnSecondaryUser_shouldNotAllowCreation() { -        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, -                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); -        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION); +        assumeTrue(mUms.canAddMoreUsersOfType(USER_TYPE_FULL_SECONDARY));          UserInfo user = mUms.createUserWithThrow(generateLongString(), USER_TYPE_FULL_SECONDARY, 0);          assertThat(mUms.canAddPrivateProfile(user.id)).isFalse();          assertThrows(ServiceSpecificException.class, @@ -788,52 +803,48 @@ public final class UserManagerServiceTest {      }      @Test +    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, +            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})      public void testCreatePrivateProfileOnAutoDevices_shouldNotAllowCreation() { -        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, -                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); -        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION);          doReturn(true).when(mMockPms).hasSystemFeature(eq(FEATURE_AUTOMOTIVE), anyInt());          int mainUser = mUms.getMainUserId(); -        assertThat(mUms.canAddPrivateProfile(0)).isFalse(); +        assertThat(mUms.canAddPrivateProfile(mainUser)).isFalse();          assertThrows(ServiceSpecificException.class,                  () -> mUms.createProfileForUserWithThrow(PRIVATE_PROFILE_NAME,                          USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null));      }      @Test +    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, +            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})      public void testCreatePrivateProfileOnTV_shouldNotAllowCreation() { -        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, -                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); -        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION);          doReturn(true).when(mMockPms).hasSystemFeature(eq(FEATURE_LEANBACK), anyInt());          int mainUser = mUms.getMainUserId(); -        assertThat(mUms.canAddPrivateProfile(0)).isFalse(); +        assertThat(mUms.canAddPrivateProfile(mainUser)).isFalse();          assertThrows(ServiceSpecificException.class,                  () -> mUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,                          USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null));      }      @Test +    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, +            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})      public void testCreatePrivateProfileOnEmbedded_shouldNotAllowCreation() { -        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, -                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); -        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION);          doReturn(true).when(mMockPms).hasSystemFeature(eq(FEATURE_EMBEDDED), anyInt());          int mainUser = mUms.getMainUserId(); -        assertThat(mUms.canAddPrivateProfile(0)).isFalse(); +        assertThat(mUms.canAddPrivateProfile(mainUser)).isFalse();          assertThrows(ServiceSpecificException.class,                  () -> mUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,                          USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null));      }      @Test +    @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, +            Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES})      public void testCreatePrivateProfileOnWatch_shouldNotAllowCreation() { -        mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, -                android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); -        mSetFlagsRule.enableFlags(Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION);          doReturn(true).when(mMockPms).hasSystemFeature(eq(FEATURE_WATCH), anyInt());          int mainUser = mUms.getMainUserId(); -        assertThat(mUms.canAddPrivateProfile(0)).isFalse(); +        assertThat(mUms.canAddPrivateProfile(mainUser)).isFalse();          assertThrows(ServiceSpecificException.class,                  () -> mUms.createProfileForUserEvenWhenDisallowedWithThrow(PRIVATE_PROFILE_NAME,                          USER_TYPE_PROFILE_PRIVATE, 0, mainUser, null)); diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp index 51c9d0ae5e5d..f2b4136c51ed 100644 --- a/services/tests/powerstatstests/Android.bp +++ b/services/tests/powerstatstests/Android.bp @@ -4,58 +4,6 @@ package {      default_applicable_licenses: ["frameworks_base_license"],  } -filegroup { -    name: "power_stats_ravenwood_tests", -    srcs: [ -        "src/com/android/server/power/stats/AggregatedPowerStatsProcessorTest.java", -        "src/com/android/server/power/stats/AggregatedPowerStatsTest.java", -        "src/com/android/server/power/stats/AmbientDisplayPowerCalculatorTest.java", -        "src/com/android/server/power/stats/AudioPowerCalculatorTest.java", -        "src/com/android/server/power/stats/BatteryChargeCalculatorTest.java", -        "src/com/android/server/power/stats/BatteryStatsCounterTest.java", -        "src/com/android/server/power/stats/BatteryStatsCpuTimesTest.java", -        "src/com/android/server/power/stats/BatteryStatsDualTimerTest.java", -        "src/com/android/server/power/stats/BatteryStatsDurationTimerTest.java", -        "src/com/android/server/power/stats/BatteryStatsHistoryIteratorTest.java", -        "src/com/android/server/power/stats/BatteryStatsHistoryTest.java", -        "src/com/android/server/power/stats/BatteryStatsImplTest.java", -        "src/com/android/server/power/stats/BatteryStatsNoteTest.java", -        "src/com/android/server/power/stats/BatteryStatsSamplingTimerTest.java", -        "src/com/android/server/power/stats/BatteryStatsSensorTest.java", -        "src/com/android/server/power/stats/BatteryStatsServTest.java", -        "src/com/android/server/power/stats/BatteryStatsStopwatchTimerTest.java", -        "src/com/android/server/power/stats/BatteryStatsTimeBaseTest.java", -        "src/com/android/server/power/stats/BatteryStatsTimerTest.java", -        "src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java", -        "src/com/android/server/power/stats/BatteryUsageStatsTest.java", -        "src/com/android/server/power/stats/BluetoothPowerCalculatorTest.java", -        "src/com/android/server/power/stats/CameraPowerCalculatorTest.java", -        "src/com/android/server/power/stats/CpuAggregatedPowerStatsProcessorTest.java", -        "src/com/android/server/power/stats/CpuPowerCalculatorTest.java", -        "src/com/android/server/power/stats/CustomEnergyConsumerPowerCalculatorTest.java", -        "src/com/android/server/power/stats/EnergyConsumerSnapshotTest.java", -        "src/com/android/server/power/stats/FlashlightPowerCalculatorTest.java", -        "src/com/android/server/power/stats/GnssPowerCalculatorTest.java", -        "src/com/android/server/power/stats/IdlePowerCalculatorTest.java", -        "src/com/android/server/power/stats/LongSamplingCounterArrayTest.java", -        "src/com/android/server/power/stats/LongSamplingCounterTest.java", -        "src/com/android/server/power/stats/MemoryPowerCalculatorTest.java", -        "src/com/android/server/power/stats/MultiStateStatsTest.java", -        "src/com/android/server/power/stats/PowerStatsAggregatorTest.java", -        "src/com/android/server/power/stats/PowerStatsCollectorTest.java", -        "src/com/android/server/power/stats/PowerStatsExporterTest.java", -        "src/com/android/server/power/stats/PowerStatsSchedulerTest.java", -        "src/com/android/server/power/stats/PowerStatsStoreTest.java", -        "src/com/android/server/power/stats/PowerStatsUidResolverTest.java", -        "src/com/android/server/power/stats/ScreenPowerCalculatorTest.java", -        "src/com/android/server/power/stats/SensorPowerCalculatorTest.java", -        "src/com/android/server/power/stats/UserPowerCalculatorTest.java", -        "src/com/android/server/power/stats/VideoPowerCalculatorTest.java", -        "src/com/android/server/power/stats/WakelockPowerCalculatorTest.java", -        "src/com/android/server/power/stats/WifiPowerCalculatorTest.java", -    ], -} -  android_test {      name: "PowerStatsTests", @@ -79,7 +27,6 @@ android_test {          "servicestests-utils",          "platform-test-annotations",          "flag-junit", -        "ravenwood-junit",      ],      libs: [ @@ -112,17 +59,20 @@ android_ravenwood_test {      name: "PowerStatsTestsRavenwood",      static_libs: [          "services.core", -        "modules-utils-binary-xml", +        "coretests-aidl", +        "ravenwood-junit", +        "truth",          "androidx.annotation_annotation",          "androidx.test.rules", -        "truth", +        "androidx.test.uiautomator_uiautomator", +        "modules-utils-binary-xml", +        "flag-junit",      ],      srcs: [ -        ":power_stats_ravenwood_tests", - -        "src/com/android/server/power/stats/BatteryUsageStatsRule.java", -        "src/com/android/server/power/stats/MockBatteryStatsImpl.java", -        "src/com/android/server/power/stats/MockClock.java", +        "src/com/android/server/power/stats/*.java", +    ], +    java_resources: [ +        "res/xml/power_profile*.xml",      ],      auto_gen_config: true,  } diff --git a/services/tests/powerstatstests/TEST_MAPPING b/services/tests/powerstatstests/TEST_MAPPING index 6d3db1cb6c23..fb243616292d 100644 --- a/services/tests/powerstatstests/TEST_MAPPING +++ b/services/tests/powerstatstests/TEST_MAPPING @@ -12,7 +12,11 @@    "ravenwood-presubmit": [      {        "name": "PowerStatsTestsRavenwood", -      "host": true +      "host": true, +      "options": [ +        {"include-filter": "com.android.server.power.stats"}, +        {"exclude-annotation": "android.platform.test.annotations.DisabledOnRavenwood"} +      ]      }    ],    "postsubmit": [ diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsTest.java index ca7de7c3f325..9975190424b5 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;  import android.os.BatteryConsumer;  import android.os.PersistableBundle; +import android.util.SparseArray;  import android.util.Xml;  import androidx.test.filters.SmallTest; @@ -43,6 +44,9 @@ public class AggregatedPowerStatsTest {      private static final int TEST_POWER_COMPONENT = 1077;      private static final int APP_1 = 27;      private static final int APP_2 = 42; +    private static final int COMPONENT_STATE_0 = 0; +    private static final int COMPONENT_STATE_1 = 1; +    private static final int COMPONENT_STATE_2 = 2;      private AggregatedPowerStatsConfig mAggregatedPowerStatsConfig;      private PowerStats.Descriptor mPowerComponentDescriptor; @@ -59,8 +63,10 @@ public class AggregatedPowerStatsTest {                          AggregatedPowerStatsConfig.STATE_SCREEN,                          AggregatedPowerStatsConfig.STATE_PROCESS_STATE); -        mPowerComponentDescriptor = new PowerStats.Descriptor(TEST_POWER_COMPONENT, "fan", 2, 3, -                PersistableBundle.forPair("speed", "fast")); +        SparseArray<String> stateLabels = new SparseArray<>(); +        stateLabels.put(COMPONENT_STATE_1, "one"); +        mPowerComponentDescriptor = new PowerStats.Descriptor(TEST_POWER_COMPONENT, "fan", 2, +                stateLabels, 1, 3, PersistableBundle.forPair("speed", "fast"));      }      @Test @@ -107,6 +113,9 @@ public class AggregatedPowerStatsTest {          ps.stats[0] = 100;          ps.stats[1] = 987; +        ps.stateStats.put(COMPONENT_STATE_0, new long[]{1111}); +        ps.stateStats.put(COMPONENT_STATE_1, new long[]{5000}); +          ps.uidStats.put(APP_1, new long[]{389, 0, 739});          ps.uidStats.put(APP_2, new long[]{278, 314, 628}); @@ -120,11 +129,14 @@ public class AggregatedPowerStatsTest {          ps.stats[0] = 444;          ps.stats[1] = 0; +        ps.stateStats.clear(); +        ps.stateStats.put(COMPONENT_STATE_1, new long[]{1000}); +        ps.stateStats.put(COMPONENT_STATE_2, new long[]{9000}); +          ps.uidStats.put(APP_1, new long[]{0, 0, 400});          ps.uidStats.put(APP_2, new long[]{100, 200, 300});          stats.addPowerStats(ps, 5000); -          return stats;      } @@ -147,6 +159,31 @@ public class AggregatedPowerStatsTest {                  AggregatedPowerStatsConfig.SCREEN_STATE_OTHER))                  .isEqualTo(new long[]{222, 0}); +        assertThat(getStateStats(stats, COMPONENT_STATE_0, +                AggregatedPowerStatsConfig.POWER_STATE_BATTERY, +                AggregatedPowerStatsConfig.SCREEN_STATE_ON)) +                .isEqualTo(new long[]{1111}); + +        assertThat(getStateStats(stats, COMPONENT_STATE_1, +                AggregatedPowerStatsConfig.POWER_STATE_BATTERY, +                AggregatedPowerStatsConfig.SCREEN_STATE_ON)) +                .isEqualTo(new long[]{5500}); + +        assertThat(getStateStats(stats, COMPONENT_STATE_1, +                AggregatedPowerStatsConfig.POWER_STATE_BATTERY, +                AggregatedPowerStatsConfig.SCREEN_STATE_OTHER)) +                .isEqualTo(new long[]{500}); + +        assertThat(getStateStats(stats, COMPONENT_STATE_2, +                AggregatedPowerStatsConfig.POWER_STATE_BATTERY, +                AggregatedPowerStatsConfig.SCREEN_STATE_ON)) +                .isEqualTo(new long[]{4500}); + +        assertThat(getStateStats(stats, COMPONENT_STATE_2, +                AggregatedPowerStatsConfig.POWER_STATE_BATTERY, +                AggregatedPowerStatsConfig.SCREEN_STATE_OTHER)) +                .isEqualTo(new long[]{4500}); +          assertThat(getUidDeviceStats(stats,                  APP_1,                  AggregatedPowerStatsConfig.POWER_STATE_BATTERY, @@ -191,14 +228,26 @@ public class AggregatedPowerStatsTest {      }      private static long[] getDeviceStats(AggregatedPowerStats stats, int... states) { -        long[] out = new long[states.length]; -        stats.getPowerComponentStats(TEST_POWER_COMPONENT).getDeviceStats(out, states); +        PowerComponentAggregatedPowerStats powerComponentStats = +                stats.getPowerComponentStats(TEST_POWER_COMPONENT); +        long[] out = new long[powerComponentStats.getPowerStatsDescriptor().statsArrayLength]; +        powerComponentStats.getDeviceStats(out, states); +        return out; +    } + +    private static long[] getStateStats(AggregatedPowerStats stats, int key, int... states) { +        PowerComponentAggregatedPowerStats powerComponentStats = +                stats.getPowerComponentStats(TEST_POWER_COMPONENT); +        long[] out = new long[powerComponentStats.getPowerStatsDescriptor().stateStatsArrayLength]; +        powerComponentStats.getStateStats(out, key, states);          return out;      }      private static long[] getUidDeviceStats(AggregatedPowerStats stats, int uid, int... states) { -        long[] out = new long[states.length]; -        stats.getPowerComponentStats(TEST_POWER_COMPONENT).getUidStats(out, uid, states); +        PowerComponentAggregatedPowerStats powerComponentStats = +                stats.getPowerComponentStats(TEST_POWER_COMPONENT); +        long[] out = new long[powerComponentStats.getPowerStatsDescriptor().uidStatsArrayLength]; +        powerComponentStats.getUidStats(out, uid, states);          return out;      }  } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java index 3ab1c2eab6ca..9b45ca79fdab 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java @@ -16,9 +16,11 @@  package com.android.server.power.stats; -  import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; + +import android.content.Context;  import android.os.BatteryManager;  import android.os.BatteryUsageStats;  import android.platform.test.ravenwood.RavenwoodRule; @@ -28,6 +30,7 @@ import androidx.test.runner.AndroidJUnit4;  import com.android.internal.os.PowerProfile; +import org.junit.Before;  import org.junit.Rule;  import org.junit.Test;  import org.junit.runner.RunWith; @@ -46,6 +49,11 @@ public class BatteryChargeCalculatorTest {      public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()                      .setAveragePower(PowerProfile.POWER_BATTERY_CAPACITY, 4000.0); +    @Before +    public void setup() { +        mStatsRule.getBatteryStats().onSystemReady(mock(Context.class)); +    } +      @Test      public void testDischargeTotals() {          // Nominal battery capacity should be ignored diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java index 997b7712a9dd..bbab0eef49cb 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryExternalStatsWorkerTest.java @@ -36,6 +36,9 @@ import android.hardware.power.stats.EnergyConsumerType;  import android.hardware.power.stats.EnergyMeasurement;  import android.hardware.power.stats.PowerEntity;  import android.hardware.power.stats.StateResidencyResult; +import android.os.Handler; +import android.os.Looper; +import android.platform.test.ravenwood.RavenwoodRule;  import android.power.PowerStatsInternal;  import android.util.IntArray;  import android.util.SparseArray; @@ -44,9 +47,11 @@ import androidx.test.InstrumentationRegistry;  import com.android.internal.os.Clock;  import com.android.internal.os.CpuScalingPolicies; +import com.android.internal.os.MonotonicClock;  import com.android.internal.os.PowerProfile;  import org.junit.Before; +import org.junit.Rule;  import org.junit.Test;  import java.util.Arrays; @@ -59,19 +64,27 @@ import java.util.concurrent.CompletableFuture;   * atest FrameworksServicesTests:BatteryExternalStatsWorkerTest   */  @SuppressWarnings("GuardedBy") +@android.platform.test.annotations.DisabledOnRavenwood  public class BatteryExternalStatsWorkerTest { +    @Rule +    public final RavenwoodRule mRavenwood = new RavenwoodRule(); +      private BatteryExternalStatsWorker mBatteryExternalStatsWorker; -    private TestBatteryStatsImpl mBatteryStatsImpl;      private TestPowerStatsInternal mPowerStatsInternal;      @Before      public void setUp() {          final Context context = InstrumentationRegistry.getContext(); -        mBatteryStatsImpl = new TestBatteryStatsImpl(context); +        BatteryStatsImpl batteryStats = new BatteryStatsImpl( +                new BatteryStatsImpl.BatteryStatsConfig.Builder().build(), Clock.SYSTEM_CLOCK, +                new MonotonicClock(0, Clock.SYSTEM_CLOCK), null, +                new Handler(Looper.getMainLooper()), null, null, null, +                new PowerProfile(context, true /* forTest */), buildScalingPolicies(), +                new PowerStatsUidResolver());          mPowerStatsInternal = new TestPowerStatsInternal(); -        mBatteryExternalStatsWorker = new BatteryExternalStatsWorker(new TestInjector(context), -                mBatteryStatsImpl); +        mBatteryExternalStatsWorker = +                new BatteryExternalStatsWorker(new TestInjector(context), batteryStats);      }      @Test @@ -213,24 +226,17 @@ public class BatteryExternalStatsWorkerTest {          }      } -    public class TestBatteryStatsImpl extends BatteryStatsImpl { -        public TestBatteryStatsImpl(Context context) { -            super(Clock.SYSTEM_CLOCK, null, null, null, null, null, null); -            mPowerProfile = new PowerProfile(context, true /* forTest */); - -            SparseArray<int[]> cpusByPolicy = new SparseArray<>(); -            cpusByPolicy.put(0, new int[]{0, 1, 2, 3}); -            cpusByPolicy.put(4, new int[]{4, 5, 6, 7}); -            SparseArray<int[]> freqsByPolicy = new SparseArray<>(); -            freqsByPolicy.put(0, new int[]{300000, 1000000, 2000000}); -            freqsByPolicy.put(4, new int[]{300000, 1000000, 2500000, 3000000}); -            mCpuScalingPolicies = new CpuScalingPolicies(freqsByPolicy, freqsByPolicy); - -            initTimersAndCounters(); -        } +    private static CpuScalingPolicies buildScalingPolicies() { +        SparseArray<int[]> cpusByPolicy = new SparseArray<>(); +        cpusByPolicy.put(0, new int[]{0, 1, 2, 3}); +        cpusByPolicy.put(4, new int[]{4, 5, 6, 7}); +        SparseArray<int[]> freqsByPolicy = new SparseArray<>(); +        freqsByPolicy.put(0, new int[]{300000, 1000000, 2000000}); +        freqsByPolicy.put(4, new int[]{300000, 1000000, 2500000, 3000000}); +        return new CpuScalingPolicies(freqsByPolicy, freqsByPolicy);      } -    public class TestPowerStatsInternal extends PowerStatsInternal { +    private static class TestPowerStatsInternal extends PowerStatsInternal {          private final SparseArray<EnergyConsumer> mEnergyConsumers = new SparseArray();          private final SparseArray<EnergyConsumerResult> mEnergyConsumerResults = new SparseArray();          private final int mTimeSinceBoot = 0; diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBackgroundStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBackgroundStatsTest.java index 4d3fcb611f24..ad05b5124955 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBackgroundStatsTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBackgroundStatsTest.java @@ -18,25 +18,37 @@ package com.android.server.power.stats;  import static android.os.BatteryStats.STATS_SINCE_CHARGED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +  import android.app.ActivityManager;  import android.os.BatteryStats;  import android.os.WorkSource; +import android.platform.test.ravenwood.RavenwoodRule;  import android.util.ArrayMap;  import android.view.Display;  import androidx.test.filters.SmallTest; -import junit.framework.TestCase; +import org.junit.Rule; +import org.junit.Test;  /**   * Test BatteryStatsImpl onBatteryBackgroundTimeBase TimeBase.   */ -public class BatteryStatsBackgroundStatsTest extends TestCase { +public class BatteryStatsBackgroundStatsTest { + +    @Rule(order = 0) +    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder() +            .setProvideMainThread(true) +            .build();      private static final int UID = 10500;      /** Test that BatteryStatsImpl.Uid.mOnBatteryBackgroundTimeBase works correctly. */      @SmallTest +    @Test      public void testBgTimeBase() throws Exception {          final MockClock clocks = new MockClock(); // holds realtime and uptime in ms          MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); @@ -105,6 +117,7 @@ public class BatteryStatsBackgroundStatsTest extends TestCase {      /** Test that BatteryStatsImpl.Uid.mOnBatteryScreenOffBackgroundTimeBase works correctly. */      @SmallTest +    @Test      public void testScreenOffBgTimeBase() throws Exception {          final MockClock clocks = new MockClock(); // holds realtime and uptime in ms          MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); @@ -153,6 +166,7 @@ public class BatteryStatsBackgroundStatsTest extends TestCase {      }      @SmallTest +    @Test      public void testWifiScan() throws Exception {          final MockClock clocks = new MockClock();          MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); @@ -195,11 +209,13 @@ public class BatteryStatsBackgroundStatsTest extends TestCase {      }      @SmallTest +    @Test      public void testAppBluetoothScan() throws Exception {          doTestAppBluetoothScanInternal(new WorkSource(UID));      }      @SmallTest +    @Test      public void testAppBluetoothScan_workChain() throws Exception {          WorkSource ws = new WorkSource();          ws.createWorkChain().addNode(UID, "foo"); @@ -275,6 +291,7 @@ public class BatteryStatsBackgroundStatsTest extends TestCase {      }      @SmallTest +    @Test      public void testJob() throws Exception {          final MockClock clocks = new MockClock();          MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); @@ -336,6 +353,7 @@ public class BatteryStatsBackgroundStatsTest extends TestCase {      }      @SmallTest +    @Test      public void testSyncs() throws Exception {          final MockClock clocks = new MockClock();          MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks); diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBinderCallStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBinderCallStatsTest.java index 3f101a96d36c..4dfc3fcec916 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBinderCallStatsTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsBinderCallStatsTest.java @@ -16,20 +16,20 @@  package com.android.server.power.stats; +import static org.junit.Assert.assertEquals; +  import android.os.Binder;  import android.os.Process; +import android.platform.test.ravenwood.RavenwoodRule;  import android.util.ArraySet;  import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4;  import com.android.internal.os.BinderCallsStats;  import com.android.internal.os.BinderTransactionNameResolver; -import junit.framework.TestCase; - +import org.junit.Rule;  import org.junit.Test; -import org.junit.runner.RunWith;  import java.util.ArrayList;  import java.util.Collection; @@ -37,9 +37,14 @@ import java.util.Collection;  /**   * Test cases for android.os.BatteryStats, system server Binder call stats.   */ -@RunWith(AndroidJUnit4.class)  @SmallTest -public class BatteryStatsBinderCallStatsTest extends TestCase { +@android.platform.test.annotations.DisabledOnRavenwood(blockedBy = BinderCallsStats.class) +public class BatteryStatsBinderCallStatsTest { + +    @Rule +    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder() +            .setProvideMainThread(true) +            .build();      private static final int TRANSACTION_CODE1 = 100;      private static final int TRANSACTION_CODE2 = 101; @@ -89,7 +94,6 @@ public class BatteryStatsBinderCallStatsTest extends TestCase {          assertEquals(500, value.recordedCpuTimeMicros);      } -      @Test      public void testProportionalSystemServiceUsage_noStatsForSomeMethods() throws Exception {          final MockClock clocks = new MockClock(); // holds realtime and uptime in ms diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsCpuTimesTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsCpuTimesTest.java index 6e62147ac6c1..eff1b7b852d9 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsCpuTimesTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsCpuTimesTest.java @@ -118,7 +118,8 @@ public class BatteryStatsCpuTimesTest {          mClocks = new MockClock();          Handler handler = new Handler(Looper.getMainLooper());          mPowerStatsUidResolver = new PowerStatsUidResolver(); -        mBatteryStatsImpl = new MockBatteryStatsImpl(mClocks, null, handler, mPowerStatsUidResolver) +        mBatteryStatsImpl = new MockBatteryStatsImpl(MockBatteryStatsImpl.DEFAULT_CONFIG, +                mClocks, null, handler, mPowerStatsUidResolver)                  .setTestCpuScalingPolicies()                  .setKernelCpuUidUserSysTimeReader(mCpuUidUserSysTimeReader)                  .setKernelCpuUidFreqTimeReader(mCpuUidFreqTimeReader) diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java index c58c92b47dd3..e40a3e314e58 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java @@ -403,7 +403,7 @@ public class BatteryStatsHistoryTest {      @Test      public void recordPowerStats() { -        PowerStats.Descriptor descriptor = new PowerStats.Descriptor(42, "foo", 1, 2, +        PowerStats.Descriptor descriptor = new PowerStats.Descriptor(42, "foo", 1, null, 0, 2,                  new PersistableBundle());          PowerStats powerStats = new PowerStats(descriptor);          powerStats.durationMs = 100; diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsManagerTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsManagerTest.java index 7ae111711b6b..9a64ce19254b 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsManagerTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsManagerTest.java @@ -25,15 +25,21 @@ import android.os.BatteryStatsManager;  import android.os.BatteryUsageStats;  import android.os.BatteryUsageStatsQuery;  import android.os.UidBatteryConsumer; +import android.platform.test.ravenwood.RavenwoodRule; +import org.junit.Rule;  import org.junit.Test;  /**   * Test BatteryStatsManager and CellularBatteryStats to ensure that valid data is being reported   * and that invalid data is not reported.   */ +@android.platform.test.annotations.DisabledOnRavenwood(reason = "Integration test")  public class BatteryStatsManagerTest { +    @Rule +    public final RavenwoodRule mRavenwood = new RavenwoodRule(); +      @Test      public void testBatteryUsageStatsDataConsistency() {          BatteryStatsManager bsm = getContext().getSystemService(BatteryStatsManager.class); diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java index 07cefa9ae878..afbe9159b66a 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsNoteTest.java @@ -170,8 +170,8 @@ public class BatteryStatsNoteTest {      public void testNoteStartWakeLocked_isolatedUid() throws Exception {          final MockClock clocks = new MockClock(); // holds realtime and uptime in ms          PowerStatsUidResolver uidResolver = new PowerStatsUidResolver(); -        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks, null, -                new Handler(Looper.getMainLooper()), uidResolver); +        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(MockBatteryStatsImpl.DEFAULT_CONFIG, +                clocks, null, new Handler(Looper.getMainLooper()), uidResolver);          int pid = 10;          String name = "name"; @@ -212,8 +212,8 @@ public class BatteryStatsNoteTest {      public void testNoteStartWakeLocked_isolatedUidRace() throws Exception {          final MockClock clocks = new MockClock(); // holds realtime and uptime in ms          PowerStatsUidResolver uidResolver = new PowerStatsUidResolver(); -        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks, null, -                new Handler(Looper.getMainLooper()), uidResolver); +        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(MockBatteryStatsImpl.DEFAULT_CONFIG, +                clocks, null, new Handler(Looper.getMainLooper()), uidResolver);          int pid = 10;          String name = "name"; @@ -256,8 +256,8 @@ public class BatteryStatsNoteTest {      public void testNoteLongPartialWakelockStart_isolatedUid() throws Exception {          final MockClock clocks = new MockClock(); // holds realtime and uptime in ms          PowerStatsUidResolver uidResolver = new PowerStatsUidResolver(); -        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks, null, -                new Handler(Looper.getMainLooper()), uidResolver); +        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(MockBatteryStatsImpl.DEFAULT_CONFIG, +                clocks, null, new Handler(Looper.getMainLooper()), uidResolver);          bi.setRecordAllHistoryLocked(true);          bi.forceRecordAllHistory(); @@ -311,8 +311,8 @@ public class BatteryStatsNoteTest {      public void testNoteLongPartialWakelockStart_isolatedUidRace() throws Exception {          final MockClock clocks = new MockClock(); // holds realtime and uptime in ms          PowerStatsUidResolver uidResolver = new PowerStatsUidResolver(); -        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks, null, -                new Handler(Looper.getMainLooper()), uidResolver); +        MockBatteryStatsImpl bi = new MockBatteryStatsImpl(MockBatteryStatsImpl.DEFAULT_CONFIG, +                clocks, null, new Handler(Looper.getMainLooper()), uidResolver);          bi.setRecordAllHistoryLocked(true);          bi.forceRecordAllHistory(); diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java index a0fb631812f4..d29bf1abd7a3 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsResetTest.java @@ -18,21 +18,32 @@ package com.android.server.power.stats;  import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +  import android.content.Context;  import android.os.BatteryManager; +import android.platform.test.ravenwood.RavenwoodRule; -import androidx.test.InstrumentationRegistry;  import androidx.test.filters.SmallTest;  import androidx.test.runner.AndroidJUnit4;  import org.junit.Before; +import org.junit.Rule;  import org.junit.Test;  import org.junit.runner.RunWith; +import java.io.IOException; +import java.nio.file.Files; +  @SmallTest  @RunWith(AndroidJUnit4.class)  public class BatteryStatsResetTest { +    @Rule(order = 0) +    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder() +            .setProvideMainThread(true) +            .build(); +      private static final int BATTERY_NOMINAL_VOLTAGE_MV = 3700;      private static final int BATTERY_CAPACITY_UAH = 4_000_000;      private static final int BATTERY_CHARGE_RATE_SECONDS_PER_LEVEL = 100; @@ -79,13 +90,11 @@ public class BatteryStatsResetTest {      private long mBatteryChargeTimeToFullSeconds;      @Before -    public void setUp() { -        final Context context = InstrumentationRegistry.getContext(); - +    public void setUp() throws IOException {          mMockClock = new MockClock(); -        mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock, context.getFilesDir()); -        mBatteryStatsImpl.onSystemReady(); - +        mBatteryStatsImpl = new MockBatteryStatsImpl(mMockClock, +                Files.createTempDirectory("BatteryStatsResetTest").toFile()); +        mBatteryStatsImpl.onSystemReady(mock(Context.class));          // Set up the battery state. Start off with a fully charged plugged in battery.          mBatteryStatus = BatteryManager.BATTERY_STATUS_FULL; diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java index c4561b16d73c..3931201aaf03 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsUserLifecycleTests.java @@ -28,6 +28,7 @@ import android.content.pm.UserInfo;  import android.os.RemoteException;  import android.os.UserHandle;  import android.os.UserManager; +import android.platform.test.ravenwood.RavenwoodRule;  import android.util.ArraySet;  import androidx.test.InstrumentationRegistry; @@ -38,6 +39,7 @@ import androidx.test.uiautomator.UiDevice;  import org.junit.After;  import org.junit.Before;  import org.junit.BeforeClass; +import org.junit.Rule;  import org.junit.Test;  import org.junit.runner.RunWith; @@ -46,8 +48,10 @@ import java.util.concurrent.TimeUnit;  @LargeTest  @RunWith(AndroidJUnit4.class) -@android.platform.test.annotations.IgnoreUnderRavenwood +@android.platform.test.annotations.DisabledOnRavenwood(reason = "Integration test")  public class BatteryStatsUserLifecycleTests { +    @Rule +    public final RavenwoodRule mRavenwood = new RavenwoodRule();      private static final long POLL_INTERVAL_MS = 500;      private static final long USER_REMOVE_TIMEOUT_MS = 5_000; @@ -65,6 +69,10 @@ public class BatteryStatsUserLifecycleTests {      @BeforeClass      public static void setUpOnce() { +        if (RavenwoodRule.isOnRavenwood()) { +            return; +        } +          assumeTrue(UserManager.getMaxSupportedUsers() > 1);      } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java index 296ad0e939de..2d7cb2245c0a 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java @@ -24,7 +24,8 @@ import static org.mockito.Mockito.mock;  import static org.mockito.Mockito.spy;  import static org.mockito.Mockito.when; -import android.annotation.XmlRes; +import android.content.Context; +import android.content.res.Resources;  import android.net.NetworkStats;  import android.os.BatteryConsumer;  import android.os.BatteryStats; @@ -35,9 +36,9 @@ import android.os.Handler;  import android.os.HandlerThread;  import android.os.UidBatteryConsumer;  import android.os.UserBatteryConsumer; +import android.platform.test.ravenwood.RavenwoodRule;  import android.util.SparseArray; - -import androidx.test.InstrumentationRegistry; +import android.util.Xml;  import com.android.internal.os.CpuScalingPolicies;  import com.android.internal.os.PowerProfile; @@ -47,6 +48,7 @@ import org.junit.rules.TestRule;  import org.junit.runner.Description;  import org.junit.runners.model.Statement;  import org.mockito.stubbing.Answer; +import org.xmlpull.v1.XmlPullParser;  import java.io.File;  import java.io.IOException; @@ -81,6 +83,7 @@ public class BatteryUsageStatsRule implements TestRule {      private boolean[] mSupportedStandardBuckets;      private String[] mCustomPowerComponentNames;      private Throwable mThrowable; +    private final BatteryStatsImpl.BatteryStatsConfig.Builder mBatteryStatsConfigBuilder;      public BatteryUsageStatsRule() {          this(0); @@ -94,6 +97,11 @@ public class BatteryUsageStatsRule implements TestRule {          mCpusByPolicy.put(4, new int[]{4, 5, 6, 7});          mFreqsByPolicy.put(0, new int[]{300000, 1000000, 2000000});          mFreqsByPolicy.put(4, new int[]{300000, 1000000, 2500000, 3000000}); +        mBatteryStatsConfigBuilder = new BatteryStatsImpl.BatteryStatsConfig.Builder() +                .setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_CPU, +                        10000) +                .setPowerStatsThrottlePeriodMillis(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, +                        10000);      }      private void initBatteryStats() { @@ -107,7 +115,8 @@ public class BatteryUsageStatsRule implements TestRule {              }              clearDirectory();          } -        mBatteryStats = new MockBatteryStatsImpl(mMockClock, mHistoryDir, mHandler); +        mBatteryStats = new MockBatteryStatsImpl(mBatteryStatsConfigBuilder.build(), +                mMockClock, mHistoryDir, mHandler, new PowerStatsUidResolver());          mBatteryStats.setPowerProfile(mPowerProfile);          mBatteryStats.setCpuScalingPolicies(new CpuScalingPolicies(mCpusByPolicy, mFreqsByPolicy));          synchronized (mBatteryStats) { @@ -116,8 +125,6 @@ public class BatteryUsageStatsRule implements TestRule {          }          mBatteryStats.informThatAllExternalStatsAreFlushed(); -        mBatteryStats.onSystemReady(); -          if (mDisplayCount != -1) {              mBatteryStats.setDisplayCountLocked(mDisplayCount);          } @@ -148,11 +155,27 @@ public class BatteryUsageStatsRule implements TestRule {          return this;      } -    public BatteryUsageStatsRule setTestPowerProfile(@XmlRes int xmlId) { -        mPowerProfile.forceInitForTesting(InstrumentationRegistry.getContext(), xmlId); +    public BatteryUsageStatsRule setTestPowerProfile(String resourceName) { +        mPowerProfile.initForTesting(resolveParser(resourceName));          return this;      } +    public static XmlPullParser resolveParser(String resourceName) { +        if (RavenwoodRule.isOnRavenwood()) { +            try { +                return Xml.resolvePullParser(BatteryUsageStatsRule.class.getClassLoader() +                        .getResourceAsStream("res/xml/" + resourceName + ".xml")); +            } catch (IOException e) { +                throw new RuntimeException(e); +            } +        } else { +            Context context = androidx.test.InstrumentationRegistry.getContext(); +            Resources resources = context.getResources(); +            int resId = resources.getIdentifier(resourceName, "xml", context.getPackageName()); +            return resources.getXml(resId); +        } +    } +      public BatteryUsageStatsRule setCpuScalingPolicy(int policy, int[] relatedCpus,              int[] frequencies) {          if (mDefaultCpuScalingPolicy) { @@ -265,6 +288,12 @@ public class BatteryUsageStatsRule implements TestRule {          return this;      } +    public BatteryUsageStatsRule setPowerStatsThrottlePeriodMillis(int powerComponent, +            long throttleMs) { +        mBatteryStatsConfigBuilder.setPowerStatsThrottlePeriodMillis(powerComponent, throttleMs); +        return this; +    } +      public BatteryUsageStatsRule startWithScreenOn(boolean screenOn) {          mScreenOn = screenOn;          return this; @@ -291,23 +320,21 @@ public class BatteryUsageStatsRule implements TestRule {      }      private void before() { -        initBatteryStats();          HandlerThread bgThread = new HandlerThread("bg thread");          bgThread.setUncaughtExceptionHandler((thread, throwable)-> {              mThrowable = throwable;          });          bgThread.start();          mHandler = new Handler(bgThread.getLooper()); -        mBatteryStats.setHandler(mHandler); + +        initBatteryStats();          mBatteryStats.setOnBatteryInternal(true);          mBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);          mBatteryStats.getOnBatteryScreenOffTimeBase().setRunning(!mScreenOn, 0, 0);      }      private void after() throws Throwable { -        if (mHandler != null) { -            waitForBackgroundThread(); -        } +        waitForBackgroundThread();      }      public void waitForBackgroundThread() throws Throwable { @@ -316,11 +343,12 @@ public class BatteryUsageStatsRule implements TestRule {          }          ConditionVariable done = new ConditionVariable(); -        mHandler.post(done::open); -        assertThat(done.block(10000)).isTrue(); - -        if (mThrowable != null) { -            throw mThrowable; +        if (mHandler.post(done::open)) { +            boolean success = done.block(5000); +            if (mThrowable != null) { +                throw mThrowable; +            } +            assertThat(success).isTrue();          }      } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java index 29e2f5ee163a..e4ab227a4840 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BstatsCpuTimesValidationTest.java @@ -46,6 +46,7 @@ import android.os.IBinder;  import android.os.PowerManager;  import android.os.Process;  import android.os.SystemClock; +import android.platform.test.ravenwood.RavenwoodRule;  import android.provider.Settings;  import android.util.ArrayMap;  import android.util.DebugUtils; @@ -74,9 +75,11 @@ import java.util.regex.Matcher;  import java.util.regex.Pattern;  @LargeTest -@RunWith(AndroidJUnit4.class) -@android.platform.test.annotations.IgnoreUnderRavenwood +@android.platform.test.annotations.DisabledOnRavenwood(reason = "Integration test")  public class BstatsCpuTimesValidationTest { +    @Rule(order = 0) +    public final RavenwoodRule mRavenwood = new RavenwoodRule(); +      private static final String TAG = BstatsCpuTimesValidationTest.class.getSimpleName();      private static final String TEST_PKG = "com.android.coretests.apps.bstatstestapp"; @@ -112,10 +115,15 @@ public class BstatsCpuTimesValidationTest {      private static boolean sCpuFreqTimesAvailable;      private static boolean sPerProcStateTimesAvailable; -    @Rule public TestName testName = new TestName(); +    @Rule(order = 1) +    public TestName testName = new TestName();      @BeforeClass      public static void setupOnce() throws Exception { +        if (RavenwoodRule.isOnRavenwood()) { +            return; +        } +          sContext = InstrumentationRegistry.getContext();          sUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());          sContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG, @@ -127,6 +135,10 @@ public class BstatsCpuTimesValidationTest {      @AfterClass      public static void tearDownOnce() throws Exception { +        if (RavenwoodRule.isOnRavenwood()) { +            return; +        } +          executeCmd("cmd deviceidle whitelist -" + TEST_PKG);          if (sBatteryStatsConstsUpdated) {              Settings.Global.putString(sContext.getContentResolver(), diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java index 64d5414bf66c..ad2939284471 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorTest.java @@ -23,65 +23,127 @@ import static org.mockito.ArgumentMatchers.anyInt;  import static org.mockito.ArgumentMatchers.anyLong;  import static org.mockito.ArgumentMatchers.eq;  import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset;  import static org.mockito.Mockito.when; -import android.content.Context; -import android.hardware.power.stats.EnergyConsumer; -import android.hardware.power.stats.EnergyConsumerResult;  import android.hardware.power.stats.EnergyConsumerType;  import android.os.BatteryConsumer;  import android.os.ConditionVariable;  import android.os.Handler;  import android.os.HandlerThread; -import android.power.PowerStatsInternal; +import android.platform.test.ravenwood.RavenwoodRule;  import android.util.SparseArray; -import androidx.test.InstrumentationRegistry;  import androidx.test.filters.SmallTest;  import androidx.test.runner.AndroidJUnit4; -import com.android.frameworks.powerstatstests.R; +import com.android.internal.os.Clock;  import com.android.internal.os.CpuScalingPolicies;  import com.android.internal.os.PowerProfile;  import com.android.internal.os.PowerStats;  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; +import org.xmlpull.v1.XmlPullParserException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; +import java.io.IOException; +import java.util.function.IntSupplier;  @RunWith(AndroidJUnit4.class)  @SmallTest  public class CpuPowerStatsCollectorTest { + +    @Rule(order = 0) +    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder() +            .setProvideMainThread(true) +            .build(); +      private static final int ISOLATED_UID = 99123;      private static final int UID_1 = 42;      private static final int UID_2 = 99; -    private Context mContext;      private final MockClock mMockClock = new MockClock();      private final HandlerThread mHandlerThread = new HandlerThread("test");      private Handler mHandler;      private PowerStats mCollectedStats; -    private PowerProfile mPowerProfile; +    private PowerProfile mPowerProfile = new PowerProfile();      @Mock      private PowerStatsUidResolver mUidResolver;      @Mock      private CpuPowerStatsCollector.KernelCpuStatsReader mMockKernelCpuStatsReader;      @Mock -    private PowerStatsInternal mPowerStatsInternal; +    private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever;      private CpuScalingPolicies mCpuScalingPolicies; +    private class TestInjector implements CpuPowerStatsCollector.Injector { +        private final int mDefaultCpuPowerBrackets; +        private final int mDefaultCpuPowerBracketsPerEnergyConsumer; + +        TestInjector(int defaultCpuPowerBrackets, int defaultCpuPowerBracketsPerEnergyConsumer) { +            mDefaultCpuPowerBrackets = defaultCpuPowerBrackets; +            mDefaultCpuPowerBracketsPerEnergyConsumer = defaultCpuPowerBracketsPerEnergyConsumer; +        } + +        @Override +        public Handler getHandler() { +            return mHandler; +        } + +        @Override +        public Clock getClock() { +            return mMockClock; +        } + +        @Override +        public PowerStatsUidResolver getUidResolver() { +            return mUidResolver; +        } + +        @Override +        public CpuScalingPolicies getCpuScalingPolicies() { +            return mCpuScalingPolicies; +        } + +        @Override +        public PowerProfile getPowerProfile() { +            return mPowerProfile; +        } + +        @Override +        public CpuPowerStatsCollector.KernelCpuStatsReader getKernelCpuStatsReader() { +            return mMockKernelCpuStatsReader; +        } + +        @Override +        public PowerStatsCollector.ConsumedEnergyRetriever getConsumedEnergyRetriever() { +            return mConsumedEnergyRetriever; +        } + +        @Override +        public IntSupplier getVoltageSupplier() { +            return () -> 3500; +        } + +        @Override +        public int getDefaultCpuPowerBrackets() { +            return mDefaultCpuPowerBrackets; +        } + +        @Override +        public int getDefaultCpuPowerBracketsPerEnergyConsumer() { +            return mDefaultCpuPowerBracketsPerEnergyConsumer; +        } +    }; +      @Before -    public void setup() { +    public void setup() throws XmlPullParserException, IOException {          MockitoAnnotations.initMocks(this); -        mContext = InstrumentationRegistry.getContext(); -          mHandlerThread.start();          mHandler = mHandlerThread.getThreadHandler(); -        when(mMockKernelCpuStatsReader.nativeIsSupportedFeature()).thenReturn(true); +        when(mMockKernelCpuStatsReader.isSupportedFeature()).thenReturn(true);          when(mUidResolver.mapUid(anyInt())).thenAnswer(invocation -> {              int uid = invocation.getArgument(0);              if (uid == ISOLATED_UID) { @@ -90,12 +152,13 @@ public class CpuPowerStatsCollectorTest {                  return uid;              }          }); +        when(mConsumedEnergyRetriever.getEnergyConsumerIds(anyInt())).thenReturn(new int[0]);      }      @Test      public void powerBrackets_specifiedInPowerProfile() { -        mPowerProfile = new PowerProfile(mContext); -        mPowerProfile.forceInitForTesting(mContext, R.xml.power_profile_test_power_brackets); +        mPowerProfile.initForTesting( +                BatteryUsageStatsRule.resolveParser("power_profile_test_power_brackets"));          mCpuScalingPolicies = new CpuScalingPolicies(                  new SparseArray<>() {{                      put(0, new int[]{0}); @@ -114,8 +177,7 @@ public class CpuPowerStatsCollectorTest {      @Test      public void powerBrackets_default_noEnergyConsumers() { -        mPowerProfile = new PowerProfile(mContext); -        mPowerProfile.forceInitForTesting(mContext, R.xml.power_profile_test); +        mPowerProfile.initForTesting(BatteryUsageStatsRule.resolveParser("power_profile_test"));          mockCpuScalingPolicies(2);          CpuPowerStatsCollector collector = createCollector(3, 0); @@ -134,8 +196,7 @@ public class CpuPowerStatsCollectorTest {      @Test      public void powerBrackets_moreBracketsThanStates() { -        mPowerProfile = new PowerProfile(mContext); -        mPowerProfile.forceInitForTesting(mContext, R.xml.power_profile_test); +        mPowerProfile.initForTesting(BatteryUsageStatsRule.resolveParser("power_profile_test"));          mockCpuScalingPolicies(2);          CpuPowerStatsCollector collector = createCollector(8, 0); @@ -146,8 +207,7 @@ public class CpuPowerStatsCollectorTest {      @Test      public void powerBrackets_energyConsumers() throws Exception { -        mPowerProfile = new PowerProfile(mContext); -        mPowerProfile.forceInitForTesting(mContext, R.xml.power_profile_test); +        mPowerProfile.initForTesting(BatteryUsageStatsRule.resolveParser("power_profile_test"));          mockCpuScalingPolicies(2);          mockEnergyConsumers(); @@ -159,8 +219,7 @@ public class CpuPowerStatsCollectorTest {      @Test      public void powerStatsDescriptor() throws Exception { -        mPowerProfile = new PowerProfile(mContext); -        mPowerProfile.forceInitForTesting(mContext, R.xml.power_profile_test); +        mPowerProfile.initForTesting(BatteryUsageStatsRule.resolveParser("power_profile_test"));          mockCpuScalingPolicies(2);          mockEnergyConsumers(); @@ -170,8 +229,8 @@ public class CpuPowerStatsCollectorTest {          assertThat(descriptor.name).isEqualTo("cpu");          assertThat(descriptor.statsArrayLength).isEqualTo(13);          assertThat(descriptor.uidStatsArrayLength).isEqualTo(5); -        CpuPowerStatsCollector.CpuStatsArrayLayout layout = -                new CpuPowerStatsCollector.CpuStatsArrayLayout(); +        CpuPowerStatsLayout layout = +                new CpuPowerStatsLayout();          layout.fromExtras(descriptor.extras);          long[] deviceStats = new long[descriptor.statsArrayLength]; @@ -209,8 +268,8 @@ public class CpuPowerStatsCollectorTest {          mockEnergyConsumers();          CpuPowerStatsCollector collector = createCollector(8, 0); -        CpuPowerStatsCollector.CpuStatsArrayLayout layout = -                new CpuPowerStatsCollector.CpuStatsArrayLayout(); +        CpuPowerStatsLayout layout = +                new CpuPowerStatsLayout();          layout.fromExtras(collector.getPowerStatsDescriptor().extras);          mockKernelCpuStats(new long[]{1111, 2222, 3333}, @@ -296,10 +355,9 @@ public class CpuPowerStatsCollectorTest {      private CpuPowerStatsCollector createCollector(int defaultCpuPowerBrackets,              int defaultCpuPowerBracketsPerEnergyConsumer) { -        CpuPowerStatsCollector collector = new CpuPowerStatsCollector(mCpuScalingPolicies, -                mPowerProfile, mHandler, mMockKernelCpuStatsReader, mUidResolver, -                () -> mPowerStatsInternal, () -> 3500, 60_000, mMockClock, -                defaultCpuPowerBrackets, defaultCpuPowerBracketsPerEnergyConsumer); +        CpuPowerStatsCollector collector = new CpuPowerStatsCollector( +                new TestInjector(defaultCpuPowerBrackets, defaultCpuPowerBracketsPerEnergyConsumer), +                0);          collector.addConsumer(stats -> mCollectedStats = stats);          collector.setEnabled(true);          return collector; @@ -307,7 +365,7 @@ public class CpuPowerStatsCollectorTest {      private void mockKernelCpuStats(long[] deviceStats, SparseArray<long[]> uidToCpuStats,              long expectedLastUpdateTimestampMs, long newLastUpdateTimestampMs) { -        when(mMockKernelCpuStatsReader.nativeReadCpuStats( +        when(mMockKernelCpuStatsReader.readCpuStats(                  any(CpuPowerStatsCollector.KernelCpuStatsCallback.class),                  any(int[].class), anyLong(), any(long[].class), any(long[].class)))                  .thenAnswer(invocation -> { @@ -335,63 +393,18 @@ public class CpuPowerStatsCollectorTest {                  });      } -    @SuppressWarnings("unchecked") -    private void mockEnergyConsumers() throws Exception { -        when(mPowerStatsInternal.getEnergyConsumerInfo()) -                .thenReturn(new EnergyConsumer[]{ -                        new EnergyConsumer() {{ -                            id = 1; -                            type = EnergyConsumerType.CPU_CLUSTER; -                            ordinal = 0; -                            name = "CPU0"; -                        }}, -                        new EnergyConsumer() {{ -                            id = 2; -                            type = EnergyConsumerType.CPU_CLUSTER; -                            ordinal = 1; -                            name = "CPU4"; -                        }}, -                        new EnergyConsumer() {{ -                            id = 3; -                            type = EnergyConsumerType.BLUETOOTH; -                            name = "BT"; -                        }}, -                }); - -        CompletableFuture<EnergyConsumerResult[]> future1 = mock(CompletableFuture.class); -        when(future1.get(anyLong(), any(TimeUnit.class))) -                .thenReturn(new EnergyConsumerResult[]{ -                        new EnergyConsumerResult() {{ -                            id = 1; -                            energyUWs = 1000; -                        }}, -                        new EnergyConsumerResult() {{ -                            id = 2; -                            energyUWs = 2000; -                        }} -                }); - -        CompletableFuture<EnergyConsumerResult[]> future2 = mock(CompletableFuture.class); -        when(future2.get(anyLong(), any(TimeUnit.class))) -                .thenReturn(new EnergyConsumerResult[]{ -                        new EnergyConsumerResult() {{ -                            id = 1; -                            energyUWs = 1500; -                        }}, -                        new EnergyConsumerResult() {{ -                            id = 2; -                            energyUWs = 2700; -                        }} -                }); - -        when(mPowerStatsInternal.getEnergyConsumedAsync(eq(new int[]{1, 2}))) -                .thenReturn(future1) -                .thenReturn(future2); +    private void mockEnergyConsumers() { +        reset(mConsumedEnergyRetriever); +        when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.CPU_CLUSTER)) +                .thenReturn(new int[]{1, 2}); +        when(mConsumedEnergyRetriever.getConsumedEnergyUws(eq(new int[]{1, 2}))) +                .thenReturn(new long[]{1000, 2000}) +                .thenReturn(new long[]{1500, 2700});      }      private static int[] getScalingStepToPowerBracketMap(CpuPowerStatsCollector collector) { -        CpuPowerStatsCollector.CpuStatsArrayLayout layout = -                new CpuPowerStatsCollector.CpuStatsArrayLayout(); +        CpuPowerStatsLayout layout = +                new CpuPowerStatsLayout();          layout.fromExtras(collector.getPowerStatsDescriptor().extras);          return layout.getScalingStepToPowerBracketMap();      } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java index cbce7e804de5..70c40f5052f0 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java @@ -28,6 +28,8 @@ import android.os.IBinder;  import android.platform.test.annotations.RequiresFlagsEnabled;  import android.platform.test.flag.junit.CheckFlagsRule;  import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.platform.test.flag.junit.RavenwoodFlagsValueProvider; +import android.platform.test.ravenwood.RavenwoodRule;  import android.provider.DeviceConfig;  import androidx.test.InstrumentationRegistry; @@ -52,11 +54,15 @@ import java.util.regex.Pattern;  @RunWith(AndroidJUnit4.class)  @LargeTest -@android.platform.test.annotations.IgnoreUnderRavenwood +@android.platform.test.annotations.DisabledOnRavenwood(reason = "Integration test")  public class CpuPowerStatsCollectorValidationTest { -    @Rule -    public final CheckFlagsRule mCheckFlagsRule = -            DeviceFlagsValueProvider.createCheckFlagsRule(); +    @Rule(order = 0) +    public final RavenwoodRule mRavenwood = new RavenwoodRule(); + +    @Rule(order = 1) +    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isOnRavenwood() +            ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule() +            : DeviceFlagsValueProvider.createCheckFlagsRule();      private static final int WORK_DURATION_MS = 2000;      private static final String TEST_PKG = "com.android.coretests.apps.bstatstestapp"; diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuAggregatedPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsProcessorTest.java index 5c0e26887505..6b5da81954d0 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuAggregatedPowerStatsProcessorTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsProcessorTest.java @@ -30,6 +30,7 @@ import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_SC  import static com.google.common.truth.Truth.assertThat;  import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock;  import android.os.BatteryConsumer;  import android.os.PersistableBundle; @@ -55,7 +56,7 @@ import java.util.Map;  @RunWith(AndroidJUnit4.class)  @SmallTest -public class CpuAggregatedPowerStatsProcessorTest { +public class CpuPowerStatsProcessorTest {      @Rule(order = 0)      public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()              .setProvideMainThread(true) @@ -77,7 +78,7 @@ public class CpuAggregatedPowerStatsProcessorTest {              .setCpuPowerBracket(2, 0, 2);      private AggregatedPowerStatsConfig.PowerComponent mConfig; -    private CpuAggregatedPowerStatsProcessor mProcessor; +    private CpuPowerStatsProcessor mProcessor;      private MockPowerComponentAggregatedPowerStats mStats;      @Before @@ -86,7 +87,7 @@ public class CpuAggregatedPowerStatsProcessorTest {                  .trackDeviceStates(STATE_POWER, STATE_SCREEN)                  .trackUidStates(STATE_POWER, STATE_SCREEN, STATE_PROCESS_STATE); -        mProcessor = new CpuAggregatedPowerStatsProcessor( +        mProcessor = new CpuPowerStatsProcessor(                  mStatsRule.getPowerProfile(), mStatsRule.getCpuScalingPolicies());      } @@ -197,7 +198,7 @@ public class CpuAggregatedPowerStatsProcessorTest {      private static class MockPowerComponentAggregatedPowerStats extends              PowerComponentAggregatedPowerStats { -        private final CpuPowerStatsCollector.CpuStatsArrayLayout mStatsLayout; +        private final CpuPowerStatsLayout mStatsLayout;          private final PowerStats.Descriptor mDescriptor;          private HashMap<String, long[]> mDeviceStats = new HashMap<>();          private HashMap<String, long[]> mUidStats = new HashMap<>(); @@ -207,8 +208,8 @@ public class CpuAggregatedPowerStatsProcessorTest {          MockPowerComponentAggregatedPowerStats(AggregatedPowerStatsConfig.PowerComponent config,                  boolean useEnergyConsumers) { -            super(config); -            mStatsLayout = new CpuPowerStatsCollector.CpuStatsArrayLayout(); +            super(new AggregatedPowerStats(mock(AggregatedPowerStatsConfig.class)), config); +            mStatsLayout = new CpuPowerStatsLayout();              mStatsLayout.addDeviceSectionCpuTimeByScalingStep(3);              mStatsLayout.addDeviceSectionCpuTimeByCluster(2);              mStatsLayout.addDeviceSectionUsageDuration(); @@ -222,8 +223,8 @@ public class CpuAggregatedPowerStatsProcessorTest {              PersistableBundle extras = new PersistableBundle();              mStatsLayout.toExtras(extras);              mDescriptor = new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_CPU, -                    mStatsLayout.getDeviceStatsArrayLength(), mStatsLayout.getUidStatsArrayLength(), -                    extras); +                    mStatsLayout.getDeviceStatsArrayLength(), null, 0, +                    mStatsLayout.getUidStatsArrayLength(), extras);          }          @Override diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/KernelWakelockReaderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/KernelWakelockReaderTest.java index e02386656cb5..f035465dd1df 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/KernelWakelockReaderTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/KernelWakelockReaderTest.java @@ -16,16 +16,26 @@  package com.android.server.power.stats; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.platform.test.ravenwood.RavenwoodRule;  import android.system.suspend.internal.WakeLockInfo;  import androidx.test.filters.SmallTest; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test;  import java.nio.charset.Charset; -@android.platform.test.annotations.IgnoreUnderRavenwood -public class KernelWakelockReaderTest extends TestCase { +@android.platform.test.annotations.DisabledOnRavenwood(reason = "Kernel dependency") +public class KernelWakelockReaderTest { +    @Rule +    public final RavenwoodRule mRavenwood = new RavenwoodRule(); +      /**       * Helper class that builds the mock Kernel module file /d/wakeup_sources.       */ @@ -105,14 +115,14 @@ public class KernelWakelockReaderTest extends TestCase {      private KernelWakelockReader mReader; -    @Override +    @Before      public void setUp() throws Exception { -        super.setUp();          mReader = new KernelWakelockReader();      }  // ------------------------- Legacy Wakelock Stats Test ------------------------      @SmallTest +    @Test      public void testParseEmptyFile() throws Exception {          KernelWakelockStats staleStats = mReader.parseProcWakelocks(new byte[0], 0, true,                  new KernelWakelockStats()); @@ -121,6 +131,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testOnlyHeader() throws Exception {          byte[] buffer = new ProcFileBuilder().getBytes(); @@ -131,6 +142,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testOneWakelock() throws Exception {          byte[] buffer = new ProcFileBuilder()                  .addLine("Wakelock", 34, 123, 456) // Milliseconds @@ -150,6 +162,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testTwoWakelocks() throws Exception {          byte[] buffer = new ProcFileBuilder()                  .addLine("Wakelock", 1, 10) @@ -166,6 +179,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testDuplicateWakelocksAccumulate() throws Exception {          byte[] buffer = new ProcFileBuilder()                  .addLine("Wakelock", 1, 10) // Milliseconds @@ -184,6 +198,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testWakelocksBecomeStale() throws Exception {          KernelWakelockStats staleStats = new KernelWakelockStats(); @@ -209,6 +224,7 @@ public class KernelWakelockReaderTest extends TestCase {  // -------------------- SystemSuspend Wakelock Stats Test -------------------      @SmallTest +    @Test      public void testEmptyWakeLockInfoList() {          KernelWakelockStats staleStats = mReader.updateWakelockStats(new WakeLockInfo[0],                  new KernelWakelockStats()); @@ -217,6 +233,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testOneWakeLockInfo() {          WakeLockInfo[] wlStats = new WakeLockInfo[1];          wlStats[0] = createWakeLockInfo("WakeLock", 20, 1000, 500);   // Milliseconds @@ -235,6 +252,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testTwoWakeLockInfos() {          WakeLockInfo[] wlStats = new WakeLockInfo[2];          wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds @@ -258,6 +276,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testWakeLockInfosBecomeStale() {          WakeLockInfo[] wlStats = new WakeLockInfo[1];          wlStats[0] = createWakeLockInfo("WakeLock1", 10, 1000); // Milliseconds @@ -288,6 +307,7 @@ public class KernelWakelockReaderTest extends TestCase {  // -------------------- Aggregate  Wakelock Stats Tests --------------------      @SmallTest +    @Test      public void testAggregateStatsEmpty() throws Exception {          KernelWakelockStats staleStats = new KernelWakelockStats(); @@ -300,6 +320,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testAggregateStatsNoNativeWakelocks() throws Exception {          KernelWakelockStats staleStats = new KernelWakelockStats(); @@ -320,6 +341,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testAggregateStatsNoKernelWakelocks() throws Exception {          KernelWakelockStats staleStats = new KernelWakelockStats(); @@ -339,6 +361,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testAggregateStatsBothKernelAndNativeWakelocks() throws Exception {          KernelWakelockStats staleStats = new KernelWakelockStats(); @@ -364,6 +387,7 @@ public class KernelWakelockReaderTest extends TestCase {      }      @SmallTest +    @Test      public void testAggregateStatsUpdate() throws Exception {          KernelWakelockStats staleStats = new KernelWakelockStats(); diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java index 888a1688c2a1..9b810bc01b4d 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java @@ -26,6 +26,7 @@ import static com.google.common.truth.Truth.assertThat;  import static org.mockito.Mockito.mock;  import static org.mockito.Mockito.when; +import android.annotation.Nullable;  import android.app.usage.NetworkStatsManager;  import android.net.NetworkCapabilities;  import android.net.NetworkStats; @@ -34,6 +35,7 @@ import android.os.BatteryStats;  import android.os.BatteryUsageStatsQuery;  import android.os.Process;  import android.os.UidBatteryConsumer; +import android.platform.test.ravenwood.RavenwoodRule;  import android.telephony.AccessNetworkConstants;  import android.telephony.ActivityStatsTechSpecificInfo;  import android.telephony.CellSignalStrength; @@ -46,8 +48,6 @@ import android.telephony.TelephonyManager;  import androidx.test.filters.SmallTest;  import androidx.test.runner.AndroidJUnit4; -import com.android.frameworks.powerstatstests.R; -  import com.google.common.collect.Range;  import org.junit.Rule; @@ -56,23 +56,29 @@ import org.junit.runner.RunWith;  import org.mockito.Mock;  import java.util.ArrayList; +import java.util.List;  @RunWith(AndroidJUnit4.class)  @SmallTest  @SuppressWarnings("GuardedBy")  public class MobileRadioPowerCalculatorTest { +    @Rule(order = 0) +    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder() +            .setProvideMainThread(true) +            .build(); +      private static final double PRECISION = 0.00001;      private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;      private static final int APP_UID2 = Process.FIRST_APPLICATION_UID + 101;      @Mock      NetworkStatsManager mNetworkStatsManager; -    @Rule +    @Rule(order = 1)      public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();      @Test      public void testCounterBasedModel() { -        mStatsRule.setTestPowerProfile(R.xml.power_profile_test_modem_calculator) +        mStatsRule.setTestPowerProfile("power_profile_test_modem_calculator")                  .initMeasuredEnergyStatsLocked();          BatteryStatsImpl stats = mStatsRule.getBatteryStats(); @@ -126,10 +132,10 @@ public class MobileRadioPowerCalculatorTest {          stats.notePhoneSignalStrengthLocked(signalStrength, 9665, 9665);          // Note application network activity -        NetworkStats networkStats = new NetworkStats(10000, 1) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, -                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 150, 2000, 30, 100)) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID2, 0, 0, +        NetworkStats networkStats = mockNetworkStats(10000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0, +                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 150, 2000, 30, 100), +                mockNetworkStatsEntry("cellular", APP_UID2, 0, 0,                          METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 500, 50, 300, 10, 111));          mStatsRule.setNetworkStats(networkStats); @@ -192,7 +198,7 @@ public class MobileRadioPowerCalculatorTest {      @Test      public void testCounterBasedModel_multipleDefinedRat() { -        mStatsRule.setTestPowerProfile(R.xml.power_profile_test_modem_calculator_multiactive) +        mStatsRule.setTestPowerProfile("power_profile_test_modem_calculator_multiactive")                  .initMeasuredEnergyStatsLocked();          BatteryStatsImpl stats = mStatsRule.getBatteryStats(); @@ -246,10 +252,10 @@ public class MobileRadioPowerCalculatorTest {          stats.notePhoneSignalStrengthLocked(signalStrength, 9665, 9665);          // Note application network activity -        NetworkStats networkStats = new NetworkStats(10000, 1) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, -                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 150, 2000, 30, 100)) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID2, 0, 0, +        NetworkStats networkStats = mockNetworkStats(10000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0, +                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 150, 2000, 30, 100), +                mockNetworkStatsEntry("cellular", APP_UID2, 0, 0,                          METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 500, 50, 300, 10, 111));          mStatsRule.setNetworkStats(networkStats); @@ -349,7 +355,7 @@ public class MobileRadioPowerCalculatorTest {      @Test      public void testCounterBasedModel_legacyPowerProfile() { -        mStatsRule.setTestPowerProfile(R.xml.power_profile_test_legacy_modem) +        mStatsRule.setTestPowerProfile("power_profile_test_legacy_modem")                  .initMeasuredEnergyStatsLocked();          BatteryStatsImpl stats = mStatsRule.getBatteryStats(); @@ -403,10 +409,10 @@ public class MobileRadioPowerCalculatorTest {          stats.notePhoneSignalStrengthLocked(signalStrength, 9665, 9665);          // Note application network activity -        NetworkStats networkStats = new NetworkStats(10000, 1) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, -                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 150, 2000, 30, 100)) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID2, 0, 0, +        NetworkStats networkStats = mockNetworkStats(10000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0, +                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 150, 2000, 30, 100), +                mockNetworkStatsEntry("cellular", APP_UID2, 0, 0,                          METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 500, 50, 300, 10, 111));          mStatsRule.setNetworkStats(networkStats); @@ -469,7 +475,7 @@ public class MobileRadioPowerCalculatorTest {      @Test      public void testTimerBasedModel_byProcessState() { -        mStatsRule.setTestPowerProfile(R.xml.power_profile_test_legacy_modem) +        mStatsRule.setTestPowerProfile("power_profile_test_legacy_modem")                  .initMeasuredEnergyStatsLocked();          BatteryStatsImpl stats = mStatsRule.getBatteryStats();          BatteryStatsImpl.Uid uid = stats.getUidStatsLocked(APP_UID); @@ -521,8 +527,8 @@ public class MobileRadioPowerCalculatorTest {          stats.notePhoneSignalStrengthLocked(signalStrength, 9665, 9665);          // Note application network activity -        mStatsRule.setNetworkStats(new NetworkStats(10000, 1) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, +        mStatsRule.setNetworkStats(mockNetworkStats(10000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0,                          METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100)));          stats.noteModemControllerActivity(null, POWER_DATA_UNAVAILABLE, 10000, 10000, @@ -531,8 +537,8 @@ public class MobileRadioPowerCalculatorTest {          uid.setProcessStateForTest(                  BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 11000); -        mStatsRule.setNetworkStats(new NetworkStats(12000, 1) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, +        mStatsRule.setNetworkStats(mockNetworkStats(12000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0,                          METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 250, 2000, 80, 200)));          stats.noteModemControllerActivity(null, POWER_DATA_UNAVAILABLE, 12000, 12000, @@ -586,7 +592,7 @@ public class MobileRadioPowerCalculatorTest {      @Test      public void testMeasuredEnergyBasedModel_mobileRadioActiveTimeModel() { -        mStatsRule.setTestPowerProfile(R.xml.power_profile_test_legacy_modem) +        mStatsRule.setTestPowerProfile("power_profile_test_legacy_modem")                  .setPerUidModemModel(                          BatteryStatsImpl.PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME)                  .initMeasuredEnergyStatsLocked(); @@ -619,8 +625,8 @@ public class MobileRadioPowerCalculatorTest {          stats.notePhoneOnLocked(9800, 9800);          // Note application network activity -        NetworkStats networkStats = new NetworkStats(10000, 1) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, +        NetworkStats networkStats = mockNetworkStats(10000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0,                          METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100));          mStatsRule.setNetworkStats(networkStats); @@ -662,11 +668,9 @@ public class MobileRadioPowerCalculatorTest {                  .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);      } - -      @Test      public void testMeasuredEnergyBasedModel_modemActivityInfoRxTxModel() { -        mStatsRule.setTestPowerProfile(R.xml.power_profile_test_modem_calculator_multiactive) +        mStatsRule.setTestPowerProfile("power_profile_test_modem_calculator_multiactive")                  .setPerUidModemModel(                          BatteryStatsImpl.PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX)                  .initMeasuredEnergyStatsLocked(); @@ -728,10 +732,10 @@ public class MobileRadioPowerCalculatorTest {          stats.notePhoneSignalStrengthLocked(signalStrength, 9665, 9665);          // Note application network activity -        NetworkStats networkStats = new NetworkStats(10000, 1) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, -                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 150, 300, 10, 100)) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID2, 0, 0, +        NetworkStats networkStats = mockNetworkStats(10000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0, +                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 150, 300, 10, 100), +                mockNetworkStatsEntry("cellular", APP_UID2, 0, 0,                          METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 500, 50, 2000, 30, 111));          mStatsRule.setNetworkStats(networkStats); @@ -850,7 +854,7 @@ public class MobileRadioPowerCalculatorTest {      @Test      public void testMeasuredEnergyBasedModel_modemActivityInfoRxTxModel_legacyPowerProfile() { -        mStatsRule.setTestPowerProfile(R.xml.power_profile_test_legacy_modem) +        mStatsRule.setTestPowerProfile("power_profile_test_legacy_modem")                  .setPerUidModemModel(                          BatteryStatsImpl.PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX)                  .initMeasuredEnergyStatsLocked(); @@ -908,8 +912,8 @@ public class MobileRadioPowerCalculatorTest {          stats.notePhoneSignalStrengthLocked(signalStrength, 9665, 9665);          // Note application network activity -        NetworkStats networkStats = new NetworkStats(10000, 1) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, +        NetworkStats networkStats = mockNetworkStats(10000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0,                          METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100));          mStatsRule.setNetworkStats(networkStats); @@ -957,7 +961,7 @@ public class MobileRadioPowerCalculatorTest {      @Test      public void testMeasuredEnergyBasedModel_byProcessState() { -        mStatsRule.setTestPowerProfile(R.xml.power_profile_test_legacy_modem) +        mStatsRule.setTestPowerProfile("power_profile_test_legacy_modem")                  .initMeasuredEnergyStatsLocked();          BatteryStatsImpl stats = mStatsRule.getBatteryStats();          BatteryStatsImpl.Uid uid = stats.getUidStatsLocked(APP_UID); @@ -988,8 +992,8 @@ public class MobileRadioPowerCalculatorTest {                  new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});          // Note application network activity -        mStatsRule.setNetworkStats(new NetworkStats(10000, 1) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, +        mStatsRule.setNetworkStats(mockNetworkStats(10000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0,                          METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100)));          stats.noteModemControllerActivity(null, 10_000_000, 10000, 10000, mNetworkStatsManager); @@ -997,8 +1001,8 @@ public class MobileRadioPowerCalculatorTest {          uid.setProcessStateForTest(                  BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 11000); -        mStatsRule.setNetworkStats(new NetworkStats(12000, 1) -                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, +        mStatsRule.setNetworkStats(mockNetworkStats(12000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0,                          METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 250, 2000, 80, 200)));          stats.noteModemControllerActivity(null, 15_000_000, 12000, 12000, mNetworkStatsManager); @@ -1047,4 +1051,40 @@ public class MobileRadioPowerCalculatorTest {          final ModemActivityInfo emptyMai = new ModemActivityInfo(0L, 0L, 0L, new int[5], 0L);          stats.noteModemControllerActivity(emptyMai, 0, 0, 0, mNetworkStatsManager);      } + +    private NetworkStats mockNetworkStats(int elapsedTime, int initialSize, +            NetworkStats.Entry... entries) { +        NetworkStats stats; +        if (RavenwoodRule.isOnRavenwood()) { +            stats = mock(NetworkStats.class); +            when(stats.iterator()).thenAnswer(inv -> List.of(entries).iterator()); +        } else { +            stats = new NetworkStats(elapsedTime, initialSize); +            for (NetworkStats.Entry entry : entries) { +                stats = stats.addEntry(entry); +            } +        } +        return stats; +    } + +    private static NetworkStats.Entry mockNetworkStatsEntry(@Nullable String iface, int uid, +            int set, int tag, int metered, int roaming, int defaultNetwork, long rxBytes, +            long rxPackets, long txBytes, long txPackets, long operations) { +        if (RavenwoodRule.isOnRavenwood()) { +            NetworkStats.Entry entry = mock(NetworkStats.Entry.class); +            when(entry.getUid()).thenReturn(uid); +            when(entry.getMetered()).thenReturn(metered); +            when(entry.getRoaming()).thenReturn(roaming); +            when(entry.getDefaultNetwork()).thenReturn(defaultNetwork); +            when(entry.getRxBytes()).thenReturn(rxBytes); +            when(entry.getRxPackets()).thenReturn(rxPackets); +            when(entry.getTxBytes()).thenReturn(txBytes); +            when(entry.getTxPackets()).thenReturn(txPackets); +            when(entry.getOperations()).thenReturn(operations); +            return entry; +        } else { +            return new NetworkStats.Entry(iface, uid, set, tag, metered, +                    roaming, defaultNetwork, rxBytes, rxPackets, txBytes, txPackets, operations); +        } +    }  } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java new file mode 100644 index 000000000000..f93c4da3d8d0 --- /dev/null +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsCollectorTest.java @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.power.stats; + +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.annotation.NonNull; +import android.content.Context; +import android.content.pm.PackageManager; +import android.hardware.power.stats.EnergyConsumerType; +import android.net.NetworkStats; +import android.os.BatteryConsumer; +import android.os.BatteryStats; +import android.os.Handler; +import android.os.OutcomeReceiver; +import android.platform.test.ravenwood.RavenwoodRule; +import android.telephony.AccessNetworkConstants; +import android.telephony.ActivityStatsTechSpecificInfo; +import android.telephony.DataConnectionRealTimeInfo; +import android.telephony.ModemActivityInfo; +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.util.IndentingPrintWriter; + +import com.android.internal.os.Clock; +import com.android.internal.os.PowerStats; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.function.IntSupplier; +import java.util.function.LongSupplier; +import java.util.function.Supplier; + +public class MobileRadioPowerStatsCollectorTest { +    private static final int APP_UID1 = 42; +    private static final int APP_UID2 = 24; +    private static final int APP_UID3 = 44; +    private static final int ISOLATED_UID = 99123; + +    @Rule(order = 0) +    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder() +            .setProvideMainThread(true) +            .build(); + +    @Rule(order = 1) +    public final BatteryUsageStatsRule mStatsRule = +            new BatteryUsageStatsRule().setPowerStatsThrottlePeriodMillis( +                    BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, 10000); + +    private MockBatteryStatsImpl mBatteryStats; + +    private final MockClock mClock = mStatsRule.getMockClock(); + +    @Mock +    private Context mContext; +    @Mock +    private PackageManager mPackageManager; +    @Mock +    private TelephonyManager mTelephony; +    @Mock +    private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever; +    @Mock +    private Supplier<NetworkStats> mNetworkStatsSupplier; +    @Mock +    private PowerStatsUidResolver mPowerStatsUidResolver; +    @Mock +    private LongSupplier mCallDurationSupplier; +    @Mock +    private LongSupplier mScanDurationSupplier; + +    private final List<PowerStats> mRecordedPowerStats = new ArrayList<>(); + +    private MobileRadioPowerStatsCollector.Injector mInjector = +            new MobileRadioPowerStatsCollector.Injector() { +        @Override +        public Handler getHandler() { +            return mStatsRule.getHandler(); +        } + +        @Override +        public Clock getClock() { +            return mStatsRule.getMockClock(); +        } + +        @Override +        public PowerStatsUidResolver getUidResolver() { +            return mPowerStatsUidResolver; +        } + +        @Override +        public PackageManager getPackageManager() { +            return mPackageManager; +        } + +        @Override +        public PowerStatsCollector.ConsumedEnergyRetriever getConsumedEnergyRetriever() { +            return mConsumedEnergyRetriever; +        } + +        @Override +        public IntSupplier getVoltageSupplier() { +            return () -> 3500; +        } + +        @Override +        public Supplier<NetworkStats> getMobileNetworkStatsSupplier() { +            return mNetworkStatsSupplier; +        } + +        @Override +        public TelephonyManager getTelephonyManager() { +            return mTelephony; +        } + +        @Override +        public LongSupplier getCallDurationSupplier() { +            return mCallDurationSupplier; +        } + +        @Override +        public LongSupplier getPhoneSignalScanDurationSupplier() { +            return mScanDurationSupplier; +        } +    }; + +    @Before +    public void setup() { +        MockitoAnnotations.initMocks(this); +        when(mContext.getPackageManager()).thenReturn(mPackageManager); +        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true); +        when(mPowerStatsUidResolver.mapUid(anyInt())).thenAnswer(invocation -> { +            int uid = invocation.getArgument(0); +            if (uid == ISOLATED_UID) { +                return APP_UID2; +            } else { +                return uid; +            } +        }); +        mBatteryStats = mStatsRule.getBatteryStats(); +    } + +    @SuppressWarnings("GuardedBy") +    @Test +    public void triggering() throws Throwable { +        PowerStatsCollector collector = mBatteryStats.getPowerStatsCollector( +                BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO); +        collector.addConsumer(mRecordedPowerStats::add); + +        mBatteryStats.setPowerStatsCollectorEnabled(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO, +                true); + +        mockModemActivityInfo(1000, 2000, 3000, 600, new int[]{100, 200, 300, 400, 500}); + +        // This should trigger a sample collection +        mBatteryStats.onSystemReady(mContext); + +        mStatsRule.waitForBackgroundThread(); +        assertThat(mRecordedPowerStats).hasSize(1); + +        mRecordedPowerStats.clear(); +        mStatsRule.setTime(20000, 20000); +        mBatteryStats.notePhoneOnLocked(mClock.realtime, mClock.uptime); +        mStatsRule.waitForBackgroundThread(); +        assertThat(mRecordedPowerStats).hasSize(1); + +        mRecordedPowerStats.clear(); +        mStatsRule.setTime(40000, 40000); +        mBatteryStats.notePhoneOffLocked(mClock.realtime, mClock.uptime); +        mStatsRule.waitForBackgroundThread(); +        assertThat(mRecordedPowerStats).hasSize(1); + +        mRecordedPowerStats.clear(); +        mStatsRule.setTime(45000, 55000); +        mBatteryStats.noteMobileRadioPowerStateLocked( +                DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH, 0, APP_UID1, mClock.realtime, +                mClock.uptime); +        mStatsRule.setTime(50001, 50001); +        // Elapsed time under the throttling threshold - shouldn't trigger stats collection +        mBatteryStats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_LOW, +                0, APP_UID1, mClock.realtime, mClock.uptime); +        mStatsRule.waitForBackgroundThread(); +        assertThat(mRecordedPowerStats).hasSize(1); + +        mRecordedPowerStats.clear(); +        mStatsRule.setTime(50002, 50002); +        mBatteryStats.noteMobileRadioPowerStateLocked( +                DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH, 0, APP_UID1, mClock.realtime, +                mClock.uptime); +        mStatsRule.setTime(55000, 50000); +        // Elapsed time under the throttling threshold - shouldn't trigger stats collection +        mBatteryStats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_LOW, +                0, APP_UID1, mClock.realtime, mClock.uptime); +        mStatsRule.waitForBackgroundThread(); +        assertThat(mRecordedPowerStats).isEmpty(); +    } + +    @Test +    public void collectStats() throws Throwable { +        PowerStats powerStats = collectPowerStats(true); +        assertThat(powerStats.durationMs).isEqualTo(100); + +        PowerStats.Descriptor descriptor = powerStats.descriptor; +        MobileRadioPowerStatsLayout layout = +                new MobileRadioPowerStatsLayout(descriptor); +        assertThat(layout.getDeviceSleepTime(powerStats.stats)).isEqualTo(200); +        assertThat(layout.getDeviceIdleTime(powerStats.stats)).isEqualTo(300); +        assertThat(layout.getDeviceCallTime(powerStats.stats)).isEqualTo(40000); +        assertThat(layout.getDeviceScanTime(powerStats.stats)).isEqualTo(60000); +        assertThat(layout.getConsumedEnergy(powerStats.stats, 0)) +                .isEqualTo((64321 - 10000) * 1000 / 3500); + +        assertThat(powerStats.stateStats.size()).isEqualTo(2); +        long[] state1 = powerStats.stateStats.get(MobileRadioPowerStatsCollector.makeStateKey( +                BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR, +                ServiceState.FREQUENCY_RANGE_MMWAVE +        )); +        assertThat(layout.getStateRxTime(state1)).isEqualTo(6000); +        assertThat(layout.getStateTxTime(state1, 0)).isEqualTo(1000); +        assertThat(layout.getStateTxTime(state1, 1)).isEqualTo(2000); +        assertThat(layout.getStateTxTime(state1, 2)).isEqualTo(3000); +        assertThat(layout.getStateTxTime(state1, 3)).isEqualTo(4000); +        assertThat(layout.getStateTxTime(state1, 4)).isEqualTo(5000); + +        long[] state2 = powerStats.stateStats.get(MobileRadioPowerStatsCollector.makeStateKey( +                BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE, +                ServiceState.FREQUENCY_RANGE_LOW +        )); +        assertThat(layout.getStateRxTime(state2)).isEqualTo(7000); +        assertThat(layout.getStateTxTime(state2, 0)).isEqualTo(8000); +        assertThat(layout.getStateTxTime(state2, 1)).isEqualTo(9000); +        assertThat(layout.getStateTxTime(state2, 2)).isEqualTo(1000); +        assertThat(layout.getStateTxTime(state2, 3)).isEqualTo(2000); +        assertThat(layout.getStateTxTime(state2, 4)).isEqualTo(3000); + +        assertThat(powerStats.uidStats.size()).isEqualTo(2); +        long[] actual1 = powerStats.uidStats.get(APP_UID1); +        assertThat(layout.getUidRxBytes(actual1)).isEqualTo(1000); +        assertThat(layout.getUidTxBytes(actual1)).isEqualTo(2000); +        assertThat(layout.getUidRxPackets(actual1)).isEqualTo(100); +        assertThat(layout.getUidTxPackets(actual1)).isEqualTo(200); + +        // Combines APP_UID2 and ISOLATED_UID +        long[] actual2 = powerStats.uidStats.get(APP_UID2); +        assertThat(layout.getUidRxBytes(actual2)).isEqualTo(6000); +        assertThat(layout.getUidTxBytes(actual2)).isEqualTo(3000); +        assertThat(layout.getUidRxPackets(actual2)).isEqualTo(60); +        assertThat(layout.getUidTxPackets(actual2)).isEqualTo(30); + +        assertThat(powerStats.uidStats.get(ISOLATED_UID)).isNull(); +        assertThat(powerStats.uidStats.get(APP_UID3)).isNull(); +    } + +    @Test +    public void collectStats_noPerNetworkTypeData() throws Throwable { +        PowerStats powerStats = collectPowerStats(false); +        assertThat(powerStats.durationMs).isEqualTo(100); + +        PowerStats.Descriptor descriptor = powerStats.descriptor; +        MobileRadioPowerStatsLayout layout = +                new MobileRadioPowerStatsLayout(descriptor); +        assertThat(layout.getDeviceSleepTime(powerStats.stats)).isEqualTo(200); +        assertThat(layout.getDeviceIdleTime(powerStats.stats)).isEqualTo(300); +        assertThat(layout.getConsumedEnergy(powerStats.stats, 0)) +                .isEqualTo((64321 - 10000) * 1000 / 3500); + +        assertThat(powerStats.stateStats.size()).isEqualTo(1); +        long[] stateStats = powerStats.stateStats.get(MobileRadioPowerStatsCollector.makeStateKey( +                AccessNetworkConstants.AccessNetworkType.UNKNOWN, +                ServiceState.FREQUENCY_RANGE_UNKNOWN +        )); +        assertThat(layout.getStateRxTime(stateStats)).isEqualTo(6000); +        assertThat(layout.getStateTxTime(stateStats, 0)).isEqualTo(1000); +        assertThat(layout.getStateTxTime(stateStats, 1)).isEqualTo(2000); +        assertThat(layout.getStateTxTime(stateStats, 2)).isEqualTo(3000); +        assertThat(layout.getStateTxTime(stateStats, 3)).isEqualTo(4000); +        assertThat(layout.getStateTxTime(stateStats, 4)).isEqualTo(5000); + +        assertThat(powerStats.uidStats.size()).isEqualTo(2); +        long[] actual1 = powerStats.uidStats.get(APP_UID1); +        assertThat(layout.getUidRxBytes(actual1)).isEqualTo(1000); +        assertThat(layout.getUidTxBytes(actual1)).isEqualTo(2000); +        assertThat(layout.getUidRxPackets(actual1)).isEqualTo(100); +        assertThat(layout.getUidTxPackets(actual1)).isEqualTo(200); + +        // Combines APP_UID2 and ISOLATED_UID +        long[] actual2 = powerStats.uidStats.get(APP_UID2); +        assertThat(layout.getUidRxBytes(actual2)).isEqualTo(6000); +        assertThat(layout.getUidTxBytes(actual2)).isEqualTo(3000); +        assertThat(layout.getUidRxPackets(actual2)).isEqualTo(60); +        assertThat(layout.getUidTxPackets(actual2)).isEqualTo(30); + +        assertThat(powerStats.uidStats.get(ISOLATED_UID)).isNull(); +        assertThat(powerStats.uidStats.get(APP_UID3)).isNull(); +    } + +    @Test +    public void dump() throws Throwable { +        PowerStats powerStats = collectPowerStats(true); +        StringWriter sw = new StringWriter(); +        IndentingPrintWriter pw = new IndentingPrintWriter(sw); +        powerStats.dump(pw); +        pw.flush(); +        String dump = sw.toString(); +        assertThat(dump).contains("duration=100"); +        assertThat(dump).contains( +                "stats=[200, 300, 60000, 40000, " + ((64321 - 10000) * 1000 / 3500) + ", 0, 0, 0]"); +        assertThat(dump).contains("state LTE: [7000, 8000, 9000, 1000, 2000, 3000]"); +        assertThat(dump).contains("state NR MMWAVE: [6000, 1000, 2000, 3000, 4000, 5000]"); +        assertThat(dump).contains("UID 24: [6000, 3000, 60, 30, 0]"); +        assertThat(dump).contains("UID 42: [1000, 2000, 100, 200, 0]"); +    } + +    private PowerStats collectPowerStats(boolean perNetworkTypeData) throws Throwable { +        MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0); +        collector.setEnabled(true); + +        when(mConsumedEnergyRetriever.getEnergyConsumerIds( +                EnergyConsumerType.MOBILE_RADIO)).thenReturn(new int[]{777}); + +        if (perNetworkTypeData) { +            mockModemActivityInfo(1000, 2000, 3000, +                    AccessNetworkConstants.AccessNetworkType.NGRAN, +                    ServiceState.FREQUENCY_RANGE_MMWAVE, +                    600, new int[]{100, 200, 300, 400, 500}, +                    AccessNetworkConstants.AccessNetworkType.EUTRAN, +                    ServiceState.FREQUENCY_RANGE_LOW, +                    700, new int[]{800, 900, 100, 200, 300}); +        } else { +            mockModemActivityInfo(1000, 2000, 3000, 600, new int[]{100, 200, 300, 400, 500}); +        } +        mockNetworkStats(1000, +                4321, 321, 1234, 23, +                4000, 40, 2000, 20); + +        when(mConsumedEnergyRetriever.getConsumedEnergyUws(eq(new int[]{777}))) +                .thenReturn(new long[]{10000}); + +        when(mCallDurationSupplier.getAsLong()).thenReturn(10000L); +        when(mScanDurationSupplier.getAsLong()).thenReturn(20000L); + +        collector.collectStats(); + +        if (perNetworkTypeData) { +            mockModemActivityInfo(1100, 2200, 3300, +                    AccessNetworkConstants.AccessNetworkType.NGRAN, +                    ServiceState.FREQUENCY_RANGE_MMWAVE, +                    6600, new int[]{1100, 2200, 3300, 4400, 5500}, +                    AccessNetworkConstants.AccessNetworkType.EUTRAN, +                    ServiceState.FREQUENCY_RANGE_LOW, +                    7700, new int[]{8800, 9900, 1100, 2200, 3300}); +        } else { +            mockModemActivityInfo(1100, 2200, 3300, 6600, new int[]{1100, 2200, 3300, 4400, 5500}); +        } +        mockNetworkStats(1100, +                5321, 421, 3234, 223, +                8000, 80, 4000, 40); + +        when(mConsumedEnergyRetriever.getConsumedEnergyUws(eq(new int[]{777}))) +                .thenReturn(new long[]{64321}); +        when(mCallDurationSupplier.getAsLong()).thenReturn(50000L); +        when(mScanDurationSupplier.getAsLong()).thenReturn(80000L); + +        mStatsRule.setTime(20000, 20000); +        return collector.collectStats(); +    } + +    private void mockModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs, +            int networkType1, int freqRange1, int rxTimeMs1, @NonNull int[] txTimeMs1, +            int networkType2, int freqRange2, int rxTimeMs2, @NonNull int[] txTimeMs2) { +        ModemActivityInfo info = new ModemActivityInfo(timestamp, sleepTimeMs, idleTimeMs, +                new ActivityStatsTechSpecificInfo[]{ +                        new ActivityStatsTechSpecificInfo(networkType1, freqRange1, txTimeMs1, +                                rxTimeMs1), +                        new ActivityStatsTechSpecificInfo(networkType2, freqRange2, txTimeMs2, +                                rxTimeMs2)}); +        doAnswer(invocation -> { +            OutcomeReceiver<ModemActivityInfo, TelephonyManager.ModemActivityInfoException> +                    receiver = invocation.getArgument(1); +            receiver.onResult(info); +            return null; +        }).when(mTelephony).requestModemActivityInfo(any(), any()); +    } + +    private void mockModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs, +            int rxTimeMs, @NonNull int[] txTimeMs) { +        ModemActivityInfo info = new ModemActivityInfo(timestamp, sleepTimeMs, idleTimeMs, txTimeMs, +                rxTimeMs); +        doAnswer(invocation -> { +            OutcomeReceiver<ModemActivityInfo, TelephonyManager.ModemActivityInfoException> +                    receiver = invocation.getArgument(1); +            receiver.onResult(info); +            return null; +        }).when(mTelephony).requestModemActivityInfo(any(), any()); +    } + +    private void mockNetworkStats(long elapsedRealtime, +            long rxBytes1, long rxPackets1, long txBytes1, long txPackets1, +            long rxBytes2, long rxPackets2, long txBytes2, long txPackets2) { +        NetworkStats stats; +        if (RavenwoodRule.isOnRavenwood()) { +            stats = mock(NetworkStats.class); +            List<NetworkStats.Entry> entries = List.of( +                    mockNetworkStatsEntry(APP_UID1, rxBytes1, rxPackets1, txBytes1, txPackets1), +                    mockNetworkStatsEntry(APP_UID2, rxBytes2, rxPackets2, txBytes2, txPackets2), +                    mockNetworkStatsEntry(ISOLATED_UID, rxBytes2 / 2, rxPackets2 / 2, txBytes2 / 2, +                            txPackets2 / 2), +                    mockNetworkStatsEntry(APP_UID3, 314, 281, 314, 281)); +            when(stats.iterator()).thenAnswer(inv -> entries.iterator()); +        } else { +            stats = new NetworkStats(elapsedRealtime, 1) +                    .addEntry(new NetworkStats.Entry("mobile", APP_UID1, 0, 0, +                            METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes1, rxPackets1, +                            txBytes1, txPackets1, 100)) +                    .addEntry(new NetworkStats.Entry("mobile", APP_UID2, 0, 0, +                            METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes2, rxPackets2, +                            txBytes2, txPackets2, 111)) +                    .addEntry(new NetworkStats.Entry("mobile", ISOLATED_UID, 0, 0, METERED_NO, +                            ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes2 / 2, rxPackets2 / 2, +                            txBytes2 / 2, txPackets2 / 2, 111)) +                    .addEntry(new NetworkStats.Entry("mobile", APP_UID3, 0, 0, METERED_NO, +                            ROAMING_NO, DEFAULT_NETWORK_NO, 314, 281, 314, 281, 111)); +        } +        when(mNetworkStatsSupplier.get()).thenReturn(stats); +    } + +    private static NetworkStats.Entry mockNetworkStatsEntry(int uid, long rxBytes, long rxPackets, +            long txBytes, long txPackets) { +        NetworkStats.Entry entry = mock(NetworkStats.Entry.class); +        when(entry.getUid()).thenReturn(uid); +        when(entry.getMetered()).thenReturn(METERED_NO); +        when(entry.getRoaming()).thenReturn(ROAMING_NO); +        when(entry.getDefaultNetwork()).thenReturn(DEFAULT_NETWORK_NO); +        when(entry.getRxBytes()).thenReturn(rxBytes); +        when(entry.getRxPackets()).thenReturn(rxPackets); +        when(entry.getTxBytes()).thenReturn(txBytes); +        when(entry.getTxPackets()).thenReturn(txPackets); +        when(entry.getOperations()).thenReturn(100L); +        return entry; +    } + +    @Test +    public void networkTypeConstants() throws Throwable { +        Class<AccessNetworkConstants.AccessNetworkType> clazz = +                AccessNetworkConstants.AccessNetworkType.class; +        for (Field field : clazz.getDeclaredFields()) { +            final int modifiers = field.getModifiers(); +            if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers) +                    && field.getType().equals(int.class)) { +                boolean found = false; +                int value = field.getInt(null); +                for (int i = 0; i < MobileRadioPowerStatsCollector.NETWORK_TYPES.length; i++) { +                    if (MobileRadioPowerStatsCollector.NETWORK_TYPES[i] == value) { +                        found = true; +                        break; +                    } +                } +                assertWithMessage("New network type, " + field.getName() + " not represented in " +                        + MobileRadioPowerStatsCollector.class).that(found).isTrue(); +            } +        } +    } +} diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java new file mode 100644 index 000000000000..4ac7ad8d07ff --- /dev/null +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MobileRadioPowerStatsProcessorTest.java @@ -0,0 +1,499 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.power.stats; + +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; +import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND; +import static android.os.BatteryConsumer.PROCESS_STATE_CACHED; +import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND; +import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE; + +import static com.android.server.power.stats.AggregatedPowerStatsConfig.POWER_STATE_OTHER; +import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_ON; +import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_OTHER; +import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_POWER; +import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_PROCESS_STATE; +import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_SCREEN; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.annotation.Nullable; +import android.content.Context; +import android.content.pm.PackageManager; +import android.hardware.power.stats.EnergyConsumerType; +import android.net.NetworkStats; +import android.os.BatteryConsumer; +import android.os.Handler; +import android.os.OutcomeReceiver; +import android.os.Process; +import android.platform.test.ravenwood.RavenwoodRule; +import android.telephony.ModemActivityInfo; +import android.telephony.TelephonyManager; + +import com.android.internal.os.Clock; +import com.android.internal.os.PowerStats; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; +import java.util.function.IntSupplier; +import java.util.function.LongSupplier; +import java.util.function.Supplier; + +public class MobileRadioPowerStatsProcessorTest { +    @Rule(order = 0) +    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder() +            .setProvideMainThread(true) +            .build(); + +    private static final double PRECISION = 0.00001; +    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42; +    private static final int APP_UID2 = Process.FIRST_APPLICATION_UID + 101; +    private static final int MOBILE_RADIO_ENERGY_CONSUMER_ID = 1; +    private static final int VOLTAGE_MV = 3500; + +    @Rule(order = 1) +    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(); +    @Mock +    private Context mContext; +    @Mock +    private PowerStatsUidResolver mPowerStatsUidResolver; +    @Mock +    private PackageManager mPackageManager; +    @Mock +    private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever; +    @Mock +    private Supplier<NetworkStats> mNetworkStatsSupplier; +    @Mock +    private TelephonyManager mTelephonyManager; +    @Mock +    private LongSupplier mCallDurationSupplier; +    @Mock +    private LongSupplier mScanDurationSupplier; + +    private final MobileRadioPowerStatsCollector.Injector mInjector = +            new MobileRadioPowerStatsCollector.Injector() { +                @Override +                public Handler getHandler() { +                    return mStatsRule.getHandler(); +                } + +                @Override +                public Clock getClock() { +                    return mStatsRule.getMockClock(); +                } + +                @Override +                public PowerStatsUidResolver getUidResolver() { +                    return mPowerStatsUidResolver; +                } + +                @Override +                public PackageManager getPackageManager() { +                    return mPackageManager; +                } + +                @Override +                public PowerStatsCollector.ConsumedEnergyRetriever getConsumedEnergyRetriever() { +                    return mConsumedEnergyRetriever; +                } + +                @Override +                public IntSupplier getVoltageSupplier() { +                    return () -> VOLTAGE_MV; +                } + +                @Override +                public Supplier<NetworkStats> getMobileNetworkStatsSupplier() { +                    return mNetworkStatsSupplier; +                } + +                @Override +                public TelephonyManager getTelephonyManager() { +                    return mTelephonyManager; +                } + +                @Override +                public LongSupplier getCallDurationSupplier() { +                    return mCallDurationSupplier; +                } + +                @Override +                public LongSupplier getPhoneSignalScanDurationSupplier() { +                    return mScanDurationSupplier; +                } +            }; + +    @Before +    public void setup() { +        MockitoAnnotations.initMocks(this); + +        when(mContext.getPackageManager()).thenReturn(mPackageManager); +        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true); +        when(mPowerStatsUidResolver.mapUid(anyInt())) +                .thenAnswer(invocation -> invocation.getArgument(0)); +    } + +    @Test +    public void powerProfileModel() { +        // No power monitoring hardware +        when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.MOBILE_RADIO)) +                .thenReturn(new int[0]); + +        mStatsRule.setTestPowerProfile("power_profile_test_modem_calculator"); + +        MobileRadioPowerStatsProcessor processor = +                new MobileRadioPowerStatsProcessor(mStatsRule.getPowerProfile()); + +        AggregatedPowerStatsConfig.PowerComponent config = +                new AggregatedPowerStatsConfig.PowerComponent( +                        BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO) +                        .trackDeviceStates(STATE_POWER, STATE_SCREEN) +                        .trackUidStates(STATE_POWER, STATE_SCREEN, STATE_PROCESS_STATE) +                        .setProcessor(processor); + +        PowerComponentAggregatedPowerStats aggregatedStats = +                new PowerComponentAggregatedPowerStats( +                        new AggregatedPowerStats(mock(AggregatedPowerStatsConfig.class)), config); + +        aggregatedStats.setState(STATE_POWER, POWER_STATE_OTHER, 0); +        aggregatedStats.setState(STATE_SCREEN, SCREEN_STATE_ON, 0); +        aggregatedStats.setUidState(APP_UID, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND, 0); +        aggregatedStats.setUidState(APP_UID2, STATE_PROCESS_STATE, PROCESS_STATE_CACHED, 0); + +        MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0); +        collector.setEnabled(true); + +        // Initial empty ModemActivityInfo. +        mockModemActivityInfo(new ModemActivityInfo(0L, 0L, 0L, new int[5], 0L)); + +        // Establish a baseline +        aggregatedStats.addPowerStats(collector.collectStats(), 0); + +        // Turn the screen off after 2.5 seconds +        aggregatedStats.setState(STATE_SCREEN, SCREEN_STATE_OTHER, 2500); +        aggregatedStats.setUidState(APP_UID, STATE_PROCESS_STATE, PROCESS_STATE_BACKGROUND, 2500); +        aggregatedStats.setUidState(APP_UID, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND_SERVICE, +                5000); + +        // Note application network activity +        NetworkStats networkStats = mockNetworkStats(10000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0, +                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 10000, 1500, 20000, 300, 100), +                mockNetworkStatsEntry("cellular", APP_UID2, 0, 0, +                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 5000, 500, 3000, 100, 111)); + +        when(mNetworkStatsSupplier.get()).thenReturn(networkStats); + +        ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000, +                new int[]{100, 200, 300, 400, 500}, 600); +        mockModemActivityInfo(mai); + +        when(mCallDurationSupplier.getAsLong()).thenReturn(200L); +        when(mScanDurationSupplier.getAsLong()).thenReturn(5555L); + +        mStatsRule.setTime(10_000, 10_000); + +        PowerStats powerStats = collector.collectStats(); + +        aggregatedStats.addPowerStats(powerStats, 10_000); + +        processor.finish(aggregatedStats); + +        MobileRadioPowerStatsLayout statsLayout = +                new MobileRadioPowerStatsLayout( +                        aggregatedStats.getPowerStatsDescriptor()); + +        //    720 mA * 100 ms  (level 0 TX drain rate * level 0 TX duration) +        // + 1080 mA * 200 ms  (level 1 TX drain rate * level 1 TX duration) +        // + 1440 mA * 300 ms  (level 2 TX drain rate * level 2 TX duration) +        // + 1800 mA * 400 ms  (level 3 TX drain rate * level 3 TX duration) +        // + 2160 mA * 500 ms  (level 4 TX drain rate * level 4 TX duration) +        // + 1440 mA * 600 ms  (RX drain rate * RX duration) +        // +  360 mA * 3000 ms (idle drain rate * idle duration) +        // +   70 mA * 2000 ms (sleep drain rate * sleep duration) +        // _________________ +        // =    4604000 mA-ms or 1.27888 mA-h +        //   25% of 1.27888 = 0.319722 +        //   75% of 1.27888 = 0.959166 +        double totalPower = 0; +        long[] deviceStats = new long[aggregatedStats.getPowerStatsDescriptor().statsArrayLength]; +        aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON)); +        assertThat(statsLayout.getDevicePowerEstimate(deviceStats)) +                .isWithin(PRECISION).of(0.319722); +        totalPower += statsLayout.getDevicePowerEstimate(deviceStats); + +        aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_OTHER)); +        assertThat(statsLayout.getDevicePowerEstimate(deviceStats)) +                .isWithin(PRECISION).of(0.959166); +        totalPower += statsLayout.getDevicePowerEstimate(deviceStats); + +        assertThat(totalPower).isWithin(PRECISION).of(1.27888); + +        //    720 mA * 100 ms  (level 0 TX drain rate * level 0 TX duration) +        // + 1080 mA * 200 ms  (level 1 TX drain rate * level 1 TX duration) +        // + 1440 mA * 300 ms  (level 2 TX drain rate * level 2 TX duration) +        // + 1800 mA * 400 ms  (level 3 TX drain rate * level 3 TX duration) +        // + 2160 mA * 500 ms  (level 4 TX drain rate * level 4 TX duration) +        // + 1440 mA * 600 ms  (RX drain rate * RX duration) +        // _________________ +        // =    3384000 mA-ms or 0.94 mA-h +        double uidPower1 = 0; +        long[] uidStats = new long[aggregatedStats.getPowerStatsDescriptor().uidStatsArrayLength]; +        aggregatedStats.getUidStats(uidStats, APP_UID, +                states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND)); +        assertThat(statsLayout.getUidPowerEstimate(uidStats)) +                .isWithin(PRECISION).of(0.17625); +        uidPower1 += statsLayout.getUidPowerEstimate(uidStats); + +        aggregatedStats.getUidStats(uidStats, APP_UID, +                states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_BACKGROUND)); +        assertThat(statsLayout.getUidPowerEstimate(uidStats)) +                .isWithin(PRECISION).of(0.17625); +        uidPower1 += statsLayout.getUidPowerEstimate(uidStats); + +        aggregatedStats.getUidStats(uidStats, APP_UID, +                states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_FOREGROUND_SERVICE)); +        assertThat(statsLayout.getUidPowerEstimate(uidStats)) +                .isWithin(PRECISION).of(0.3525); +        uidPower1 += statsLayout.getUidPowerEstimate(uidStats); + +        double uidPower2 = 0; +        aggregatedStats.getUidStats(uidStats, APP_UID2, +                states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED)); +        assertThat(statsLayout.getUidPowerEstimate(uidStats)) +                .isWithin(PRECISION).of(0.05875); +        uidPower2 += statsLayout.getUidPowerEstimate(uidStats); + +        aggregatedStats.getUidStats(uidStats, APP_UID2, +                states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_CACHED)); +        assertThat(statsLayout.getUidPowerEstimate(uidStats)) +                .isWithin(PRECISION).of(0.17625); +        uidPower2 += statsLayout.getUidPowerEstimate(uidStats); + +        assertThat(uidPower1 + uidPower2) +                .isWithin(PRECISION).of(0.94); + +        // 3/4 of total packets were sent by APP_UID so 75% of total +        assertThat(uidPower1 / (uidPower1 + uidPower2)) +                .isWithin(PRECISION).of(0.75); +    } + +    @Test +    public void measuredEnergyModel() { +        // PowerStats hardware is available +        when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.MOBILE_RADIO)) +                .thenReturn(new int[] {MOBILE_RADIO_ENERGY_CONSUMER_ID}); + +        mStatsRule.setTestPowerProfile("power_profile_test_legacy_modem") +                .initMeasuredEnergyStatsLocked(); + +        MobileRadioPowerStatsProcessor processor = +                new MobileRadioPowerStatsProcessor(mStatsRule.getPowerProfile()); + +        AggregatedPowerStatsConfig.PowerComponent config = +                new AggregatedPowerStatsConfig.PowerComponent( +                        BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO) +                        .trackDeviceStates(STATE_POWER, STATE_SCREEN) +                        .trackUidStates(STATE_POWER, STATE_SCREEN, STATE_PROCESS_STATE) +                        .setProcessor(processor); + +        PowerComponentAggregatedPowerStats aggregatedStats = +                new PowerComponentAggregatedPowerStats( +                        new AggregatedPowerStats(mock(AggregatedPowerStatsConfig.class)), config); + +        aggregatedStats.setState(STATE_POWER, POWER_STATE_OTHER, 0); +        aggregatedStats.setState(STATE_SCREEN, SCREEN_STATE_ON, 0); +        aggregatedStats.setUidState(APP_UID, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND, 0); +        aggregatedStats.setUidState(APP_UID2, STATE_PROCESS_STATE, PROCESS_STATE_CACHED, 0); + +        MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0); +        collector.setEnabled(true); + +        // Initial empty ModemActivityInfo. +        mockModemActivityInfo(new ModemActivityInfo(0L, 0L, 0L, new int[5], 0L)); + +        when(mConsumedEnergyRetriever.getConsumedEnergyUws( +                new int[]{MOBILE_RADIO_ENERGY_CONSUMER_ID})) +                .thenReturn(new long[]{0}); + +        // Establish a baseline +        aggregatedStats.addPowerStats(collector.collectStats(), 0); + +        // Turn the screen off after 2.5 seconds +        aggregatedStats.setState(STATE_SCREEN, SCREEN_STATE_OTHER, 2500); +        aggregatedStats.setUidState(APP_UID, STATE_PROCESS_STATE, PROCESS_STATE_BACKGROUND, 2500); +        aggregatedStats.setUidState(APP_UID, STATE_PROCESS_STATE, PROCESS_STATE_FOREGROUND_SERVICE, +                5000); + +        // Note application network activity +        NetworkStats networkStats = mockNetworkStats(10000, 1, +                mockNetworkStatsEntry("cellular", APP_UID, 0, 0, +                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 10000, 1500, 20000, 300, 100), +                mockNetworkStatsEntry("cellular", APP_UID2, 0, 0, +                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 5000, 500, 3000, 100, 111)); + +        when(mNetworkStatsSupplier.get()).thenReturn(networkStats); + +        ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000, +                new int[]{100, 200, 300, 400, 500}, 600); +        mockModemActivityInfo(mai); + +        mStatsRule.setTime(10_000, 10_000); + +        long energyUws = 10_000_000L * VOLTAGE_MV / 1000L; +        when(mConsumedEnergyRetriever.getConsumedEnergyUws( +                new int[]{MOBILE_RADIO_ENERGY_CONSUMER_ID})).thenReturn(new long[]{energyUws}); + +        when(mCallDurationSupplier.getAsLong()).thenReturn(200L); +        when(mScanDurationSupplier.getAsLong()).thenReturn(5555L); + +        PowerStats powerStats = collector.collectStats(); + +        aggregatedStats.addPowerStats(powerStats, 10_000); + +        processor.finish(aggregatedStats); + +        MobileRadioPowerStatsLayout statsLayout = +                new MobileRadioPowerStatsLayout( +                        aggregatedStats.getPowerStatsDescriptor()); + +        // 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh +        double totalPower = 0; +        long[] deviceStats = new long[aggregatedStats.getPowerStatsDescriptor().statsArrayLength]; +        aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON)); +        assertThat(statsLayout.getDevicePowerEstimate(deviceStats)) +                .isWithin(PRECISION).of(0.671837); +        totalPower += statsLayout.getDevicePowerEstimate(deviceStats); +        assertThat(statsLayout.getDeviceCallPowerEstimate(deviceStats)) +                .isWithin(PRECISION).of(0.022494); +        totalPower += statsLayout.getDeviceCallPowerEstimate(deviceStats); + +        aggregatedStats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_OTHER)); +        assertThat(statsLayout.getDevicePowerEstimate(deviceStats)) +                .isWithin(PRECISION).of(2.01596); +        totalPower += statsLayout.getDevicePowerEstimate(deviceStats); +        assertThat(statsLayout.getDeviceCallPowerEstimate(deviceStats)) +                .isWithin(PRECISION).of(0.067484); +        totalPower += statsLayout.getDeviceCallPowerEstimate(deviceStats); + +        // These estimates are supposed to add up to the measured energy, 2.77778 mAh +        assertThat(totalPower).isWithin(PRECISION).of(2.77778); + +        double uidPower1 = 0; +        long[] uidStats = new long[aggregatedStats.getPowerStatsDescriptor().uidStatsArrayLength]; +        aggregatedStats.getUidStats(uidStats, APP_UID, +                states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND)); +        assertThat(statsLayout.getUidPowerEstimate(uidStats)) +                .isWithin(PRECISION).of(0.198236); +        uidPower1 += statsLayout.getUidPowerEstimate(uidStats); + +        aggregatedStats.getUidStats(uidStats, APP_UID, +                states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_BACKGROUND)); +        assertThat(statsLayout.getUidPowerEstimate(uidStats)) +                .isWithin(PRECISION).of(0.198236); +        uidPower1 += statsLayout.getUidPowerEstimate(uidStats); + +        aggregatedStats.getUidStats(uidStats, APP_UID, +                states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_FOREGROUND_SERVICE)); +        assertThat(statsLayout.getUidPowerEstimate(uidStats)) +                .isWithin(PRECISION).of(0.396473); +        uidPower1 += statsLayout.getUidPowerEstimate(uidStats); + +        double uidPower2 = 0; +        aggregatedStats.getUidStats(uidStats, APP_UID2, +                states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED)); +        assertThat(statsLayout.getUidPowerEstimate(uidStats)) +                .isWithin(PRECISION).of(0.066078); +        uidPower2 += statsLayout.getUidPowerEstimate(uidStats); + +        aggregatedStats.getUidStats(uidStats, APP_UID2, +                states(POWER_STATE_OTHER, SCREEN_STATE_OTHER, PROCESS_STATE_CACHED)); +        assertThat(statsLayout.getUidPowerEstimate(uidStats)) +                .isWithin(PRECISION).of(0.198236); +        uidPower2 += statsLayout.getUidPowerEstimate(uidStats); + +        // Total power attributed to apps is significantly less than the grand total, +        // because we only attribute TX/RX to apps but not maintaining a connection with the cell. +        assertThat(uidPower1 + uidPower2) +                .isWithin(PRECISION).of(1.057259); + +        // 3/4 of total packets were sent by APP_UID so 75% of total RX/TX power is attributed to it +        assertThat(uidPower1 / (uidPower1 + uidPower2)) +                .isWithin(PRECISION).of(0.75); +    } + +    private int[] states(int... states) { +        return states; +    } + +    private void mockModemActivityInfo(ModemActivityInfo emptyMai) { +        doAnswer(invocation -> { +            OutcomeReceiver<ModemActivityInfo, TelephonyManager.ModemActivityInfoException> +                    receiver = invocation.getArgument(1); +            receiver.onResult(emptyMai); +            return null; +        }).when(mTelephonyManager).requestModemActivityInfo(any(), any()); +    } + +    private NetworkStats mockNetworkStats(int elapsedTime, int initialSize, +            NetworkStats.Entry... entries) { +        NetworkStats stats; +        if (RavenwoodRule.isOnRavenwood()) { +            stats = mock(NetworkStats.class); +            when(stats.iterator()).thenAnswer(inv -> List.of(entries).iterator()); +        } else { +            stats = new NetworkStats(elapsedTime, initialSize); +            for (NetworkStats.Entry entry : entries) { +                stats = stats.addEntry(entry); +            } +        } +        return stats; +    } + +    private static NetworkStats.Entry mockNetworkStatsEntry(@Nullable String iface, int uid, +            int set, int tag, int metered, int roaming, int defaultNetwork, long rxBytes, +            long rxPackets, long txBytes, long txPackets, long operations) { +        if (RavenwoodRule.isOnRavenwood()) { +            NetworkStats.Entry entry = mock(NetworkStats.Entry.class); +            when(entry.getUid()).thenReturn(uid); +            when(entry.getMetered()).thenReturn(metered); +            when(entry.getRoaming()).thenReturn(roaming); +            when(entry.getDefaultNetwork()).thenReturn(defaultNetwork); +            when(entry.getRxBytes()).thenReturn(rxBytes); +            when(entry.getRxPackets()).thenReturn(rxPackets); +            when(entry.getTxBytes()).thenReturn(txBytes); +            when(entry.getTxPackets()).thenReturn(txPackets); +            when(entry.getOperations()).thenReturn(operations); +            return entry; +        } else { +            return new NetworkStats.Entry(iface, uid, set, tag, metered, +                    roaming, defaultNetwork, rxBytes, rxPackets, txBytes, txPackets, operations); +        } +    } +} diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java index 9f069130502f..1d48975c086e 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java @@ -35,6 +35,7 @@ import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeRea  import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;  import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader;  import com.android.internal.os.KernelSingleUidTimeReader; +import com.android.internal.os.MonotonicClock;  import com.android.internal.os.PowerProfile;  import com.android.internal.power.EnergyConsumerStats; @@ -52,6 +53,8 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {      // The mNetworkStats will be used for both wifi and mobile categories      private NetworkStats mNetworkStats;      private DummyExternalStatsSync mExternalStatsSync = new DummyExternalStatsSync(); +    public static final BatteryStatsConfig DEFAULT_CONFIG = +            new BatteryStatsConfig.Builder().build();      MockBatteryStatsImpl() {          this(new MockClock()); @@ -66,15 +69,18 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {      }      MockBatteryStatsImpl(Clock clock, File historyDirectory, Handler handler) { -        this(clock, historyDirectory, handler, new PowerStatsUidResolver()); +        this(DEFAULT_CONFIG, clock, historyDirectory, handler, new PowerStatsUidResolver());      } -    MockBatteryStatsImpl(Clock clock, File historyDirectory, Handler handler, -            PowerStatsUidResolver powerStatsUidResolver) { -        super(clock, historyDirectory, handler, powerStatsUidResolver, -                mock(FrameworkStatsLogger.class), mock(BatteryStatsHistory.TraceDelegate.class), +    MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, File historyDirectory, +            Handler handler, PowerStatsUidResolver powerStatsUidResolver) { +        super(config, clock, new MonotonicClock(0, clock), historyDirectory, handler, +                mock(PlatformIdleStateCallback.class), mock(EnergyStatsRetriever.class), +                mock(UserInfoProvider.class), mock(PowerProfile.class), +                new CpuScalingPolicies(new SparseArray<>(), new SparseArray<>()), +                powerStatsUidResolver, mock(FrameworkStatsLogger.class), +                mock(BatteryStatsHistory.TraceDelegate.class),                  mock(BatteryStatsHistory.EventLogger.class)); -        initTimersAndCounters();          setMaxHistoryBuffer(128 * 1024);          setExternalStatsSyncLocked(mExternalStatsSync); @@ -276,10 +282,6 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {      public void writeSyncLocked() {      } -    public void setHandler(Handler handler) { -        mHandler = handler; -    } -      @Override      protected void updateBatteryPropertiesLocked() {      } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java new file mode 100644 index 000000000000..dadcf3f3871e --- /dev/null +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PhoneCallPowerStatsProcessorTest.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.power.stats; + +import static com.android.server.power.stats.AggregatedPowerStatsConfig.POWER_STATE_OTHER; +import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_ON; +import static com.android.server.power.stats.AggregatedPowerStatsConfig.SCREEN_STATE_OTHER; +import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_POWER; +import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_PROCESS_STATE; +import static com.android.server.power.stats.AggregatedPowerStatsConfig.STATE_SCREEN; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.hardware.power.stats.EnergyConsumerType; +import android.net.NetworkStats; +import android.os.BatteryConsumer; +import android.os.Handler; +import android.os.OutcomeReceiver; +import android.platform.test.ravenwood.RavenwoodRule; +import android.telephony.ModemActivityInfo; +import android.telephony.TelephonyManager; + +import com.android.internal.os.Clock; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.function.IntSupplier; +import java.util.function.LongSupplier; +import java.util.function.Supplier; + +public class PhoneCallPowerStatsProcessorTest { +    @Rule(order = 0) +    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder() +            .setProvideMainThread(true) +            .build(); + +    private static final double PRECISION = 0.00001; +    private static final int VOLTAGE_MV = 3500; + +    @Rule(order = 1) +    public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(); +    @Mock +    private Context mContext; +    @Mock +    private PowerStatsUidResolver mPowerStatsUidResolver; +    @Mock +    private PackageManager mPackageManager; +    @Mock +    private PowerStatsCollector.ConsumedEnergyRetriever mConsumedEnergyRetriever; +    @Mock +    private Supplier<NetworkStats> mNetworkStatsSupplier; +    @Mock +    private TelephonyManager mTelephonyManager; +    @Mock +    private LongSupplier mCallDurationSupplier; +    @Mock +    private LongSupplier mScanDurationSupplier; + +    private final MobileRadioPowerStatsCollector.Injector mInjector = +            new MobileRadioPowerStatsCollector.Injector() { +                @Override +                public Handler getHandler() { +                    return mStatsRule.getHandler(); +                } + +                @Override +                public Clock getClock() { +                    return mStatsRule.getMockClock(); +                } + +                @Override +                public PowerStatsUidResolver getUidResolver() { +                    return mPowerStatsUidResolver; +                } + +                @Override +                public PackageManager getPackageManager() { +                    return mPackageManager; +                } + +                @Override +                public PowerStatsCollector.ConsumedEnergyRetriever getConsumedEnergyRetriever() { +                    return mConsumedEnergyRetriever; +                } + +                @Override +                public IntSupplier getVoltageSupplier() { +                    return () -> VOLTAGE_MV; +                } + +                @Override +                public Supplier<NetworkStats> getMobileNetworkStatsSupplier() { +                    return mNetworkStatsSupplier; +                } + +                @Override +                public TelephonyManager getTelephonyManager() { +                    return mTelephonyManager; +                } + +                @Override +                public LongSupplier getCallDurationSupplier() { +                    return mCallDurationSupplier; +                } + +                @Override +                public LongSupplier getPhoneSignalScanDurationSupplier() { +                    return mScanDurationSupplier; +                } +            }; + +    @Before +    public void setup() { +        MockitoAnnotations.initMocks(this); + +        when(mContext.getPackageManager()).thenReturn(mPackageManager); +        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true); +        when(mPowerStatsUidResolver.mapUid(anyInt())) +                .thenAnswer(invocation -> invocation.getArgument(0)); + +        // No power monitoring hardware +        when(mConsumedEnergyRetriever.getEnergyConsumerIds(EnergyConsumerType.MOBILE_RADIO)) +                .thenReturn(new int[0]); + +        mStatsRule.setTestPowerProfile("power_profile_test_legacy_modem"); +    } + +    @Test +    public void copyEstimatesFromMobileRadioPowerStats() { +        MobileRadioPowerStatsProcessor mobileStatsProcessor = +                new MobileRadioPowerStatsProcessor(mStatsRule.getPowerProfile()); + +        PhoneCallPowerStatsProcessor phoneStatsProcessor = +                new PhoneCallPowerStatsProcessor(); + +        AggregatedPowerStatsConfig aggregatedPowerStatsConfig = new AggregatedPowerStatsConfig(); +        aggregatedPowerStatsConfig.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO) +                .trackDeviceStates(STATE_POWER, STATE_SCREEN) +                .trackUidStates(STATE_POWER, STATE_SCREEN, STATE_PROCESS_STATE) +                .setProcessor(mobileStatsProcessor); +        aggregatedPowerStatsConfig.trackPowerComponent(BatteryConsumer.POWER_COMPONENT_PHONE, +                        BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO) +                .setProcessor(phoneStatsProcessor); + +        AggregatedPowerStats aggregatedPowerStats = +                new AggregatedPowerStats(aggregatedPowerStatsConfig); +        PowerComponentAggregatedPowerStats mobileRadioStats = +                aggregatedPowerStats.getPowerComponentStats( +                        BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO); + +        aggregatedPowerStats.setDeviceState(STATE_POWER, POWER_STATE_OTHER, 0); +        aggregatedPowerStats.setDeviceState(STATE_SCREEN, SCREEN_STATE_ON, 0); + +        MobileRadioPowerStatsCollector collector = new MobileRadioPowerStatsCollector(mInjector, 0); +        collector.setEnabled(true); + +        // Initial empty ModemActivityInfo. +        mockModemActivityInfo(new ModemActivityInfo(0L, 0L, 0L, new int[5], 0L)); + +        // Establish a baseline +        aggregatedPowerStats.addPowerStats(collector.collectStats(), 0); + +        // Turn the screen off after 2.5 seconds +        aggregatedPowerStats.setDeviceState(STATE_SCREEN, SCREEN_STATE_OTHER, 2500); + +        ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000, +                new int[]{100, 200, 300, 400, 500}, 600); +        mockModemActivityInfo(mai); + +        // A phone call was made +        when(mCallDurationSupplier.getAsLong()).thenReturn(7000L); + +        mStatsRule.setTime(10_000, 10_000); + +        aggregatedPowerStats.addPowerStats(collector.collectStats(), 10_000); + +        mobileStatsProcessor.finish(mobileRadioStats); + +        PowerComponentAggregatedPowerStats stats = +                aggregatedPowerStats.getPowerComponentStats(BatteryConsumer.POWER_COMPONENT_PHONE); +        phoneStatsProcessor.finish(stats); + +        PowerStatsLayout statsLayout = +                new PowerStatsLayout(stats.getPowerStatsDescriptor()); + +        long[] deviceStats = new long[stats.getPowerStatsDescriptor().statsArrayLength]; +        stats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_ON)); +        assertThat(statsLayout.getDevicePowerEstimate(deviceStats)) +                .isWithin(PRECISION).of(0.7); +        stats.getDeviceStats(deviceStats, states(POWER_STATE_OTHER, SCREEN_STATE_OTHER)); +        assertThat(statsLayout.getDevicePowerEstimate(deviceStats)) +                .isWithin(PRECISION).of(2.1); +    } + +    private void mockModemActivityInfo(ModemActivityInfo emptyMai) { +        doAnswer(invocation -> { +            OutcomeReceiver<ModemActivityInfo, TelephonyManager.ModemActivityInfoException> +                    receiver = invocation.getArgument(1); +            receiver.onResult(emptyMai); +            return null; +        }).when(mTelephonyManager).requestModemActivityInfo(any(), any()); +    } + +    private int[] states(int... states) { +        return states; +    } +} diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java index 2ea86a4527eb..3929137fa8c3 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java @@ -58,7 +58,7 @@ public class PowerStatsAggregatorTest {      @Before      public void setup() throws ParseException { -        mHistory = new BatteryStatsHistory(1024, +        mHistory = new BatteryStatsHistory(null, null, 0, 1024,                  mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class), mClock,                  mMonotonicClock, mock(BatteryStatsHistory.TraceDelegate.class), null); @@ -76,9 +76,8 @@ public class PowerStatsAggregatorTest {      @Test      public void stateUpdates() { -        PowerStats.Descriptor descriptor = -                new PowerStats.Descriptor(TEST_POWER_COMPONENT, "majorDrain", 1, 1, -                        new PersistableBundle()); +        PowerStats.Descriptor descriptor = new PowerStats.Descriptor(TEST_POWER_COMPONENT, +                "majorDrain", 1, null, 0, 1, new PersistableBundle());          PowerStats powerStats = new PowerStats(descriptor);          mClock.currentTime = 1222156800000L;    // An important date in world history @@ -186,9 +185,8 @@ public class PowerStatsAggregatorTest {      @Test      public void incompatiblePowerStats() { -        PowerStats.Descriptor descriptor = -                new PowerStats.Descriptor(TEST_POWER_COMPONENT, "majorDrain", 1, 1, -                        new PersistableBundle()); +        PowerStats.Descriptor descriptor = new PowerStats.Descriptor(TEST_POWER_COMPONENT, +                "majorDrain", 1, null, 0, 1, new PersistableBundle());          PowerStats powerStats = new PowerStats(descriptor);          mHistory.forceRecordAllHistory(); @@ -209,7 +207,7 @@ public class PowerStatsAggregatorTest {          advance(1000); -        descriptor = new PowerStats.Descriptor(TEST_POWER_COMPONENT, "majorDrain", 1, 1, +        descriptor = new PowerStats.Descriptor(TEST_POWER_COMPONENT, "majorDrain", 1, null, 0, 1,                  PersistableBundle.forPair("something", "changed"));          powerStats = new PowerStats(descriptor);          powerStats.stats = new long[]{20000}; diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java index 17a7d3ecf9d3..df1200bb6b1a 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsCollectorTest.java @@ -18,11 +18,22 @@ package com.android.server.power.stats;  import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.hardware.power.stats.EnergyConsumer; +import android.hardware.power.stats.EnergyConsumerResult; +import android.hardware.power.stats.EnergyConsumerType;  import android.os.ConditionVariable;  import android.os.Handler;  import android.os.HandlerThread;  import android.os.PersistableBundle; +import android.platform.test.annotations.DisabledOnRavenwood;  import android.platform.test.ravenwood.RavenwoodRule; +import android.power.PowerStatsInternal;  import androidx.test.filters.SmallTest;  import androidx.test.runner.AndroidJUnit4; @@ -34,6 +45,9 @@ import org.junit.Rule;  import org.junit.Test;  import org.junit.runner.RunWith; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +  @RunWith(AndroidJUnit4.class)  @SmallTest  public class PowerStatsCollectorTest { @@ -57,7 +71,8 @@ public class PowerStatsCollectorTest {                  mMockClock) {              @Override              protected PowerStats collectStats() { -                return new PowerStats(new PowerStats.Descriptor(0, 0, 0, new PersistableBundle())); +                return new PowerStats( +                        new PowerStats.Descriptor(0, 0, null, 0, 0, new PersistableBundle()));              }          };          mCollector.addConsumer(stats -> mCollectedStats = stats); @@ -92,4 +107,74 @@ public class PowerStatsCollectorTest {          mHandler.post(done::open);          done.block();      } + +    @Test +    @DisabledOnRavenwood +    public void consumedEnergyRetriever() throws Exception { +        PowerStatsInternal powerStatsInternal = mock(PowerStatsInternal.class); +        mockEnergyConsumers(powerStatsInternal); + +        PowerStatsCollector.ConsumedEnergyRetrieverImpl retriever = +                new PowerStatsCollector.ConsumedEnergyRetrieverImpl(powerStatsInternal); +        int[] energyConsumerIds = retriever.getEnergyConsumerIds(EnergyConsumerType.CPU_CLUSTER); +        assertThat(energyConsumerIds).isEqualTo(new int[]{1, 2}); +        long[] energy = retriever.getConsumedEnergyUws(energyConsumerIds); +        assertThat(energy).isEqualTo(new long[]{1000, 2000}); +        energy = retriever.getConsumedEnergyUws(energyConsumerIds); +        assertThat(energy).isEqualTo(new long[]{1500, 2700}); +    } + +    @SuppressWarnings("unchecked") +    private void mockEnergyConsumers(PowerStatsInternal powerStatsInternal) throws Exception { +        when(powerStatsInternal.getEnergyConsumerInfo()) +                .thenReturn(new EnergyConsumer[]{ +                        new EnergyConsumer() {{ +                            id = 1; +                            type = EnergyConsumerType.CPU_CLUSTER; +                            ordinal = 0; +                            name = "CPU0"; +                        }}, +                        new EnergyConsumer() {{ +                            id = 2; +                            type = EnergyConsumerType.CPU_CLUSTER; +                            ordinal = 1; +                            name = "CPU4"; +                        }}, +                        new EnergyConsumer() {{ +                            id = 3; +                            type = EnergyConsumerType.BLUETOOTH; +                            name = "BT"; +                        }}, +                }); + +        CompletableFuture<EnergyConsumerResult[]> future1 = mock(CompletableFuture.class); +        when(future1.get(anyLong(), any(TimeUnit.class))) +                .thenReturn(new EnergyConsumerResult[]{ +                        new EnergyConsumerResult() {{ +                            id = 1; +                            energyUWs = 1000; +                        }}, +                        new EnergyConsumerResult() {{ +                            id = 2; +                            energyUWs = 2000; +                        }} +                }); + +        CompletableFuture<EnergyConsumerResult[]> future2 = mock(CompletableFuture.class); +        when(future2.get(anyLong(), any(TimeUnit.class))) +                .thenReturn(new EnergyConsumerResult[]{ +                        new EnergyConsumerResult() {{ +                            id = 1; +                            energyUWs = 1500; +                        }}, +                        new EnergyConsumerResult() {{ +                            id = 2; +                            energyUWs = 2700; +                        }} +                }); + +        when(powerStatsInternal.getEnergyConsumedAsync(eq(new int[]{1, 2}))) +                .thenReturn(future1) +                .thenReturn(future2); +    }  } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java index 18d7b909150b..412fc88dcd27 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java @@ -77,7 +77,7 @@ public class PowerStatsExporterTest {      private PowerStatsStore mPowerStatsStore;      private PowerStatsAggregator mPowerStatsAggregator;      private BatteryStatsHistory mHistory; -    private CpuPowerStatsCollector.CpuStatsArrayLayout mCpuStatsArrayLayout; +    private CpuPowerStatsLayout mCpuStatsArrayLayout;      private PowerStats.Descriptor mPowerStatsDescriptor;      @Before @@ -93,7 +93,7 @@ public class PowerStatsExporterTest {                          AggregatedPowerStatsConfig.STATE_SCREEN,                          AggregatedPowerStatsConfig.STATE_PROCESS_STATE)                  .setProcessor( -                        new CpuAggregatedPowerStatsProcessor(mStatsRule.getPowerProfile(), +                        new CpuPowerStatsProcessor(mStatsRule.getPowerProfile(),                                  mStatsRule.getCpuScalingPolicies()));          mPowerStatsStore = new PowerStatsStore(storeDirectory, new TestHandler(), config); @@ -102,9 +102,10 @@ public class PowerStatsExporterTest {                  mMonotonicClock, null, null);          mPowerStatsAggregator = new PowerStatsAggregator(config, mHistory); -        mCpuStatsArrayLayout = new CpuPowerStatsCollector.CpuStatsArrayLayout(); +        mCpuStatsArrayLayout = new CpuPowerStatsLayout();          mCpuStatsArrayLayout.addDeviceSectionCpuTimeByScalingStep(1);          mCpuStatsArrayLayout.addDeviceSectionCpuTimeByCluster(1); +        mCpuStatsArrayLayout.addDeviceSectionUsageDuration();          mCpuStatsArrayLayout.addDeviceSectionPowerEstimate();          mCpuStatsArrayLayout.addUidSectionCpuTimeByPowerBracket(new int[]{0});          mCpuStatsArrayLayout.addUidSectionPowerEstimate(); @@ -113,7 +114,7 @@ public class PowerStatsExporterTest {          mPowerStatsDescriptor = new PowerStats.Descriptor(BatteryConsumer.POWER_COMPONENT_CPU,                  mCpuStatsArrayLayout.getDeviceStatsArrayLength(), -                mCpuStatsArrayLayout.getUidStatsArrayLength(), extras); +                null, 0, mCpuStatsArrayLayout.getUidStatsArrayLength(), extras);      }      @Test @@ -126,20 +127,20 @@ public class PowerStatsExporterTest {          BatteryUsageStats actual = builder.build();          String message = "Actual BatteryUsageStats: " + actual; -        assertDevicePowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 25.53); -        assertAllAppsPowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 25.53); +        assertDevicePowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 7.51016); +        assertAllAppsPowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 7.51016);          assertUidPowerEstimate(message, actual, APP_UID1, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_ANY, 13.5); +                BatteryConsumer.PROCESS_STATE_ANY, 3.97099);          assertUidPowerEstimate(message, actual, APP_UID1, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_FOREGROUND, 7.47); +                BatteryConsumer.PROCESS_STATE_FOREGROUND, 2.198082);          assertUidPowerEstimate(message, actual, APP_UID1, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_BACKGROUND, 6.03); +                BatteryConsumer.PROCESS_STATE_BACKGROUND, 1.772916);          assertUidPowerEstimate(message, actual, APP_UID2, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_ANY, 12.03); +                BatteryConsumer.PROCESS_STATE_ANY, 3.538999);          assertUidPowerEstimate(message, actual, APP_UID2, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE, 12.03); +                BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE, 3.538999);          actual.close();      } @@ -154,20 +155,20 @@ public class PowerStatsExporterTest {          BatteryUsageStats actual = builder.build();          String message = "Actual BatteryUsageStats: " + actual; -        assertDevicePowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 15.4); -        assertAllAppsPowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 15.4); +        assertDevicePowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 4.526749); +        assertAllAppsPowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 4.526749);          assertUidPowerEstimate(message, actual, APP_UID1, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_ANY, 4.06); +                BatteryConsumer.PROCESS_STATE_ANY, 1.193332);          assertUidPowerEstimate(message, actual, APP_UID1, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_FOREGROUND, 1.35); +                BatteryConsumer.PROCESS_STATE_FOREGROUND, 0.397749);          assertUidPowerEstimate(message, actual, APP_UID1, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_BACKGROUND, 2.70); +                BatteryConsumer.PROCESS_STATE_BACKGROUND, 0.795583);          assertUidPowerEstimate(message, actual, APP_UID2, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_ANY, 11.33); +                BatteryConsumer.PROCESS_STATE_ANY, 3.333249);          assertUidPowerEstimate(message, actual, APP_UID2, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE, 11.33); +                BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE, 3.333249);          actual.close();      } @@ -182,13 +183,13 @@ public class PowerStatsExporterTest {          BatteryUsageStats actual = builder.build();          String message = "Actual BatteryUsageStats: " + actual; -        assertDevicePowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 25.53); -        assertAllAppsPowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 25.53); +        assertDevicePowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 7.51016); +        assertAllAppsPowerEstimate(message, actual, BatteryConsumer.POWER_COMPONENT_CPU, 7.51016);          assertUidPowerEstimate(message, actual, APP_UID1, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_ANY, 13.5); +                BatteryConsumer.PROCESS_STATE_ANY, 3.97099);          assertUidPowerEstimate(message, actual, APP_UID2, BatteryConsumer.POWER_COMPONENT_CPU, -                BatteryConsumer.PROCESS_STATE_ANY, 12.03); +                BatteryConsumer.PROCESS_STATE_ANY, 3.538999);          UidBatteryConsumer uidScope = actual.getUidBatteryConsumers().stream()                  .filter(us -> us.getUid() == APP_UID1).findFirst().orElse(null);          // There shouldn't be any per-procstate data diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsProcessorTest.java index af83be04db7d..02e446aa1859 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/AggregatedPowerStatsProcessorTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsProcessorTest.java @@ -35,7 +35,7 @@ import java.util.Objects;  @RunWith(AndroidJUnit4.class)  @SmallTest -public class AggregatedPowerStatsProcessorTest { +public class PowerStatsProcessorTest {      @Test      public void createPowerEstimationPlan_allDeviceStatesPresentInUidStates() { @@ -44,8 +44,8 @@ public class AggregatedPowerStatsProcessorTest {                          .trackDeviceStates(STATE_POWER, STATE_SCREEN)                          .trackUidStates(STATE_POWER, STATE_SCREEN, STATE_PROCESS_STATE); -        AggregatedPowerStatsProcessor.PowerEstimationPlan plan = -                new AggregatedPowerStatsProcessor.PowerEstimationPlan(config); +        PowerStatsProcessor.PowerEstimationPlan plan = +                new PowerStatsProcessor.PowerEstimationPlan(config);          assertThat(deviceStateEstimatesToStrings(plan))                  .containsExactly("[0, 0]", "[0, 1]", "[1, 0]", "[1, 1]");          assertThat(combinedDeviceStatsToStrings(plan)) @@ -65,8 +65,8 @@ public class AggregatedPowerStatsProcessorTest {                          .trackDeviceStates(STATE_POWER, STATE_SCREEN)                          .trackUidStates(STATE_POWER, STATE_PROCESS_STATE); -        AggregatedPowerStatsProcessor.PowerEstimationPlan plan = -                new AggregatedPowerStatsProcessor.PowerEstimationPlan(config); +        PowerStatsProcessor.PowerEstimationPlan plan = +                new PowerStatsProcessor.PowerEstimationPlan(config);          assertThat(deviceStateEstimatesToStrings(plan))                  .containsExactly("[0, 0]", "[0, 1]", "[1, 0]", "[1, 1]"); @@ -81,13 +81,13 @@ public class AggregatedPowerStatsProcessorTest {      }      private static List<String> deviceStateEstimatesToStrings( -            AggregatedPowerStatsProcessor.PowerEstimationPlan plan) { +            PowerStatsProcessor.PowerEstimationPlan plan) {          return plan.deviceStateEstimations.stream()                  .map(dse -> dse.stateValues).map(Arrays::toString).toList();      }      private static List<String> combinedDeviceStatsToStrings( -            AggregatedPowerStatsProcessor.PowerEstimationPlan plan) { +            PowerStatsProcessor.PowerEstimationPlan plan) {          return plan.combinedDeviceStateEstimations.stream()                  .map(cds -> cds.deviceStateEstimations)                  .map(dses -> dses.stream() @@ -97,7 +97,7 @@ public class AggregatedPowerStatsProcessorTest {      }      private static List<String> uidStateEstimatesToStrings( -            AggregatedPowerStatsProcessor.PowerEstimationPlan plan, +            PowerStatsProcessor.PowerEstimationPlan plan,              AggregatedPowerStatsConfig.PowerComponent config) {          MultiStateStats.States[] uidStateConfig = config.getUidStateConfig();          return plan.uidStateEstimates.stream() diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServerCpuThreadReaderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServerCpuThreadReaderTest.java index 80cbe0da402e..d67d40862e95 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServerCpuThreadReaderTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServerCpuThreadReaderTest.java @@ -18,11 +18,14 @@ package com.android.server.power.stats;  import static com.google.common.truth.Truth.assertThat; +import android.platform.test.ravenwood.RavenwoodRule; +  import androidx.test.filters.SmallTest;  import androidx.test.runner.AndroidJUnit4;  import com.android.internal.os.KernelSingleProcessCpuThreadReader; +import org.junit.Rule;  import org.junit.Test;  import org.junit.runner.RunWith; @@ -30,7 +33,10 @@ import java.io.IOException;  @SmallTest  @RunWith(AndroidJUnit4.class) +@android.platform.test.annotations.DisabledOnRavenwood(reason = "Kernel dependency")  public class SystemServerCpuThreadReaderTest { +    @Rule +    public final RavenwoodRule mRavenwood = new RavenwoodRule();      @Test      public void testReadDelta() throws IOException { diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java index 8e53d5285cc4..ef0b570a1354 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java @@ -31,9 +31,10 @@ import android.os.Process;  import android.platform.test.annotations.RequiresFlagsDisabled;  import android.platform.test.flag.junit.CheckFlagsRule;  import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.platform.test.flag.junit.RavenwoodFlagsValueProvider; +import android.platform.test.ravenwood.RavenwoodRule;  import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4;  import com.android.internal.os.BinderCallsStats;  import com.android.internal.os.KernelCpuSpeedReader; @@ -46,7 +47,6 @@ import com.android.server.power.optimization.Flags;  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; @@ -55,17 +55,21 @@ import java.util.ArrayList;  import java.util.Collection;  @SmallTest -@RunWith(AndroidJUnit4.class)  @SuppressWarnings("GuardedBy")  public class SystemServicePowerCalculatorTest { -    @Rule -    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); +    @Rule(order = 0) +    public final RavenwoodRule mRavenwood = new RavenwoodRule(); + +    @Rule(order = 1) +    public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isOnRavenwood() +            ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule() +            : DeviceFlagsValueProvider.createCheckFlagsRule();      private static final double PRECISION = 0.000001;      private static final int APP_UID1 = 100;      private static final int APP_UID2 = 200; -    @Rule +    @Rule(order = 2)      public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()              .setAveragePower(PowerProfile.POWER_CPU_ACTIVE, 720)              .setCpuScalingPolicy(0, new int[]{0, 1}, new int[]{100, 200}) diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java index 4e059b4b7432..8024915692aa 100644 --- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java @@ -17,7 +17,6 @@  package com.android.server;  import static com.android.server.GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS; -import static com.android.server.GestureLauncherService.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS;  import static org.junit.Assert.assertEquals;  import static org.junit.Assert.assertFalse; @@ -773,6 +772,9 @@ public class GestureLauncherServiceTest {      @Test      public void testInterceptPowerKeyDown_triggerEmergency_fiveFastTaps_gestureIgnored() { +        when(mResources.getInteger( +                com.android.internal.R.integer.config_defaultMinEmergencyGestureTapDurationMillis)) +                .thenReturn(200);          // Trigger emergency by tapping button 5 times          long eventTime = triggerEmergencyGesture(/* tapIntervalMs= */ 1); @@ -1449,7 +1451,7 @@ public class GestureLauncherServiceTest {          long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(                  mContext.getContentResolver(),                  Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS, -                EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS); +                200);          assertTrue(intercepted);          if (tapIntervalMs * 4 > emergencyGestureTapDetectionMinTimeMs) {              assertTrue(outLaunched.value); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java index 1bf9a9d02431..5a1785175be7 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -69,10 +69,9 @@ import android.os.Handler;  import android.os.IBinder;  import android.os.LocaleList;  import android.os.UserHandle; -import android.platform.test.annotations.RequiresFlagsDisabled; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule;  import android.provider.Settings;  import android.testing.AndroidTestingRunner;  import android.testing.TestableContext; @@ -144,8 +143,7 @@ public class AccessibilityManagerServiceTest {              ApplicationProvider.getApplicationContext());      @Rule -    public final CheckFlagsRule mCheckFlagsRule = -            DeviceFlagsValueProvider.createCheckFlagsRule(); +    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();      private static final int ACTION_ID = 20;      private static final String LABEL = "label"; @@ -624,7 +622,7 @@ public class AccessibilityManagerServiceTest {      @SmallTest      @Test -    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) +    @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)      public void testOnClientChange_magnificationTwoFingerTripleTapEnabled_requestConnection() {          when(mProxyManager.canRetrieveInteractiveWindowsLocked()).thenReturn(false); @@ -642,7 +640,7 @@ public class AccessibilityManagerServiceTest {      @SmallTest      @Test -    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) +    @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)      public void testOnClientChange_magnificationTwoFingerTripleTapDisabled_requestDisconnection() {          when(mProxyManager.canRetrieveInteractiveWindowsLocked()).thenReturn(false); @@ -704,7 +702,7 @@ public class AccessibilityManagerServiceTest {      @SmallTest      @Test -    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) +    @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)      public void onClientChange_magnificationTwoFingerTripleTapDisabled_removeMagnificationButton() {          final AccessibilityUserState userState = mA11yms.mUserStates.get(                  mA11yms.getCurrentUserIdLocked()); @@ -720,7 +718,7 @@ public class AccessibilityManagerServiceTest {      @SmallTest      @Test -    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE) +    @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)      public void onClientChange_magnificationTwoFingerTripleTapEnabled_keepMagnificationButton() {          final AccessibilityUserState userState = mA11yms.mUserStates.get(                  mA11yms.getCurrentUserIdLocked()); @@ -772,7 +770,7 @@ public class AccessibilityManagerServiceTest {      @SmallTest      @Test -    @RequiresFlagsDisabled(com.android.systemui.Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG) +    @DisableFlags(com.android.systemui.Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)      public void testPerformAccessibilityShortcut_hearingAids_startActivityWithExpectedComponent() {          final AccessibilityUserState userState = mA11yms.mUserStates.get(                  mA11yms.getCurrentUserIdLocked()); @@ -790,7 +788,7 @@ public class AccessibilityManagerServiceTest {      @SmallTest      @Test -    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG) +    @EnableFlags(com.android.systemui.Flags.FLAG_HEARING_AIDS_QS_TILE_DIALOG)      public void testPerformAccessibilityShortcut_hearingAids_sendExpectedBroadcast() {          final AccessibilityUserState userState = mA11yms.mUserStates.get(                  mA11yms.getCurrentUserIdLocked()); @@ -949,7 +947,7 @@ public class AccessibilityManagerServiceTest {      }      @Test -    @RequiresFlagsEnabled(FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES) +    @EnableFlags(FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES)      public void testIsAccessibilityServiceWarningRequired_notRequiredIfAllowlisted() {          mockManageAccessibilityGranted(mTestableContext);          final AccessibilityServiceInfo info_a = mockAccessibilityServiceInfo( @@ -1008,6 +1006,33 @@ public class AccessibilityManagerServiceTest {      }      @Test +    @EnableFlags(Flags.FLAG_ENABLE_HARDWARE_SHORTCUT_DISABLES_WARNING) +    public void enableHardwareShortcutsForTargets_shortcutDialogSetting_isShown() { +        Settings.Secure.putInt( +                mTestableContext.getContentResolver(), +                Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, +                AccessibilityShortcutController.DialogStatus.NOT_SHOWN +        ); + +        mockManageAccessibilityGranted(mTestableContext); +        setupShortcutTargetServices(); +        String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(); + +        mA11yms.enableShortcutsForTargets( +                /* enable= */ true, +                UserShortcutType.HARDWARE, +                List.of(target), +                mA11yms.getCurrentUserIdLocked()); +        mTestableLooper.processAllMessages(); + +        assertThat(Settings.Secure.getInt( +                mTestableContext.getContentResolver(), +                Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, +                AccessibilityShortcutController.DialogStatus.NOT_SHOWN)) +                .isEqualTo(AccessibilityShortcutController.DialogStatus.SHOWN); +    } + +    @Test      public void enableShortcutsForTargets_disableSoftwareShortcut_shortcutTurnedOff()              throws Exception {          String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(); @@ -1341,7 +1366,7 @@ public class AccessibilityManagerServiceTest {      }      @Test -    @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)      public void notifyQuickSettingsTilesChanged_statusBarServiceNotGranted_throwsException() {          mTestableContext.getTestablePermissions().setPermission(                  Manifest.permission.STATUS_BAR_SERVICE, PackageManager.PERMISSION_DENIED); @@ -1355,7 +1380,7 @@ public class AccessibilityManagerServiceTest {      }      @Test -    @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)      public void notifyQuickSettingsTilesChanged_manageAccessibilityNotGranted_throwsException() {          mockStatusBarServiceGranted(mTestableContext);          mTestableContext.getTestablePermissions().setPermission( @@ -1369,7 +1394,7 @@ public class AccessibilityManagerServiceTest {      }      @Test -    @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)      public void notifyQuickSettingsTilesChanged_qsTileChanges_updateA11yTilesInQsPanel() {          mockStatusBarServiceGranted(mTestableContext);          mockManageAccessibilityGranted(mTestableContext); @@ -1389,7 +1414,7 @@ public class AccessibilityManagerServiceTest {      }      @Test -    @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)      public void notifyQuickSettingsTilesChanged_sameQsTiles_noUpdateToA11yTilesInQsPanel() {          notifyQuickSettingsTilesChanged_qsTileChanges_updateA11yTilesInQsPanel();          List<ComponentName> tiles = @@ -1406,7 +1431,7 @@ public class AccessibilityManagerServiceTest {      }      @Test -    @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)      public void notifyQuickSettingsTilesChanged_serviceWarningRequired_qsShortcutRemainDisabled() {          mockStatusBarServiceGranted(mTestableContext);          mockManageAccessibilityGranted(mTestableContext); @@ -1424,7 +1449,7 @@ public class AccessibilityManagerServiceTest {      }      @Test -    @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)      public void notifyQuickSettingsTilesChanged_serviceWarningNotRequired_qsShortcutEnabled() {          mockStatusBarServiceGranted(mTestableContext);          mockManageAccessibilityGranted(mTestableContext); @@ -1446,7 +1471,7 @@ public class AccessibilityManagerServiceTest {      }      @Test -    @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)      public void notifyQuickSettingsTilesChanged_addFrameworkTile_qsShortcutEnabled() {          mockStatusBarServiceGranted(mTestableContext);          mockManageAccessibilityGranted(mTestableContext); @@ -1469,7 +1494,7 @@ public class AccessibilityManagerServiceTest {      }      @Test -    @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)      public void notifyQuickSettingsTilesChanged_removeFrameworkTile_qsShortcutDisabled() {          notifyQuickSettingsTilesChanged_addFrameworkTile_qsShortcutEnabled();          Set<ComponentName> qsTiles = mA11yms.getCurrentUserState().getA11yQsTilesInQsPanel(); @@ -1487,7 +1512,7 @@ public class AccessibilityManagerServiceTest {      }      @Test -    @RequiresFlagsEnabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) +    @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)      public void restoreAccessibilityQsTargets_a11yQsTargetsRestored() {          String daltonizerTile =                  AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString(); @@ -1510,7 +1535,7 @@ public class AccessibilityManagerServiceTest {      }      @Test -    @RequiresFlagsDisabled(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT) +    @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)      public void restoreAccessibilityQsTargets_a11yQsTargetsNotRestored() {          String daltonizerTile =                  AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString(); diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java index ab36ba250986..0c92abce7254 100644 --- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java @@ -3194,6 +3194,78 @@ public class AccountManagerServiceTest extends AndroidTestCase {      }      @SmallTest +    public void testAccountsChangedBroadcastMarkedAccountAsVisibleThreeTimes() throws Exception { +        unlockSystemUser(); + +        HashMap<String, Integer> visibility = new HashMap<>(); +        visibility.put("testpackage1", AccountManager.VISIBILITY_VISIBLE); + +        addAccountRemovedReceiver("testpackage1"); +        mAms.registerAccountListener( +                new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1}, +                "testpackage1"); +        mAms.addAccountExplicitlyWithVisibility( +                AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, +                /* password= */ "p11", +                /* extras= */ null, +                visibility, +                /* callerPackage= */ null); + +        updateBroadcastCounters(2); +        assertEquals(mVisibleAccountsChangedBroadcasts, 1); +        assertEquals(mLoginAccountsChangedBroadcasts, 1); +        assertEquals(mAccountRemovedBroadcasts, 0); + +        mAms.setAccountVisibility(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, +                "testpackage1", +                AccountManager.VISIBILITY_VISIBLE); +        mAms.setAccountVisibility(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, +                "testpackage1", +                AccountManager.VISIBILITY_VISIBLE); + +        updateBroadcastCounters(2); +        assertEquals(mVisibleAccountsChangedBroadcasts, 1); +        assertEquals(mLoginAccountsChangedBroadcasts, 1); +        assertEquals(mAccountRemovedBroadcasts, 0); +    } + +    @SmallTest +    public void testAccountsChangedBroadcastChangedVisibilityTwoTimes() throws Exception { +        unlockSystemUser(); + +        HashMap<String, Integer> visibility = new HashMap<>(); +        visibility.put("testpackage1", AccountManager.VISIBILITY_VISIBLE); + +        addAccountRemovedReceiver("testpackage1"); +        mAms.registerAccountListener( +                new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1}, +                "testpackage1"); +        mAms.addAccountExplicitlyWithVisibility( +                AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, +                /* password= */ "p11", +                /* extras= */ null, +                visibility, +                /* callerPackage= */ null); + +        updateBroadcastCounters(2); +        assertEquals(mVisibleAccountsChangedBroadcasts, 1); +        assertEquals(mLoginAccountsChangedBroadcasts, 1); +        assertEquals(mAccountRemovedBroadcasts, 0); + +        mAms.setAccountVisibility(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, +                "testpackage1", +                AccountManager.VISIBILITY_NOT_VISIBLE); +        mAms.setAccountVisibility(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, +                "testpackage1", +                AccountManager.VISIBILITY_VISIBLE); + +        updateBroadcastCounters(7); +        assertEquals(mVisibleAccountsChangedBroadcasts, 3); +        assertEquals(mLoginAccountsChangedBroadcasts, 3); +        assertEquals(mAccountRemovedBroadcasts, 1); +    } + +    @SmallTest      public void testRegisterAccountListenerCredentialsUpdate() throws Exception {          unlockSystemUser();          mAms.registerAccountListener( diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java index 34092b6855b1..48f1286e29e3 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java @@ -25,6 +25,7 @@ import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_NEGAT  import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED;  import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED; +import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PAUSED;  import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED_UI_SHOWING;  import static com.android.server.biometrics.BiometricServiceStateProto.STATE_ERROR_PENDING_SYSUI; @@ -289,6 +290,44 @@ public class AuthSessionTest {      }      @Test +    public void testOnRejectionReceivedBeforeOnDialogAnimatedIn() throws RemoteException { +        final int fingerprintId = 0; +        final int faceId = 1; +        setupFingerprint(fingerprintId, FingerprintSensorProperties.TYPE_REAR); +        setupFace(faceId, false /* confirmationAlwaysRequired */, +                mock(IBiometricAuthenticator.class)); +        final AuthSession session = createAuthSession(mSensors, +                false /* checkDevicePolicyManager */, +                Authenticators.BIOMETRIC_STRONG, +                TEST_REQUEST_ID, +                0 /* operationId */, +                0 /* userId */); +        session.goToInitialState(); + +        for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) { +            assertThat(sensor.getSensorState()).isEqualTo(BiometricSensor.STATE_WAITING_FOR_COOKIE); +            session.onCookieReceived( +                    session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie()); +        } +        assertThat(session.allCookiesReceived()).isTrue(); +        assertThat(session.getState()).isEqualTo(STATE_AUTH_STARTED); + +        final BiometricSensor faceSensor = session.mPreAuthInfo.eligibleSensors.get(faceId); +        final BiometricSensor fingerprintSensor = session.mPreAuthInfo.eligibleSensors.get( +                fingerprintId); +        session.onAuthenticationRejected(faceId); + +        assertThat(faceSensor.getSensorState()).isEqualTo(BiometricSensor.STATE_CANCELING); +        assertThat(session.getState()).isEqualTo(STATE_AUTH_PAUSED); + +        session.onDialogAnimatedIn(true); + +        assertThat(session.getState()).isEqualTo(STATE_AUTH_STARTED_UI_SHOWING); +        assertThat(fingerprintSensor.getSensorState()).isEqualTo( +                BiometricSensor.STATE_AUTHENTICATING); +    } + +    @Test      public void testCancelReducesAppetiteForCookies() throws Exception {          setupFace(0 /* id */, false /* confirmationAlwaysRequired */,                  mock(IBiometricAuthenticator.class)); diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java index 4405a20cb059..b91ef7cbfff8 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java @@ -1256,6 +1256,30 @@ public final class UserManagerTest {      @MediumTest      @Test +    public void testDefaultUserRestrictionsForPrivateProfile() { +        assumeTrue(mUserManager.canAddPrivateProfile()); +        final int currentUserId = ActivityManager.getCurrentUser(); +        UserInfo privateProfileInfo = null; +        try { +            privateProfileInfo = createProfileForUser("Private", +                    UserManager.USER_TYPE_PROFILE_PRIVATE, currentUserId); +            assertThat(privateProfileInfo).isNotNull(); +        } catch (Exception e) { +            fail("Creation of private profile failed due to " + e.getMessage()); +        } +        assertDefaultPrivateProfileRestrictions(privateProfileInfo.getUserHandle()); +    } + +    private void assertDefaultPrivateProfileRestrictions(UserHandle userHandle) { +        Bundle defaultPrivateProfileRestrictions = +                UserTypeFactory.getDefaultPrivateProfileRestrictions(); +        for (String restriction : defaultPrivateProfileRestrictions.keySet()) { +            assertThat(mUserManager.hasUserRestrictionForUser(restriction, userHandle)).isTrue(); +        } +    } + +    @MediumTest +    @Test      public void testAddRestrictedProfile() throws Exception {          if (isAutomotive() || UserManager.isHeadlessSystemUserMode()) return;          assertWithMessage("There should be no associated restricted profiles before the test") 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 610627886c1b..4a61d32d00b2 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -7916,8 +7916,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          setAppInForegroundForToasts(mUid, true);          // enqueue toast -> toast should still enqueue -        enqueueToast(testPackage, new TestableToastCallback()); +        boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());          assertEquals(1, mService.mToastQueue.size()); +        assertThat(wasEnqueued).isTrue();      }      @Test @@ -7936,8 +7937,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          setAppInForegroundForToasts(mUid, false);          // enqueue toast -> no toasts enqueued -        enqueueToast(testPackage, new TestableToastCallback()); +        boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());          assertEquals(0, mService.mToastQueue.size()); +        assertThat(wasEnqueued).isFalse();      }      @Test @@ -8045,8 +8047,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          setAppInForegroundForToasts(mUid, true);          // enqueue toast -> toast should still enqueue -        enqueueTextToast(testPackage, "Text"); +        boolean wasEnqueued = enqueueTextToast(testPackage, "Text");          assertEquals(1, mService.mToastQueue.size()); +        assertThat(wasEnqueued).isTrue();      }      @Test @@ -8065,8 +8068,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          setAppInForegroundForToasts(mUid, false);          // enqueue toast -> toast should still enqueue -        enqueueTextToast(testPackage, "Text"); +        boolean wasEnqueued = enqueueTextToast(testPackage, "Text");          assertEquals(1, mService.mToastQueue.size()); +        assertThat(wasEnqueued).isTrue();      }      @Test @@ -8220,8 +8224,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          setAppInForegroundForToasts(mUid, false);          // enqueue toast -> toast should still enqueue -        enqueueToast(testPackage, new TestableToastCallback()); +        boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());          assertEquals(1, mService.mToastQueue.size()); +        assertThat(wasEnqueued).isTrue();          verify(mAm).setProcessImportant(any(), anyInt(), eq(true), any());      } @@ -8242,8 +8247,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          setAppInForegroundForToasts(mUid, true);          // enqueue toast -> toast should still enqueue -        enqueueTextToast(testPackage, "Text"); +        boolean wasEnqueued = enqueueTextToast(testPackage, "Text");          assertEquals(1, mService.mToastQueue.size()); +        assertThat(wasEnqueued).isTrue();          verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any());      } @@ -8264,8 +8270,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          setAppInForegroundForToasts(mUid, false);          // enqueue toast -> toast should still enqueue -        enqueueTextToast(testPackage, "Text"); +        boolean wasEnqueued = enqueueTextToast(testPackage, "Text");          assertEquals(1, mService.mToastQueue.size()); +        assertThat(wasEnqueued).isTrue();          verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any());      } @@ -8274,7 +8281,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          allowTestPackageToToast();          // enqueue toast -> no toasts enqueued -        enqueueTextToast(TEST_PACKAGE, "Text"); +        boolean wasEnqueued = enqueueTextToast(TEST_PACKAGE, "Text"); +        assertThat(wasEnqueued).isTrue();          verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY);      } @@ -8367,10 +8375,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {                  .thenReturn(false);          // enqueue toast -> no toasts enqueued -        enqueueTextToast(testPackage, "Text"); +        boolean wasEnqueued = enqueueTextToast(testPackage, "Text");          verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),                  anyInt());          assertEquals(0, mService.mToastQueue.size()); +        assertThat(wasEnqueued).isFalse();      }      @Test @@ -8390,10 +8399,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);          // enqueue toast -> no toasts enqueued -        enqueueToast(testPackage, new TestableToastCallback()); +        boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());          verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(),                  anyInt());          assertEquals(0, mService.mToastQueue.size()); +        assertThat(wasEnqueued).isFalse();      }      @Test @@ -8415,8 +8425,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          setAppInForegroundForToasts(mUid, false);          // enqueue toast -> no toasts enqueued -        enqueueToast(testPackage, new TestableToastCallback()); +        boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());          assertEquals(0, mService.mToastQueue.size()); +        assertThat(wasEnqueued).isFalse();      }      @Test @@ -8437,8 +8448,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          setAppInForegroundForToasts(mUid, false);          // enqueue toast -> system toast can still be enqueued -        enqueueToast(testPackage, new TestableToastCallback()); +        boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback());          assertEquals(1, mService.mToastQueue.size()); +        assertThat(wasEnqueued).isTrue();      }      @Test @@ -8458,7 +8470,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {          // Trying to quickly enqueue more toast than allowed.          for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS + 1; i++) { -            enqueueTextToast(testPackage, "Text"); +            boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); +            if (i < NotificationManagerService.MAX_PACKAGE_TOASTS) { +                assertThat(wasEnqueued).isTrue(); +            } else { +                assertThat(wasEnqueued).isFalse(); +            }          }          // Only allowed number enqueued, rest ignored.          assertEquals(NotificationManagerService.MAX_PACKAGE_TOASTS, mService.mToastQueue.size()); @@ -13994,6 +14011,314 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {      }      @Test +    @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) +    public void enqueueNotification_acceptsCorrectToken() throws RemoteException { +        Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID) +                .setContentIntent(createPendingIntent("content")) +                .build(); +        Notification received = parcelAndUnparcel(sent, Notification.CREATOR); +        assertThat(received.getAllowlistToken()).isEqualTo( +                NotificationManagerService.ALLOWLIST_TOKEN); + +        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, +                parcelAndUnparcel(received, Notification.CREATOR), mUserId); +        waitForIdle(); + +        assertThat(mService.mNotificationList).hasSize(1); +        assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken()) +                .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN); +    } + +    @Test +    @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) +    public void enqueueNotification_acceptsNullToken_andPopulatesIt() throws RemoteException { +        Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID) +                .setContentIntent(createPendingIntent("content")) +                .build(); +        assertThat(receivedWithoutParceling.getAllowlistToken()).isNull(); + +        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, +                parcelAndUnparcel(receivedWithoutParceling, Notification.CREATOR), mUserId); +        waitForIdle(); + +        assertThat(mService.mNotificationList).hasSize(1); +        assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken()) +                .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN); +    } + +    @Test +    @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) +    public void enqueueNotification_rejectsOtherToken() throws RemoteException { +        Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID) +                .setContentIntent(createPendingIntent("content")) +                .build(); +        sent.overrideAllowlistToken(new Binder()); +        Notification received = parcelAndUnparcel(sent, Notification.CREATOR); +        assertThat(received.getAllowlistToken()).isEqualTo(sent.getAllowlistToken()); + +        assertThrows(SecurityException.class, () -> +                mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, +                        parcelAndUnparcel(received, Notification.CREATOR), mUserId)); +        waitForIdle(); + +        assertThat(mService.mNotificationList).isEmpty(); +    } + +    @Test +    @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) +    public void enqueueNotification_customParcelingWithFakeInnerToken_hasCorrectTokenInIntents() +            throws RemoteException { +        Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID) +                .setContentIntent(createPendingIntent("content")) +                .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID) +                        .setContentIntent(createPendingIntent("public")) +                        .build()) +                .build(); +        sentFromApp.publicVersion.overrideAllowlistToken(new Binder()); + +        // Instead of using the normal parceling, assume the caller parcels it by hand, including a +        // null token in the outer notification (as would be expected, and as is verified by +        // enqueue) but trying to sneak in a different one in the inner notification, hoping it gets +        // propagated to the PendingIntents. +        Parcel parcelSentFromApp = Parcel.obtain(); +        writeNotificationToParcelCustom(parcelSentFromApp, sentFromApp, new ArraySet<>( +                Lists.newArrayList(sentFromApp.contentIntent, +                        sentFromApp.publicVersion.contentIntent))); + +        // Use the unparceling as received in enqueueNotificationWithTag() +        parcelSentFromApp.setDataPosition(0); +        Notification receivedByNms = new Notification(parcelSentFromApp); + +        // Verify that all the pendingIntents have the correct token. +        assertThat(receivedByNms.contentIntent.getWhitelistToken()).isEqualTo( +                NotificationManagerService.ALLOWLIST_TOKEN); +        assertThat(receivedByNms.publicVersion.contentIntent.getWhitelistToken()).isEqualTo( +                NotificationManagerService.ALLOWLIST_TOKEN); +    } + +    /** +     * Replicates the behavior of {@link Notification#writeToParcel} but excluding the +     * "always use the same allowlist token as the root notification" parts. +     */ +    private static void writeNotificationToParcelCustom(Parcel parcel, Notification notif, +            ArraySet<PendingIntent> allPendingIntents) { +        int flags = 0; +        parcel.writeInt(1); // version? + +        parcel.writeStrongBinder(notif.getAllowlistToken()); +        parcel.writeLong(notif.when); +        parcel.writeLong(notif.creationTime); +        if (notif.getSmallIcon() != null) { +            parcel.writeInt(1); +            notif.getSmallIcon().writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } +        parcel.writeInt(notif.number); +        if (notif.contentIntent != null) { +            parcel.writeInt(1); +            notif.contentIntent.writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } +        if (notif.deleteIntent != null) { +            parcel.writeInt(1); +            notif.deleteIntent.writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } +        if (notif.tickerText != null) { +            parcel.writeInt(1); +            TextUtils.writeToParcel(notif.tickerText, parcel, flags); +        } else { +            parcel.writeInt(0); +        } +        if (notif.tickerView != null) { +            parcel.writeInt(1); +            notif.tickerView.writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } +        if (notif.contentView != null) { +            parcel.writeInt(1); +            notif.contentView.writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } +        if (notif.getLargeIcon() != null) { +            parcel.writeInt(1); +            notif.getLargeIcon().writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } + +        parcel.writeInt(notif.defaults); +        parcel.writeInt(notif.flags); + +        if (notif.sound != null) { +            parcel.writeInt(1); +            notif.sound.writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } +        parcel.writeInt(notif.audioStreamType); + +        if (notif.audioAttributes != null) { +            parcel.writeInt(1); +            notif.audioAttributes.writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } + +        parcel.writeLongArray(notif.vibrate); +        parcel.writeInt(notif.ledARGB); +        parcel.writeInt(notif.ledOnMS); +        parcel.writeInt(notif.ledOffMS); +        parcel.writeInt(notif.iconLevel); + +        if (notif.fullScreenIntent != null) { +            parcel.writeInt(1); +            notif.fullScreenIntent.writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } + +        parcel.writeInt(notif.priority); + +        parcel.writeString8(notif.category); + +        parcel.writeString8(notif.getGroup()); + +        parcel.writeString8(notif.getSortKey()); + +        parcel.writeBundle(notif.extras); // null ok + +        parcel.writeTypedArray(notif.actions, 0); // null ok + +        if (notif.bigContentView != null) { +            parcel.writeInt(1); +            notif.bigContentView.writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } + +        if (notif.headsUpContentView != null) { +            parcel.writeInt(1); +            notif.headsUpContentView.writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } + +        parcel.writeInt(notif.visibility); + +        if (notif.publicVersion != null) { +            parcel.writeInt(1); +            writeNotificationToParcelCustom(parcel, notif.publicVersion, new ArraySet<>()); +        } else { +            parcel.writeInt(0); +        } + +        parcel.writeInt(notif.color); + +        if (notif.getChannelId() != null) { +            parcel.writeInt(1); +            parcel.writeString8(notif.getChannelId()); +        } else { +            parcel.writeInt(0); +        } +        parcel.writeLong(notif.getTimeoutAfter()); + +        if (notif.getShortcutId() != null) { +            parcel.writeInt(1); +            parcel.writeString8(notif.getShortcutId()); +        } else { +            parcel.writeInt(0); +        } + +        if (notif.getLocusId() != null) { +            parcel.writeInt(1); +            notif.getLocusId().writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } + +        parcel.writeInt(notif.getBadgeIconType()); + +        if (notif.getSettingsText() != null) { +            parcel.writeInt(1); +            TextUtils.writeToParcel(notif.getSettingsText(), parcel, flags); +        } else { +            parcel.writeInt(0); +        } + +        parcel.writeInt(notif.getGroupAlertBehavior()); + +        if (notif.getBubbleMetadata() != null) { +            parcel.writeInt(1); +            notif.getBubbleMetadata().writeToParcel(parcel, 0); +        } else { +            parcel.writeInt(0); +        } + +        parcel.writeBoolean(notif.getAllowSystemGeneratedContextualActions()); + +        parcel.writeInt(Notification.FOREGROUND_SERVICE_DEFAULT); // no getter for mFgsDeferBehavior + +        // mUsesStandardHeader is not written because it should be recomputed in listeners + +        parcel.writeArraySet(allPendingIntents); +    } + +    @Test +    @SuppressWarnings("unchecked") +    @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) +    public void getActiveNotifications_doesNotLeakAllowlistToken() throws RemoteException { +        Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID) +                .setContentIntent(createPendingIntent("content")) +                .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID) +                        .setContentIntent(createPendingIntent("public")) +                        .build()) +                .extend(new Notification.WearableExtender() +                        .addPage(new Notification.Builder(mContext, TEST_CHANNEL_ID) +                                .setContentIntent(createPendingIntent("wearPage")) +                                .build())) +                .build(); +        // Binder transition: app -> NMS +        Notification receivedByNms = parcelAndUnparcel(sentFromApp, Notification.CREATOR); +        assertThat(receivedByNms.getAllowlistToken()).isEqualTo( +                NotificationManagerService.ALLOWLIST_TOKEN); +        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, +                parcelAndUnparcel(receivedByNms, Notification.CREATOR), mUserId); +        waitForIdle(); +        assertThat(mService.mNotificationList).hasSize(1); +        Notification posted = mService.mNotificationList.get(0).getNotification(); +        assertThat(posted.getAllowlistToken()).isEqualTo( +                NotificationManagerService.ALLOWLIST_TOKEN); +        assertThat(posted.contentIntent.getWhitelistToken()).isEqualTo( +                NotificationManagerService.ALLOWLIST_TOKEN); + +        ParceledListSlice<StatusBarNotification> listSentFromNms = +                mBinderService.getAppActiveNotifications(mPkg, mUserId); +        // Binder transition: NMS -> app. App doesn't have the allowlist token so clear it +        // (having a different one would produce the same effect; the relevant thing is to not let +        // out ALLOWLIST_TOKEN). +        // Note: for other tests, this is restored by constructing TestableNMS in setup(). +        Notification.processAllowlistToken = null; +        ParceledListSlice<StatusBarNotification> listReceivedByApp = parcelAndUnparcel( +                listSentFromNms, ParceledListSlice.CREATOR); +        Notification gottenBackByApp = listReceivedByApp.getList().get(0).getNotification(); + +        assertThat(gottenBackByApp.getAllowlistToken()).isNull(); +        assertThat(gottenBackByApp.contentIntent.getWhitelistToken()).isNull(); +        assertThat(gottenBackByApp.publicVersion.getAllowlistToken()).isNull(); +        assertThat(gottenBackByApp.publicVersion.contentIntent.getWhitelistToken()).isNull(); +        assertThat(new Notification.WearableExtender(gottenBackByApp).getPages() +                .get(0).getAllowlistToken()).isNull(); +        assertThat(new Notification.WearableExtender(gottenBackByApp).getPages() +                .get(0).contentIntent.getWhitelistToken()).isNull(); +    } + +    @Test      public void enqueueNotification_allowlistsPendingIntents() throws RemoteException {          PendingIntent contentIntent = createPendingIntent("content");          PendingIntent actionIntent1 = createPendingIntent("action1"); @@ -15089,25 +15414,27 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {                  .thenReturn(false);      } -    private void enqueueToast(String testPackage, ITransientNotification callback) +    private boolean enqueueToast(String testPackage, ITransientNotification callback)              throws RemoteException { -        enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(), callback); +        return enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(), +                callback);      } -    private void enqueueToast(INotificationManager service, String testPackage, +    private boolean enqueueToast(INotificationManager service, String testPackage,              IBinder token, ITransientNotification callback) throws RemoteException { -        service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */ true, -                DEFAULT_DISPLAY); +        return service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */ +                true, DEFAULT_DISPLAY);      } -    private void enqueueTextToast(String testPackage, CharSequence text) throws RemoteException { -        enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY); +    private boolean enqueueTextToast(String testPackage, CharSequence text) throws RemoteException { +        return enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY);      } -    private void enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, +    private boolean enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext,              int displayId) throws RemoteException { -        ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(), text, -                TOAST_DURATION, isUiContext, displayId, /* textCallback= */ null); +        return ((INotificationManager) mService.mService).enqueueTextToast(testPackage, +                new Binder(), text, TOAST_DURATION, isUiContext, displayId, +                /* textCallback= */ null);      }      private void mockIsVisibleBackgroundUsersSupported(boolean supported) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 3df52c75b52e..43f24750ddef 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -3655,6 +3655,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {          // Create immersive rule          AutomaticZenRule immersive = new AutomaticZenRule.Builder("Immersed", CONDITION_ID)                  .setType(TYPE_IMMERSIVE) +                .setZenPolicy(mZenModeHelper.mConfig.toZenPolicy()) // same as the manual rule                  .build();          String immersiveId = mZenModeHelper.addAutomaticZenRule(mPkg, immersive, UPDATE_ORIGIN_APP,                  "reason", CUSTOM_PKG_UID); @@ -4242,6 +4243,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {      public void updateAutomaticZenRule_fromUser_updatesBitmaskAndValue() {          // Adds a starting rule with empty zen policies and device effects          AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID) +                .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)                  .setZenPolicy(new ZenPolicy.Builder().build())                  .setDeviceEffects(new ZenDeviceEffects.Builder().build())                  .build(); @@ -4250,7 +4252,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {                  azrBase, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID);          AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId); -        // Modifies the zen policy and device effects +        // Modifies the filter, zen policy, and device effects          ZenPolicy policy = new ZenPolicy.Builder(rule.getZenPolicy())                  .allowPriorityChannels(false)                  .build(); diff --git a/services/tests/vibrator/AndroidManifest.xml b/services/tests/vibrator/AndroidManifest.xml index a14ea5598758..c0f514fb9673 100644 --- a/services/tests/vibrator/AndroidManifest.xml +++ b/services/tests/vibrator/AndroidManifest.xml @@ -30,6 +30,8 @@      <uses-permission android:name="android.permission.ACCESS_VIBRATOR_STATE" />      <!-- Required to set always-on vibrations -->      <uses-permission android:name="android.permission.VIBRATE_ALWAYS_ON" /> +    <!-- Required to play system-only haptic feedback constants --> +    <uses-permission android:name="android.permission.VIBRATE_SYSTEM_CONSTANTS" />      <application android:debuggable="true">          <uses-library android:name="android.test.mock" android:required="true" /> diff --git a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java index e3d45967848a..633a3c985b7f 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java @@ -27,6 +27,8 @@ import static android.os.VibrationEffect.Composition.PRIMITIVE_TICK;  import static android.os.VibrationEffect.EFFECT_CLICK;  import static android.os.VibrationEffect.EFFECT_TEXTURE_TICK;  import static android.os.VibrationEffect.EFFECT_TICK; +import static android.view.HapticFeedbackConstants.BIOMETRIC_CONFIRM; +import static android.view.HapticFeedbackConstants.BIOMETRIC_REJECT;  import static android.view.HapticFeedbackConstants.CLOCK_TICK;  import static android.view.HapticFeedbackConstants.CONTEXT_CLICK;  import static android.view.HapticFeedbackConstants.KEYBOARD_RELEASE; @@ -80,6 +82,8 @@ public class HapticFeedbackVibrationProviderTest {              new int[] {SCROLL_ITEM_FOCUS, SCROLL_LIMIT, SCROLL_TICK};      private static final int[] KEYBOARD_FEEDBACK_CONSTANTS =              new int[] {KEYBOARD_TAP, KEYBOARD_RELEASE}; +    private static final int[] BIOMETRIC_FEEDBACK_CONSTANTS = +            new int[] {BIOMETRIC_CONFIRM, BIOMETRIC_REJECT};      private static final float KEYBOARD_VIBRATION_FIXED_AMPLITUDE = 0.62f; @@ -283,6 +287,17 @@ public class HapticFeedbackVibrationProviderTest {      }      @Test +    public void testVibrationAttribute_biometricConstants_returnsCommunicationRequestUsage() { +        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations(); + +        for (int effectId : BIOMETRIC_FEEDBACK_CONSTANTS) { +            VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback( +                    effectId, /* bypassVibrationIntensitySetting= */ false, /* fromIme= */ false); +            assertThat(attrs.getUsage()).isEqualTo(VibrationAttributes.USAGE_COMMUNICATION_REQUEST); +        } +    } + +    @Test      public void testVibrationAttribute_forNotBypassingIntensitySettings() {          HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations(); @@ -422,6 +437,15 @@ public class HapticFeedbackVibrationProviderTest {          }      } +    @Test +    public void testIsRestricted_biometricConstants_returnsTrue() { +        HapticFeedbackVibrationProvider hapticProvider = createProviderWithDefaultCustomizations(); + +        for (int effectId : BIOMETRIC_FEEDBACK_CONSTANTS) { +            assertThat(hapticProvider.isRestrictedHapticFeedback(effectId)).isTrue(); +        } +    } +      private HapticFeedbackVibrationProvider createProviderWithDefaultCustomizations() {          return createProvider(/* customizations= */ null);      } diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java index 185677f966a4..d6c0fef9649a 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -1410,6 +1410,70 @@ public class VibratorManagerServiceTest {      }      @Test +    public void performHapticFeedback_restrictedConstantsWithoutPermission_doesNotVibrate() +            throws Exception { +        // Deny permission to vibrate with restricted constants +        denyPermission(android.Manifest.permission.VIBRATE_SYSTEM_CONSTANTS); +        // Public constant, no permission required +        mHapticFeedbackVibrationMap.put( +                HapticFeedbackConstants.CONFIRM, +                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); +        // Hidden system-only constant, permission required +        mHapticFeedbackVibrationMap.put( +                HapticFeedbackConstants.BIOMETRIC_CONFIRM, +                VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK)); +        mockVibrators(1); +        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); +        fakeVibrator.setSupportedEffects( +                VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_HEAVY_CLICK); +        VibratorManagerService service = createSystemReadyService(); + +        performHapticFeedbackAndWaitUntilFinished( +                service, HapticFeedbackConstants.CONFIRM, /* always= */ false); + +        performHapticFeedbackAndWaitUntilFinished( +                service, HapticFeedbackConstants.BIOMETRIC_CONFIRM, /* always= */ false); + +        List<VibrationEffectSegment> playedSegments = fakeVibrator.getAllEffectSegments(); +        assertEquals(1, playedSegments.size()); +        PrebakedSegment segment = (PrebakedSegment) playedSegments.get(0); +        assertEquals(VibrationEffect.EFFECT_CLICK, segment.getEffectId()); +    } + +    @Test +    public void performHapticFeedback_restrictedConstantsWithPermission_playsVibration() +            throws Exception { +        // Grant permission to vibrate with restricted constants +        grantPermission(android.Manifest.permission.VIBRATE_SYSTEM_CONSTANTS); +        // Public constant, no permission required +        mHapticFeedbackVibrationMap.put( +                HapticFeedbackConstants.CONFIRM, +                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)); +        // Hidden system-only constant, permission required +        mHapticFeedbackVibrationMap.put( +                HapticFeedbackConstants.BIOMETRIC_CONFIRM, +                VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK)); +        mockVibrators(1); +        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); +        fakeVibrator.setSupportedEffects( +                VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_HEAVY_CLICK); +        VibratorManagerService service = createSystemReadyService(); + +        performHapticFeedbackAndWaitUntilFinished( +                service, HapticFeedbackConstants.CONFIRM, /* always= */ false); + +        performHapticFeedbackAndWaitUntilFinished( +                service, HapticFeedbackConstants.BIOMETRIC_CONFIRM, /* always= */ false); + +        List<VibrationEffectSegment> playedSegments = fakeVibrator.getAllEffectSegments(); +        assertEquals(2, playedSegments.size()); +        assertEquals(VibrationEffect.EFFECT_CLICK, +                ((PrebakedSegment) playedSegments.get(0)).getEffectId()); +        assertEquals(VibrationEffect.EFFECT_HEAVY_CLICK, +                ((PrebakedSegment) playedSegments.get(1)).getEffectId()); +    } + +    @Test      public void performHapticFeedback_doesNotVibrateWhenVibratorInfoNotReady() throws Exception {          denyPermission(android.Manifest.permission.VIBRATE);          mHapticFeedbackVibrationMap.put( diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java index 80e169d8d579..b90fa21cb2b1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java @@ -25,6 +25,8 @@ import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_RE  import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;  import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP; +import static com.android.server.wm.testing.Assert.assertThrows; +  import static org.mockito.ArgumentMatchers.anyInt;  import static org.mockito.ArgumentMatchers.eq;  import static org.mockito.Mockito.mock; @@ -37,6 +39,8 @@ import android.platform.test.annotations.Presubmit;  import androidx.test.filters.SmallTest; +import com.android.server.wm.testing.Assert; +  import org.junit.Before;  import org.junit.Test; @@ -288,4 +292,56 @@ public class LetterboxConfigurationTest {                  false /* forTabletopMode */,                  LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);      } + +    @Test +    public void test_setLetterboxHorizontalPositionMultiplier_validValues() { +        assertThrows(IllegalArgumentException.class, +                () -> mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(-1)); +        assertThrows(IllegalArgumentException.class, +                () -> mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(2)); + +        // Does not throw an exception for values [0,1]. +        mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(0); +        mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(0.5f); +        mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(1); +    } + +    @Test +    public void test_setLetterboxVerticalPositionMultiplier_validValues() { +        assertThrows(IllegalArgumentException.class, +                () -> mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(-1)); +        assertThrows(IllegalArgumentException.class, +                () -> mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(2)); + +        // Does not throw an exception for values [0,1]. +        mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0); +        mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f); +        mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(1); +    } + +    @Test +    public void test_setLetterboxBookModePositionMultiplier_validValues() { +        assertThrows(IllegalArgumentException.class, +                () -> mLetterboxConfiguration.setLetterboxBookModePositionMultiplier(-1)); +        assertThrows(IllegalArgumentException.class, +                () -> mLetterboxConfiguration.setLetterboxBookModePositionMultiplier(2)); + +        // Does not throw an exception for values [0,1]. +        mLetterboxConfiguration.setLetterboxBookModePositionMultiplier(0); +        mLetterboxConfiguration.setLetterboxBookModePositionMultiplier(0.5f); +        mLetterboxConfiguration.setLetterboxBookModePositionMultiplier(1); +    } + +    @Test +    public void test_setLetterboxTabletopModePositionMultiplier_validValues() { +        assertThrows(IllegalArgumentException.class, +                () -> mLetterboxConfiguration.setLetterboxTabletopModePositionMultiplier(-1)); +        assertThrows(IllegalArgumentException.class, +                () -> mLetterboxConfiguration.setLetterboxTabletopModePositionMultiplier(2)); + +        // Does not throw an exception for values [0,1]. +        mLetterboxConfiguration.setLetterboxTabletopModePositionMultiplier(0); +        mLetterboxConfiguration.setLetterboxTabletopModePositionMultiplier(0.5f); +        mLetterboxConfiguration.setLetterboxTabletopModePositionMultiplier(1); +    }  } 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 856ad2a02444..2e80bc721c7f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -130,6 +130,7 @@ import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;  import org.junit.After;  import org.junit.Before; +import org.junit.Ignore;  import org.junit.Rule;  import org.junit.Test;  import org.junit.rules.TestRule; @@ -2363,6 +2364,92 @@ public class SizeCompatTests extends WindowTestsBase {      }      @Test +    public void testUserOverrideFullscreenForLandscapeDisplay() { +        final int displayWidth = 1600; +        final int displayHeight = 1400; +        setUpDisplaySizeWithApp(displayWidth, displayHeight); +        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); +        spyOn(mActivity.mWmService.mLetterboxConfiguration); +        doReturn(true).when(mActivity.mWmService.mLetterboxConfiguration) +                .isUserAppAspectRatioFullscreenEnabled(); + +        // Set user aspect ratio override +        spyOn(mActivity.mLetterboxUiController); +        doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN).when(mActivity.mLetterboxUiController) +                .getUserMinAspectRatioOverrideCode(); + +        prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_PORTRAIT); + +        final Rect bounds = mActivity.getBounds(); + +        // bounds should be fullscreen +        assertEquals(displayHeight, bounds.height()); +        assertEquals(displayWidth, bounds.width()); +    } + +    @Test +    public void testUserOverrideFullscreenForPortraitDisplay() { +        final int displayWidth = 1400; +        final int displayHeight = 1600; +        setUpDisplaySizeWithApp(displayWidth, displayHeight); +        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); +        spyOn(mActivity.mWmService.mLetterboxConfiguration); +        doReturn(true).when(mActivity.mWmService.mLetterboxConfiguration) +                .isUserAppAspectRatioFullscreenEnabled(); + +        // Set user aspect ratio override +        spyOn(mActivity.mLetterboxUiController); +        doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN).when(mActivity.mLetterboxUiController) +                .getUserMinAspectRatioOverrideCode(); + +        prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_LANDSCAPE); + +        final Rect bounds = mActivity.getBounds(); + +        // bounds should be fullscreen +        assertEquals(displayHeight, bounds.height()); +        assertEquals(displayWidth, bounds.width()); +    } + +    @Test +    public void testSystemFullscreenOverrideForLandscapeDisplay() { +        final int displayWidth = 1600; +        final int displayHeight = 1400; +        setUpDisplaySizeWithApp(displayWidth, displayHeight); +        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); +        spyOn(mActivity.mLetterboxUiController); +        doReturn(true).when(mActivity.mLetterboxUiController) +                .isSystemOverrideToFullscreenEnabled(); + +        prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_PORTRAIT); + +        final Rect bounds = mActivity.getBounds(); + +        // bounds should be fullscreen +        assertEquals(displayHeight, bounds.height()); +        assertEquals(displayWidth, bounds.width()); +    } + +    @Test +    public void testSystemFullscreenOverrideForPortraitDisplay() { +        final int displayWidth = 1400; +        final int displayHeight = 1600; +        setUpDisplaySizeWithApp(displayWidth, displayHeight); +        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); +        spyOn(mActivity.mLetterboxUiController); +        doReturn(true).when(mActivity.mLetterboxUiController) +                .isSystemOverrideToFullscreenEnabled(); + +        prepareMinAspectRatio(mActivity, 16 / 9f, SCREEN_ORIENTATION_LANDSCAPE); + +        final Rect bounds = mActivity.getBounds(); + +        // bounds should be fullscreen +        assertEquals(displayHeight, bounds.height()); +        assertEquals(displayWidth, bounds.width()); +    } + +    @Test      public void testUserOverrideSplitScreenAspectRatioForLandscapeDisplay() {          final int displayWidth = 1600;          final int displayHeight = 1400; @@ -4056,31 +4143,6 @@ public class SizeCompatTests extends WindowTestsBase {      }      @Test -    public void testUpdateResolvedBoundsHorizontalPosition_invalidMultiplier_defaultToCenter() { -        // Display configured as (2800, 1400). - -        // Below 0.0. -        assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( -                /* letterboxHorizontalPositionMultiplier */ -1.0f, -                // At launch. -                /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400), -                // After 90 degree rotation. -                /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400), -                // After the display is resized to (700, 1400). -                /* sizeCompatScaled */ new Rect(525, 0, 875, 700)); - -        // Above 1.0 -        assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( -                /* letterboxHorizontalPositionMultiplier */ 2.0f, -                // At launch. -                /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400), -                // After 90 degree rotation. -                /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400), -                // After the display is resized to (700, 1400). -                /* sizeCompatScaled */ new Rect(525, 0, 875, 700)); -    } - -    @Test      public void testUpdateResolvedBoundsHorizontalPosition_right() {          // Display configured as (2800, 1400).          assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( @@ -4117,6 +4179,7 @@ public class SizeCompatTests extends WindowTestsBase {      }      @Test +    @Ignore // TODO(b/330888878): fix test in main      public void testPortraitCloseToSquareDisplayWithTaskbar_notLetterboxed() {          if (Flags.insetsDecoupledConfiguration()) {              // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config @@ -4310,31 +4373,6 @@ public class SizeCompatTests extends WindowTestsBase {      }      @Test -    public void testUpdateResolvedBoundsVerticalPosition_invalidMultiplier_defaultToCenter() { -        // Display configured as (1400, 2800). - -        // Below 0.0. -        assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity( -                /* letterboxVerticalPositionMultiplier */ -1.0f, -                // At launch. -                /* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750), -                // After 90 degree rotation. -                /* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050), -                // After the display is resized to (1400, 700). -                /* sizeCompatScaled */ new Rect(0, 525, 700, 875)); - -        // Above 1.0 -        assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity( -                /* letterboxVerticalPositionMultiplier */ 2.0f, -                // At launch. -                /* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750), -                // After 90 degree rotation. -                /* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050), -                // After the display is resized to (1400, 700). -                /* sizeCompatScaled */ new Rect(0, 525, 700, 875)); -    } - -    @Test      public void testUpdateResolvedBoundsVerticalPosition_bottom() {          // Display configured as (1400, 2800).          assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity( diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 018600641853..42fe3a747b64 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -1630,6 +1630,7 @@ public class TransitionTests extends WindowTestsBase {          assertTrue(controller.mWaitingTransitions.contains(transition));          assertTrue(controller.isTransientHide(appTask));          assertTrue(controller.isTransientVisible(appTask)); +        assertTrue(controller.isTransientLaunch(recent));      }      @Test 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 ec2c968a8a0a..50db99ea6dfc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -1162,7 +1162,8 @@ public class WindowManagerServiceTests extends WindowTestsBase {              invocationOnMock.callRealMethod();              return null;          }).when(surface).lockCanvas(any()); -        mWm.mAccessibilityController.drawMagnifiedRegionBorderIfNeeded(displayId); +        mWm.mAccessibilityController +                .recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded(displayId);          waitUntilHandlersIdle();          try {              verify(surface).lockCanvas(any()); @@ -1170,7 +1171,8 @@ public class WindowManagerServiceTests extends WindowTestsBase {              clearInvocations(surface);              // Invalidate and redraw.              mWm.mAccessibilityController.onDisplaySizeChanged(mDisplayContent); -            mWm.mAccessibilityController.drawMagnifiedRegionBorderIfNeeded(displayId); +            mWm.mAccessibilityController +                    .recomputeMagnifiedRegionAndDrawMagnifiedRegionBorderIfNeeded(displayId);              // Turn off magnification to release surface.              mWm.mAccessibilityController.setMagnificationCallbacks(displayId, null);              waitUntilHandlersIdle(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 43b424fab907..69b5c37466da 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -1681,7 +1681,8 @@ public class WindowOrganizerTests extends WindowTestsBase {          WindowContainerToken wct = rootTask.mRemoteToken.toWindowContainerToken();          t.setWindowingMode(wct, WINDOWING_MODE_PINNED);          mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); -        verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities(); +        verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivitiesUnchecked(any(), +                any(), any(), anyBoolean());          clearInvocations(mWm.mAtmService.mRootWindowContainer);          // The token for the PIP root task may have changed when the task entered PIP mode, so do @@ -1690,7 +1691,8 @@ public class WindowOrganizerTests extends WindowTestsBase {                  record.getRootTask().mRemoteToken.toWindowContainerToken();          t.setWindowingMode(newToken, WINDOWING_MODE_FULLSCREEN);          mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); -        verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivities(); +        verify(mWm.mAtmService.mRootWindowContainer).resumeFocusedTasksTopActivitiesUnchecked(any(), +                any(), any(), anyBoolean());      }      @Test diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index ae4faa84421e..9729c688439e 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -180,7 +180,8 @@ public class VoiceInteractionManagerService extends SystemService {                  LocalServices.getService(ActivityManagerInternal.class));          mAtmInternal = Objects.requireNonNull(                  LocalServices.getService(ActivityTaskManagerInternal.class)); -        mWmInternal = LocalServices.getService(WindowManagerInternal.class); +        mWmInternal = Objects.requireNonNull( +                LocalServices.getService(WindowManagerInternal.class));          mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);          LegacyPermissionManagerInternal permissionManagerInternal = LocalServices.getService(                  LegacyPermissionManagerInternal.class); @@ -2737,12 +2738,8 @@ public class VoiceInteractionManagerService extends SystemService {                      isManagedProfileVisible = true;                  }              } -            final ScreenCapture.ScreenshotHardwareBuffer shb; -            if (mWmInternal != null) { -                shb = mWmInternal.takeAssistScreenshot(); -            } else { -                shb = null; -            } +            final ScreenCapture.ScreenshotHardwareBuffer shb = +                    mWmInternal.takeAssistScreenshot();              final Bitmap bm = shb != null ? shb.asBitmap() : null;              // Now that everything is fetched, putting it in the launchIntent.              if (bm != null) { diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index ec60c676d078..0ddc38a78b1e 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -35,8 +35,6 @@ import android.telephony.TelephonyManager;  import android.util.Log;  import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.flags.FeatureFlags; -import com.android.internal.telephony.flags.FeatureFlagsImpl;  import java.util.HashMap;  import java.util.HashSet; @@ -48,8 +46,7 @@ public final class TelephonyPermissions {      private static final String LOG_TAG = "TelephonyPermissions";      private static final boolean DBG = false; -    /** Feature flags */ -    private static final FeatureFlags sFeatureFlag = new FeatureFlagsImpl(); +      /**       * Whether to disable the new device identifier access restrictions.       */ @@ -886,12 +883,6 @@ public final class TelephonyPermissions {       */      public static boolean checkSubscriptionAssociatedWithUser(@NonNull Context context, int subId,              @NonNull UserHandle callerUserHandle) { -        if (!sFeatureFlag.rejectBadSubIdInteraction() -                && !SubscriptionManager.isValidSubscriptionId(subId)) { -            // Return true for invalid sub Id. -            return true; -        } -          SubscriptionManager subManager = (SubscriptionManager) context.getSystemService(                  Context.TELEPHONY_SUBSCRIPTION_SERVICE);          final long token = Binder.clearCallingIdentity(); @@ -906,7 +897,7 @@ public final class TelephonyPermissions {          } catch (IllegalArgumentException e) {              // Found no record of this sub Id.              Log.e(LOG_TAG, "Subscription[Subscription ID:" + subId + "] has no records on device"); -            return !sFeatureFlag.rejectBadSubIdInteraction(); +            return false;          } finally {              Binder.restoreCallingIdentity(token);          } diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt index 46ad77e1eff9..519b4296d93a 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt @@ -16,8 +16,8 @@  package com.android.server.wm.flicker.activityembedding.close +import android.graphics.Rect  import android.platform.test.annotations.Presubmit -import android.tools.datatypes.Rect  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest @@ -122,7 +122,7 @@ class CloseSecondaryActivityInSplitTest(flicker: LegacyFlickerTest) :      companion object {          /** {@inheritDoc} */ -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          /**           * Creates the test configurations.           * diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt index af4f7a721464..4cd6d15b2983 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt @@ -16,8 +16,8 @@  package com.android.server.wm.flicker.activityembedding.layoutchange +import android.graphics.Rect  import android.platform.test.annotations.Presubmit -import android.tools.datatypes.Rect  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest @@ -114,11 +114,11 @@ class HorizontalSplitChangeRatioTest(flicker: LegacyFlickerTest) :              // Compare dimensions of two splits, given we're using default split attributes,              // both activities take up the same visible size on the display.              check { "height" } -                .that(topLayerRegion.region.height) -                .isEqual(bottomLayerRegion.region.height) +                .that(topLayerRegion.region.bounds.height()) +                .isEqual(bottomLayerRegion.region.bounds.height())              check { "width" } -                .that(topLayerRegion.region.width) -                .isEqual(bottomLayerRegion.region.width) +                .that(topLayerRegion.region.bounds.width()) +                .isEqual(bottomLayerRegion.region.bounds.width())              topLayerRegion.notOverlaps(bottomLayerRegion.region)              // Layers of two activities sum to be fullscreen size on display.              topLayerRegion.plus(bottomLayerRegion.region).coversExactly(startDisplayBounds) @@ -132,14 +132,17 @@ class HorizontalSplitChangeRatioTest(flicker: LegacyFlickerTest) :              // Compare dimensions of two splits, given we're using default split attributes,              // both activities take up the same visible size on the display.              check { "height" } -                .that(topLayerRegion.region.height) -                .isLower(bottomLayerRegion.region.height) +                .that(topLayerRegion.region.bounds.height()) +                .isLower(bottomLayerRegion.region.bounds.height())              check { "height" } -                .that(topLayerRegion.region.height / 0.3f - bottomLayerRegion.region.height / 0.7f) +                .that( +                    topLayerRegion.region.bounds.height() / 0.3f - +                        bottomLayerRegion.region.bounds.height() / 0.7f +                )                  .isLower(0.1f)              check { "width" } -                .that(topLayerRegion.region.width) -                .isEqual(bottomLayerRegion.region.width) +                .that(topLayerRegion.region.bounds.width()) +                .isEqual(bottomLayerRegion.region.bounds.width())              topLayerRegion.notOverlaps(bottomLayerRegion.region)              // Layers of two activities sum to be fullscreen size on display.              topLayerRegion.plus(bottomLayerRegion.region).coversExactly(startDisplayBounds) @@ -148,7 +151,7 @@ class HorizontalSplitChangeRatioTest(flicker: LegacyFlickerTest) :      companion object {          /** {@inheritDoc} */ -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          /**           * Creates the test configurations. diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt index e511b727d57f..5df8b57294f0 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt @@ -16,8 +16,8 @@  package com.android.server.wm.flicker.activityembedding.open +import android.graphics.Rect  import android.platform.test.annotations.Presubmit -import android.tools.datatypes.Rect  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest @@ -132,7 +132,7 @@ class MainActivityStartsSecondaryWithAlwaysExpandTest(flicker: LegacyFlickerTest      companion object {          /** {@inheritDoc} */ -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          /**           * Creates the test configurations. diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt index 4352177a8984..78004ccc3f97 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt @@ -16,8 +16,8 @@  package com.android.server.wm.flicker.activityembedding.open +import android.graphics.Rect  import android.platform.test.annotations.Presubmit -import android.tools.datatypes.Rect  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest @@ -143,7 +143,7 @@ class OpenThirdActivityOverSplitTest(flicker: LegacyFlickerTest) :      companion object {          /** {@inheritDoc} */ -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          /**           * Creates the test configurations.           * diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt index 62cf6cd528e9..cf4edd50040b 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt @@ -16,8 +16,8 @@  package com.android.server.wm.flicker.activityembedding.open +import android.graphics.Rect  import android.platform.test.annotations.Presubmit -import android.tools.datatypes.Rect  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest @@ -156,11 +156,11 @@ class OpenTrampolineActivityTest(flicker: LegacyFlickerTest) : ActivityEmbedding                              it.timestamp                          )                      check { "height" } -                        .that(mainActivityRegion.region.height) -                        .isEqual(secondaryActivityRegion.region.height) +                        .that(mainActivityRegion.region.bounds.height()) +                        .isEqual(secondaryActivityRegion.region.bounds.height())                      check { "width" } -                        .that(mainActivityRegion.region.width) -                        .isEqual(secondaryActivityRegion.region.width) +                        .that(mainActivityRegion.region.bounds.width()) +                        .isEqual(secondaryActivityRegion.region.bounds.width())                      mainActivityRegion                          .plus(secondaryActivityRegion.region)                          .coversExactly(startDisplayBounds) @@ -192,11 +192,11 @@ class OpenTrampolineActivityTest(flicker: LegacyFlickerTest) : ActivityEmbedding              // Compare dimensions of two splits, given we're using default split attributes,              // both activities take up the same visible size on the display.              check { "height" } -                .that(leftLayerRegion.region.height) -                .isEqual(rightLayerRegion.region.height) +                .that(leftLayerRegion.region.bounds.height()) +                .isEqual(rightLayerRegion.region.bounds.height())              check { "width" } -                .that(leftLayerRegion.region.width) -                .isEqual(rightLayerRegion.region.width) +                .that(leftLayerRegion.region.bounds.width()) +                .isEqual(rightLayerRegion.region.bounds.width())              leftLayerRegion.notOverlaps(rightLayerRegion.region)              // Layers of two activities sum to be fullscreen size on display.              leftLayerRegion.plus(rightLayerRegion.region).coversExactly(startDisplayBounds) @@ -211,7 +211,7 @@ class OpenTrampolineActivityTest(flicker: LegacyFlickerTest) : ActivityEmbedding      companion object {          /** {@inheritDoc} */ -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          /**           * Creates the test configurations. diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt index aa8b4cebe91d..bc3696b3ed1c 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt @@ -16,8 +16,8 @@  package com.android.server.wm.flicker.activityembedding.pip +import android.graphics.Rect  import android.platform.test.annotations.Presubmit -import android.tools.datatypes.Rect  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest @@ -79,11 +79,11 @@ class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) :              // Compare dimensions of two splits, given we're using default split attributes,              // both activities take up the same visible size on the display.              check { "height" } -                .that(leftLayerRegion.region.height) -                .isEqual(rightLayerRegion.region.height) +                .that(leftLayerRegion.region.bounds.height()) +                .isEqual(rightLayerRegion.region.bounds.height())              check { "width" } -                .that(leftLayerRegion.region.width) -                .isEqual(rightLayerRegion.region.width) +                .that(leftLayerRegion.region.bounds.width()) +                .isEqual(rightLayerRegion.region.bounds.width())              leftLayerRegion.notOverlaps(rightLayerRegion.region)              leftLayerRegion.plus(rightLayerRegion.region).coversExactly(startDisplayBounds)          } @@ -136,9 +136,11 @@ class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) :              val pipWindowRegion =                  visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)              check { "height" } -                .that(pipWindowRegion.region.height) -                .isLower(startDisplayBounds.height / 2) -            check { "width" }.that(pipWindowRegion.region.width).isLower(startDisplayBounds.width) +                .that(pipWindowRegion.region.bounds.height()) +                .isLower(startDisplayBounds.height() / 2) +            check { "width" } +                .that(pipWindowRegion.region.bounds.width()) +                .isLower(startDisplayBounds.width())          }      } @@ -151,7 +153,7 @@ class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) :                  ComponentNameMatcher.PIP_CONTENT_OVERLAY.layerMatchesAnyOf(it) && it.isVisible              }              pipLayerList.zipWithNext { previous, current -> -                if (startDisplayBounds.width > startDisplayBounds.height) { +                if (startDisplayBounds.width() > startDisplayBounds.height()) {                      // Only verify when the display is landscape, because otherwise the final pip                      // window can be to the left of the original secondary activity.                      current.screenBounds.isToTheRightBottom(previous.screenBounds.region, 3) @@ -162,8 +164,12 @@ class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) :          }          flicker.assertLayersEnd {              val pipRegion = visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) -            check { "height" }.that(pipRegion.region.height).isLower(startDisplayBounds.height / 2) -            check { "width" }.that(pipRegion.region.width).isLower(startDisplayBounds.width) +            check { "height" } +                .that(pipRegion.region.bounds.height()) +                .isLower(startDisplayBounds.height() / 2) +            check { "width" } +                .that(pipRegion.region.bounds.width()) +                .isLower(startDisplayBounds.width())          }      } @@ -175,7 +181,7 @@ class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) :              invoke("secondaryLayerNotJumpToLeft") {                  val secondaryVisibleRegion =                      it.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) -                if (secondaryVisibleRegion.region.isNotEmpty) { +                if (!secondaryVisibleRegion.region.isEmpty) {                      check { "left" }.that(secondaryVisibleRegion.region.bounds.left).isGreater(0)                  }              } @@ -222,7 +228,7 @@ class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) :      companion object {          /** {@inheritDoc} */ -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          /**           * Creates the test configurations.           * diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt index 3d834c16163f..f5e6c7854eba 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt @@ -85,11 +85,11 @@ open class RotateSplitNoChangeTest(flicker: LegacyFlickerTest) : RotationTransit                  // Compare dimensions of two splits, given we're using default split attributes,                  // both activities take up the same visible size on the display.                  check { "height" } -                    .that(leftLayerRegion.region.height) -                    .isEqual(rightLayerRegion.region.height) +                    .that(leftLayerRegion.region.bounds.height()) +                    .isEqual(rightLayerRegion.region.bounds.height())                  check { "width" } -                    .that(leftLayerRegion.region.width) -                    .isEqual(rightLayerRegion.region.width) +                    .that(leftLayerRegion.region.bounds.width()) +                    .isEqual(rightLayerRegion.region.bounds.width())                  leftLayerRegion.notOverlaps(rightLayerRegion.region)                  // Layers of two activities sum to be fullscreen size on display.                  leftLayerRegion.plus(rightLayerRegion.region).coversExactly(display.layerStackSpace) @@ -108,11 +108,11 @@ open class RotateSplitNoChangeTest(flicker: LegacyFlickerTest) : RotationTransit                  val rightLayerRegion =                      this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)                  check { "height" } -                    .that(leftLayerRegion.region.height) -                    .isEqual(rightLayerRegion.region.height) +                    .that(leftLayerRegion.region.bounds.height()) +                    .isEqual(rightLayerRegion.region.bounds.height())                  check { "width" } -                    .that(leftLayerRegion.region.width) -                    .isEqual(rightLayerRegion.region.width) +                    .that(leftLayerRegion.region.bounds.width()) +                    .isEqual(rightLayerRegion.region.bounds.width())                  leftLayerRegion.notOverlaps(rightLayerRegion.region)                  leftLayerRegion.plus(rightLayerRegion.region).coversExactly(display.layerStackSpace)              } diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt index 13902184ac6e..ee2c05e82d51 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt @@ -16,9 +16,9 @@  package com.android.server.wm.flicker.activityembedding.rotation +import android.graphics.Rect  import android.platform.test.annotations.Presubmit  import android.tools.Position -import android.tools.datatypes.Rect  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest  import android.tools.traces.Condition @@ -97,7 +97,7 @@ abstract class RotationTransition(flicker: LegacyFlickerTest) : ActivityEmbeddin              val navBarPosition = display.navBarPosition(isGesturalNavigation)              val navBarRegion = dump.layerState                  .getLayerWithBuffer(ComponentNameMatcher.NAV_BAR) -                ?.visibleRegion?.bounds ?: Rect.EMPTY +                ?.visibleRegion?.bounds ?: Rect()              when (navBarPosition) {                  Position.TOP -> diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt index 7298e5f71b05..fb9258304870 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt @@ -16,9 +16,9 @@  package com.android.server.wm.flicker.activityembedding.splitscreen +import android.graphics.Rect  import android.platform.test.annotations.Presubmit  import android.platform.test.annotations.RequiresDevice -import android.tools.datatypes.Rect  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest @@ -32,6 +32,7 @@ import com.android.wm.shell.flicker.utils.SplitScreenUtils  import com.android.wm.shell.flicker.utils.appWindowIsVisibleAtEnd  import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd  import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesVisible +import kotlin.math.abs  import org.junit.FixMethodOrder  import org.junit.Ignore  import org.junit.Test @@ -135,19 +136,25 @@ class EnterSystemSplitTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBa                  .plus(systemDivider.region)                  .coversExactly(startDisplayBounds)              check { "ActivityEmbeddingSplitHeight" } -                .that(leftAELayerRegion.region.height) -                .isEqual(rightAELayerRegion.region.height) +                .that(leftAELayerRegion.region.bounds.height()) +                .isEqual(rightAELayerRegion.region.bounds.height())              check { "SystemSplitHeight" } -                .that(rightAELayerRegion.region.height) -                .isEqual(secondaryAppLayerRegion.region.height) +                .that(rightAELayerRegion.region.bounds.height()) +                .isEqual(secondaryAppLayerRegion.region.bounds.height())              // TODO(b/292283182): Remove this special case handling.              check { "ActivityEmbeddingSplitWidth" } -                .that(Math.abs(leftAELayerRegion.region.width - rightAELayerRegion.region.width)) +                .that( +                    abs( +                        leftAELayerRegion.region.bounds.width() - +                            rightAELayerRegion.region.bounds.width() +                    ) +                )                  .isLower(2)              check { "SystemSplitWidth" }                  .that( -                    Math.abs( -                        secondaryAppLayerRegion.region.width - 2 * rightAELayerRegion.region.width +                    abs( +                        secondaryAppLayerRegion.region.bounds.width() - +                            2 * rightAELayerRegion.region.bounds.width()                      )                  )                  .isLower(2) @@ -167,18 +174,24 @@ class EnterSystemSplitTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBa              val secondaryAppLayerRegion =                  visibleRegion(ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())              check { "ActivityEmbeddingSplitHeight" } -                .that(leftAEWindowRegion.region.height) -                .isEqual(rightAEWindowRegion.region.height) +                .that(leftAEWindowRegion.region.bounds.height()) +                .isEqual(rightAEWindowRegion.region.bounds.height())              check { "SystemSplitHeight" } -                .that(rightAEWindowRegion.region.height) -                .isEqual(secondaryAppLayerRegion.region.height) +                .that(rightAEWindowRegion.region.bounds.height()) +                .isEqual(secondaryAppLayerRegion.region.bounds.height())              check { "ActivityEmbeddingSplitWidth" } -                .that(Math.abs(leftAEWindowRegion.region.width - rightAEWindowRegion.region.width)) +                .that( +                    abs( +                        leftAEWindowRegion.region.bounds.width() - +                            rightAEWindowRegion.region.bounds.width() +                    ) +                )                  .isLower(2)              check { "SystemSplitWidth" }                  .that( -                    Math.abs( -                        secondaryAppLayerRegion.region.width - 2 * rightAEWindowRegion.region.width +                    abs( +                        secondaryAppLayerRegion.region.bounds.width() - +                            2 * rightAEWindowRegion.region.bounds.width()                      )                  )                  .isLower(2) @@ -190,7 +203,7 @@ class EnterSystemSplitTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBa      companion object {          /** {@inheritDoc} */ -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          /**           * Creates the test configurations.           * diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt index b1d78cbc034e..a71599d25632 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt @@ -19,8 +19,9 @@ package com.android.server.wm.flicker.launch  import android.app.Instrumentation  import android.app.WallpaperManager  import android.content.res.Resources +import android.graphics.Rect +import android.graphics.Region  import android.platform.test.annotations.Presubmit -import android.tools.datatypes.Region  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest @@ -213,6 +214,12 @@ class TaskTransitionTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {          private fun LayersTraceSubject.visibleRegionCovers(              component: IComponentMatcher, +            expectedArea: Rect, +            isOptional: Boolean = true +        ): LayersTraceSubject = visibleRegionCovers(component, Region(expectedArea), isOptional) + +        private fun LayersTraceSubject.visibleRegionCovers( +            component: IComponentMatcher,              expectedArea: Region,              isOptional: Boolean = true          ): LayersTraceSubject = diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt index 7e486abbd30f..da8368f3cedf 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt @@ -83,11 +83,12 @@ class CloseImeOnDismissPopupDialogTest(flicker: LegacyFlickerTest) : BaseTest(fl                      }                  if (imeSnapshotLayers.isNotEmpty()) {                      val visibleAreas = -                        imeSnapshotLayers -                            .mapNotNull { imeSnapshotLayer -> imeSnapshotLayer.layer.visibleRegion } +                        imeSnapshotLayers.mapNotNull { imeSnapshotLayer -> +                            imeSnapshotLayer.layer.visibleRegion +                        }                      val imeVisibleRegion = RegionSubject(visibleAreas, timestamp)                      val appVisibleRegion = it.visibleRegion(imeTestApp) -                    if (imeVisibleRegion.region.isNotEmpty) { +                    if (!imeVisibleRegion.region.isEmpty) {                          imeVisibleRegion.coversAtMost(appVisibleRegion.region)                      }                  } diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt index e8249bca4c2d..48ec4d1fed2c 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt @@ -115,7 +115,10 @@ class ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest(flicker: LegacyF                  .isEqual(true)              imeLayerSubjects.forEach { imeLayerSubject -> -                imeLayerSubject.check { "alpha" }.that(imeLayerSubject.layer.color.a).isEqual(1.0f) +                imeLayerSubject +                    .check { "alpha" } +                    .that(imeLayerSubject.layer.color.alpha()) +                    .isEqual(1.0f)              }          }      } diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt index 617237d37368..063088d54b45 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt @@ -50,7 +50,10 @@ class ShowImeOnAppStartWhenLaunchingAppFromOverviewTest(flicker: LegacyFlickerTe              testApp.launchViaIntent(wmHelper)              testApp.openIME(wmHelper)              this.setRotation(flicker.scenario.startRotation) -            device.pressRecentApps() +            if (flicker.scenario.isTablet) { +                tapl.launchedAppState.swipeUpToUnstashTaskbar() +            } +            tapl.launchedAppState.switchToOverview()              wmHelper.StateSyncBuilder().withRecentsActivityVisible().waitForAndVerify()          }          transitions { diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt index a14dc62b0023..7aa525fcccef 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt @@ -191,7 +191,7 @@ class ShowImeWhileEnteringOverviewTest(flicker: LegacyFlickerTest) : BaseTest(fl              this.invoke("imeLayerIsVisibleAndAlignAppWidow") {                  val imeVisibleRegion = it.visibleRegion(ComponentNameMatcher.IME)                  val appVisibleRegion = it.visibleRegion(imeTestApp) -                if (imeVisibleRegion.region.isNotEmpty) { +                if (!imeVisibleRegion.region.isEmpty) {                      it.isVisible(ComponentNameMatcher.IME)                      imeVisibleRegion.coversAtMost(appVisibleRegion.region)                  } diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt index 8b09b590e790..9bb62e1e1794 100644 --- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt +++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt @@ -16,9 +16,9 @@  package com.android.server.wm.flicker.quickswitch +import android.graphics.Rect  import android.platform.test.annotations.Presubmit  import android.tools.NavBar -import android.tools.datatypes.Rect  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest @@ -237,7 +237,7 @@ class QuickSwitchBetweenTwoAppsBackTest(flicker: LegacyFlickerTest) : BaseTest(f      override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()      companion object { -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          @Parameterized.Parameters(name = "{0}")          @JvmStatic diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt index c54ddcf793f6..491b9945d12d 100644 --- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt +++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt @@ -16,8 +16,8 @@  package com.android.server.wm.flicker.quickswitch +import android.graphics.Rect  import android.tools.NavBar -import android.tools.datatypes.Rect  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest @@ -285,7 +285,7 @@ class QuickSwitchBetweenTwoAppsForwardTest(flicker: LegacyFlickerTest) : BaseTes          super.visibleWindowsShownMoreThanOneConsecutiveEntry()      companion object { -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          @Parameterized.Parameters(name = "{0}")          @JvmStatic diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt index 69a84a0cbcb0..de54c95da361 100644 --- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt +++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt @@ -16,10 +16,10 @@  package com.android.server.wm.flicker.quickswitch +import android.graphics.Rect  import android.platform.test.annotations.Presubmit  import android.tools.NavBar  import android.tools.Rotation -import android.tools.datatypes.Rect  import android.tools.flicker.junit.FlickerParametersRunnerFactory  import android.tools.flicker.legacy.FlickerBuilder  import android.tools.flicker.legacy.LegacyFlickerTest @@ -266,7 +266,7 @@ class QuickSwitchFromLauncherTest(flicker: LegacyFlickerTest) : BaseTest(flicker      companion object {          /** {@inheritDoc} */ -        private var startDisplayBounds = Rect.EMPTY +        private var startDisplayBounds = Rect()          @Parameterized.Parameters(name = "{0}")          @JvmStatic diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt index 8853c1db856f..348d0af5a2d3 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt @@ -279,12 +279,11 @@ fun LegacyFlickerTest.snapshotStartingWindowLayerCoversExactlyOnApp(                          subject.isVisible                  }              val visibleAreas = -                snapshotLayers -                    .mapNotNull { snapshotLayer -> snapshotLayer.layer.visibleRegion } +                snapshotLayers.mapNotNull { snapshotLayer -> snapshotLayer.layer.visibleRegion }              val snapshotRegion = RegionSubject(visibleAreas, it.timestamp)              val appVisibleRegion = it.visibleRegion(component)              // Verify the size of snapshotRegion covers appVisibleRegion exactly in animation. -            if (snapshotRegion.region.isNotEmpty && appVisibleRegion.region.isNotEmpty) { +            if (!snapshotRegion.region.isEmpty && !appVisibleRegion.region.isEmpty) {                  snapshotRegion.coversExactly(appVisibleRegion.region)              }          } diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt index ffed4087acff..ef8d84fb915a 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt @@ -45,13 +45,7 @@ constructor(          require(gameView != null) { "Mock game app view not found." }          val bound = gameView.getVisibleBounds() -        return uiDevice.swipe( -            bound.centerX(), -            0, -            bound.centerX(), -            bound.centerY(), -            SWIPE_STEPS -        ) +        return uiDevice.swipe(bound.centerX(), 0, bound.centerX(), bound.centerY(), SWIPE_STEPS)      }      /** diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt index b09e53b6400d..634b6eedd7e6 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt @@ -17,8 +17,8 @@  package com.android.server.wm.flicker.helpers  import android.app.Instrumentation -import android.tools.datatypes.Rect -import android.tools.datatypes.Region +import android.graphics.Rect +import android.graphics.Region  import android.tools.device.apphelpers.StandardAppHelper  import android.tools.helpers.FIND_TIMEOUT  import android.tools.helpers.SYSTEMUI_PACKAGE @@ -86,7 +86,7 @@ constructor(              .add("letterboxAppRepositioned") {                  val letterboxAppWindow = getWindowRegion(wmHelper)                  val appRegionBounds = letterboxAppWindow.bounds -                val appWidth = appRegionBounds.width +                val appWidth = appRegionBounds.width()                  return@add if (right)                      appRegionBounds.left == displayBounds.right - appWidth &&                          appRegionBounds.right == displayBounds.right @@ -108,7 +108,7 @@ constructor(              .add("letterboxAppRepositioned") {                  val letterboxAppWindow = getWindowRegion(wmHelper)                  val appRegionBounds = letterboxAppWindow.bounds -                val appHeight = appRegionBounds.height +                val appHeight = appRegionBounds.height()                  return@add if (bottom)                      appRegionBounds.bottom == displayBounds.bottom &&                          appRegionBounds.top == (displayBounds.bottom - appHeight + navBarHeight) diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt index db933b30a822..43fd57bf39aa 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt @@ -18,10 +18,11 @@ package com.android.server.wm.flicker.helpers  import android.app.Instrumentation  import android.content.Intent +import android.graphics.Rect +import android.graphics.Region  import android.media.session.MediaController  import android.media.session.MediaSessionManager -import android.tools.datatypes.Rect -import android.tools.datatypes.Region +import android.tools.datatypes.coversMoreThan  import android.tools.device.apphelpers.StandardAppHelper  import android.tools.helpers.FIND_TIMEOUT  import android.tools.helpers.SYSTEMUI_PACKAGE @@ -62,7 +63,7 @@ open class PipAppHelper(instrumentation: Instrumentation) :      /** Drags the PIP window to the provided final coordinates without releasing the pointer. */      fun dragPipWindowAwayFromEdgeWithoutRelease(wmHelper: WindowManagerStateHelper, steps: Int) { -        val initWindowRect = getWindowRect(wmHelper).clone() +        val initWindowRect = Rect(getWindowRect(wmHelper))          // initial pointer at the center of the window          val initialCoord = @@ -101,7 +102,7 @@ open class PipAppHelper(instrumentation: Instrumentation) :       * @throws IllegalStateException if default display bounds are not available       */      fun dragPipWindowAwayFromEdge(wmHelper: WindowManagerStateHelper, steps: Int) { -        val initWindowRect = getWindowRect(wmHelper).clone() +        val initWindowRect = Rect(getWindowRect(wmHelper))          // initial pointer at the center of the window          val startX = initWindowRect.centerX() @@ -153,12 +154,12 @@ open class PipAppHelper(instrumentation: Instrumentation) :          val windowRect = getWindowRect(wmHelper)          // first pointer's initial x coordinate is halfway between the left edge and the center -        val initLeftX = (windowRect.centerX() - windowRect.width / 4).toFloat() +        val initLeftX = (windowRect.centerX() - windowRect.width() / 4).toFloat()          // second pointer's initial x coordinate is halfway between the right edge and the center -        val initRightX = (windowRect.centerX() + windowRect.width / 4).toFloat() +        val initRightX = (windowRect.centerX() + windowRect.width() / 4).toFloat()          // horizontal distance the window should increase by -        val distIncrease = windowRect.width * percent +        val distIncrease = windowRect.width() * percent          // final x-coordinates          val finalLeftX = initLeftX - (distIncrease / 2) @@ -183,7 +184,7 @@ open class PipAppHelper(instrumentation: Instrumentation) :              adjustedSteps          ) -        waitForPipWindowToExpandFrom(wmHelper, Region.from(windowRect)) +        waitForPipWindowToExpandFrom(wmHelper, Region(windowRect))      }      /** @@ -201,12 +202,12 @@ open class PipAppHelper(instrumentation: Instrumentation) :          val windowRect = getWindowRect(wmHelper)          // first pointer's initial x coordinate is halfway between the left edge and the center -        val initLeftX = (windowRect.centerX() - windowRect.width / 4).toFloat() +        val initLeftX = (windowRect.centerX() - windowRect.width() / 4).toFloat()          // second pointer's initial x coordinate is halfway between the right edge and the center -        val initRightX = (windowRect.centerX() + windowRect.width / 4).toFloat() +        val initRightX = (windowRect.centerX() + windowRect.width() / 4).toFloat()          // decrease by the distance specified through the percentage -        val distDecrease = windowRect.width * percent +        val distDecrease = windowRect.width() * percent          // get the final x-coordinates and make sure they are not passing the center of the window          val finalLeftX = Math.min(initLeftX + (distDecrease / 2), windowRect.centerX().toFloat()) @@ -231,7 +232,7 @@ open class PipAppHelper(instrumentation: Instrumentation) :              adjustedSteps          ) -        waitForPipWindowToMinimizeFrom(wmHelper, Region.from(windowRect)) +        waitForPipWindowToMinimizeFrom(wmHelper, Region(windowRect))      }      /** @@ -375,7 +376,7 @@ open class PipAppHelper(instrumentation: Instrumentation) :          uiDevice.click(windowRect.centerX(), windowRect.centerY())          Log.d(TAG, "Wait for app transition to end")          wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() -        waitForPipWindowToExpandFrom(wmHelper, Region.from(windowRect)) +        waitForPipWindowToExpandFrom(wmHelper, Region(windowRect))      }      private fun waitForPipWindowToExpandFrom( diff --git a/tests/OneMedia/Android.bp b/tests/OneMedia/Android.bp index 5c7317735bc7..a43cd39f0dcb 100644 --- a/tests/OneMedia/Android.bp +++ b/tests/OneMedia/Android.bp @@ -16,6 +16,7 @@ android_app {      platform_apis: true,      certificate: "platform",      libs: ["org.apache.http.legacy"], +    optional_uses_libs: ["org.apache.http.legacy"],      optimize: {          enabled: false,      }, diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index 093923f3ed53..1fdf97a4c821 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -45,13 +45,13 @@ import android.os.test.TestLooper;  import android.platform.test.flag.junit.SetFlagsRule;  import android.provider.DeviceConfig;  import android.util.AtomicFile; -import android.util.LongArrayQueue;  import android.util.Xml; +import android.utils.LongArrayQueue; +import android.utils.XmlUtils;  import androidx.test.InstrumentationRegistry;  import com.android.dx.mockito.inline.extended.ExtendedMockito; -import com.android.internal.util.XmlUtils;  import com.android.modules.utils.TypedXmlPullParser;  import com.android.modules.utils.TypedXmlSerializer;  import com.android.server.PackageWatchdog.HealthCheckState; diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java index c1c520e99cac..191f38d3df80 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/AslConverter.java @@ -59,13 +59,16 @@ public class AslConverter {          switch (format) {              case HUMAN_READABLE:                  Element appMetadataBundles = -                        XmlUtils.getSingleElement(document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES); +                        XmlUtils.getSingleChildElement( +                                document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES, true);                  return new AndroidSafetyLabelFactory()                          .createFromHrElements(XmlUtils.listOf(appMetadataBundles));              case ON_DEVICE: -                throw new IllegalArgumentException( -                        "Parsing from on-device format is not supported at this time."); +                Element bundleEle = +                        XmlUtils.getSingleChildElement(document, XmlUtils.OD_TAG_BUNDLE, true); +                return new AndroidSafetyLabelFactory() +                        .createFromOdElements(XmlUtils.listOf(bundleEle));              default:                  throw new IllegalStateException("Unrecognized input format.");          } @@ -88,8 +91,10 @@ public class AslConverter {          switch (format) {              case HUMAN_READABLE: -                throw new IllegalArgumentException( -                        "Outputting human-readable format is not supported at this time."); +                for (var child : asl.toHrDomElements(document)) { +                    document.appendChild(child); +                } +                break;              case ON_DEVICE:                  for (var child : asl.toOdDomElements(document)) {                      document.appendChild(child); diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java index 112b92c9aebb..72140a17297c 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabel.java @@ -61,4 +61,21 @@ public class AndroidSafetyLabel implements AslMarshallable {          }          return XmlUtils.listOf(aslEle);      } + +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    @Override +    public List<Element> toHrDomElements(Document doc) { +        Element aslEle = doc.createElement(XmlUtils.HR_TAG_APP_METADATA_BUNDLES); +        aslEle.setAttribute(XmlUtils.HR_ATTR_VERSION, String.valueOf(mVersion)); +        if (mSafetyLabels != null) { +            XmlUtils.appendChildren(aslEle, mSafetyLabels.toHrDomElements(doc)); +        } +        if (mSystemAppSafetyLabel != null) { +            XmlUtils.appendChildren(aslEle, mSystemAppSafetyLabel.toHrDomElements(doc)); +        } +        if (mTransparencyInfo != null) { +            XmlUtils.appendChildren(aslEle, mTransparencyInfo.toHrDomElements(doc)); +        } +        return XmlUtils.listOf(aslEle); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java index b69c30f7f522..c53cbbf99a46 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AndroidSafetyLabelFactory.java @@ -55,4 +55,33 @@ public class AndroidSafetyLabelFactory implements AslMarshallableFactory<Android          return new AndroidSafetyLabel(                  version, systemAppSafetyLabel, safetyLabels, transparencyInfo);      } + +    /** Creates an {@link AndroidSafetyLabel} from on-device DOM elements */ +    @Override +    public AndroidSafetyLabel createFromOdElements(List<Element> elements) +            throws MalformedXmlException { +        Element bundleEle = XmlUtils.getSingleElement(elements); +        Long version = XmlUtils.getOdLongEle(bundleEle, XmlUtils.OD_NAME_VERSION, true); + +        Element safetyLabelsEle = +                XmlUtils.getOdPbundleWithName(bundleEle, XmlUtils.OD_NAME_SAFETY_LABELS, false); +        SafetyLabels safetyLabels = +                new SafetyLabelsFactory().createFromOdElements(XmlUtils.listOf(safetyLabelsEle)); + +        Element systemAppSafetyLabelEle = +                XmlUtils.getOdPbundleWithName( +                        bundleEle, XmlUtils.OD_NAME_SYSTEM_APP_SAFETY_LABEL, false); +        SystemAppSafetyLabel systemAppSafetyLabel = +                new SystemAppSafetyLabelFactory() +                        .createFromOdElements(XmlUtils.listOf(systemAppSafetyLabelEle)); + +        Element transparencyInfoEle = +                XmlUtils.getOdPbundleWithName(bundleEle, XmlUtils.OD_NAME_TRANSPARENCY_INFO, false); +        TransparencyInfo transparencyInfo = +                new TransparencyInfoFactory() +                        .createFromOdElements(XmlUtils.listOf(transparencyInfoEle)); + +        return new AndroidSafetyLabel( +                version, systemAppSafetyLabel, safetyLabels, transparencyInfo); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java index 3f1ddebefe99..129733ebc1b6 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfo.java @@ -142,4 +142,59 @@ public class AppInfo implements AslMarshallable {          }          return XmlUtils.listOf(appInfoEle);      } + +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    @Override +    public List<Element> toHrDomElements(Document doc) { +        Element appInfoEle = doc.createElement(XmlUtils.HR_TAG_APP_INFO); +        if (this.mTitle != null) { +            appInfoEle.setAttribute(XmlUtils.HR_ATTR_TITLE, this.mTitle); +        } +        if (this.mDescription != null) { +            appInfoEle.setAttribute(XmlUtils.HR_ATTR_DESCRIPTION, this.mDescription); +        } +        if (this.mContainsAds != null) { +            appInfoEle.setAttribute( +                    XmlUtils.HR_ATTR_CONTAINS_ADS, String.valueOf(this.mContainsAds)); +        } +        if (this.mObeyAps != null) { +            appInfoEle.setAttribute(XmlUtils.HR_ATTR_OBEY_APS, String.valueOf(this.mObeyAps)); +        } +        if (this.mAdsFingerprinting != null) { +            appInfoEle.setAttribute( +                    XmlUtils.HR_ATTR_ADS_FINGERPRINTING, String.valueOf(this.mAdsFingerprinting)); +        } +        if (this.mSecurityFingerprinting != null) { +            appInfoEle.setAttribute( +                    XmlUtils.HR_ATTR_SECURITY_FINGERPRINTING, +                    String.valueOf(this.mSecurityFingerprinting)); +        } +        if (this.mPrivacyPolicy != null) { +            appInfoEle.setAttribute(XmlUtils.HR_ATTR_PRIVACY_POLICY, this.mPrivacyPolicy); +        } +        if (this.mSecurityEndpoints != null) { +            appInfoEle.setAttribute( +                    XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, String.join("|", this.mSecurityEndpoints)); +        } +        if (this.mFirstPartyEndpoints != null) { +            appInfoEle.setAttribute( +                    XmlUtils.HR_ATTR_FIRST_PARTY_ENDPOINTS, +                    String.join("|", this.mFirstPartyEndpoints)); +        } +        if (this.mServiceProviderEndpoints != null) { +            appInfoEle.setAttribute( +                    XmlUtils.HR_ATTR_SERVICE_PROVIDER_ENDPOINTS, +                    String.join("|", this.mServiceProviderEndpoints)); +        } +        if (this.mCategory != null) { +            appInfoEle.setAttribute(XmlUtils.HR_ATTR_CATEGORY, this.mCategory); +        } +        if (this.mEmail != null) { +            appInfoEle.setAttribute(XmlUtils.HR_ATTR_EMAIL, this.mEmail); +        } +        if (this.mWebsite != null) { +            appInfoEle.setAttribute(XmlUtils.HR_ATTR_WEBSITE, this.mWebsite); +        } +        return XmlUtils.listOf(appInfoEle); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java index 59a437d7ece5..c5069619e069 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AppInfoFactory.java @@ -35,15 +35,16 @@ public class AppInfoFactory implements AslMarshallableFactory<AppInfo> {              return null;          } -        String title = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_TITLE); -        String description = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_DESCRIPTION); +        String title = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_TITLE, true); +        String description = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_DESCRIPTION, true);          Boolean containsAds = XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_CONTAINS_ADS, true);          Boolean obeyAps = XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_OBEY_APS, true);          Boolean adsFingerprinting =                  XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_ADS_FINGERPRINTING, true);          Boolean securityFingerprinting =                  XmlUtils.getBoolAttr(appInfoEle, XmlUtils.HR_ATTR_SECURITY_FINGERPRINTING, true); -        String privacyPolicy = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_PRIVACY_POLICY); +        String privacyPolicy = +                XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_PRIVACY_POLICY, true);          List<String> securityEndpoints =                  XmlUtils.getPipelineSplitAttr(                          appInfoEle, XmlUtils.HR_ATTR_SECURITY_ENDPOINTS, true); @@ -53,8 +54,8 @@ public class AppInfoFactory implements AslMarshallableFactory<AppInfo> {          List<String> serviceProviderEndpoints =                  XmlUtils.getPipelineSplitAttr(                          appInfoEle, XmlUtils.HR_ATTR_SERVICE_PROVIDER_ENDPOINTS, true); -        String category = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_CATEGORY); -        String email = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_EMAIL); +        String category = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_CATEGORY, true); +        String email = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_EMAIL, true);          String website = XmlUtils.getStringAttr(appInfoEle, XmlUtils.HR_ATTR_WEBSITE, false);          return new AppInfo( @@ -72,4 +73,52 @@ public class AppInfoFactory implements AslMarshallableFactory<AppInfo> {                  email,                  website);      } + +    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ +    @Override +    public AppInfo createFromOdElements(List<Element> elements) throws MalformedXmlException { +        Element appInfoEle = XmlUtils.getSingleElement(elements); +        if (appInfoEle == null) { +            AslgenUtil.logI("No AppInfo found in od format."); +            return null; +        } + +        String title = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_TITLE, true); +        String description = +                XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_DESCRIPTION, true); +        Boolean containsAds = +                XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_CONTAINS_ADS, true); +        Boolean obeyAps = XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_OBEY_APS, true); +        Boolean adsFingerprinting = +                XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_ADS_FINGERPRINTING, true); +        Boolean securityFingerprinting = +                XmlUtils.getOdBoolEle(appInfoEle, XmlUtils.OD_NAME_SECURITY_FINGERPRINTING, true); +        String privacyPolicy = +                XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_PRIVACY_POLICY, true); +        List<String> securityEndpoints = +                XmlUtils.getOdStringArray(appInfoEle, XmlUtils.OD_NAME_SECURITY_ENDPOINT, true); +        List<String> firstPartyEndpoints = +                XmlUtils.getOdStringArray(appInfoEle, XmlUtils.OD_NAME_FIRST_PARTY_ENDPOINT, true); +        List<String> serviceProviderEndpoints = +                XmlUtils.getOdStringArray( +                        appInfoEle, XmlUtils.OD_NAME_SERVICE_PROVIDER_ENDPOINT, true); +        String category = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_CATEGORY, true); +        String email = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_EMAIL, true); +        String website = XmlUtils.getOdStringEle(appInfoEle, XmlUtils.OD_NAME_WEBSITE, false); + +        return new AppInfo( +                title, +                description, +                containsAds, +                obeyAps, +                adsFingerprinting, +                securityFingerprinting, +                privacyPolicy, +                securityEndpoints, +                firstPartyEndpoints, +                serviceProviderEndpoints, +                category, +                email, +                website); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java index 48747ccbcff6..0a70e7d0d74b 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallable.java @@ -23,6 +23,9 @@ import java.util.List;  public interface AslMarshallable { -    /** Creates the on-device DOM element from the AslMarshallable Java Object. */ +    /** Creates the on-device DOM elements from the AslMarshallable Java Object. */      List<Element> toOdDomElements(Document doc); + +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    List<Element> toHrDomElements(Document doc);  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java index a49b3e77155b..39582900f3a0 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/AslMarshallableFactory.java @@ -24,6 +24,9 @@ import java.util.List;  public interface AslMarshallableFactory<T extends AslMarshallable> { -    /** Creates an {@link AslMarshallableFactory} from human-readable DOM element */ +    /** Creates an {@link AslMarshallableFactory} from human-readable DOM elements */      T createFromHrElements(List<Element> elements) throws MalformedXmlException; + +    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ +    T createFromOdElements(List<Element> elements) throws MalformedXmlException;  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java index 4d67162b442d..d551953477d8 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategory.java @@ -59,4 +59,12 @@ public class DataCategory implements AslMarshallable {          }          return XmlUtils.listOf(dataCategoryEle);      } + +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    @Override +    public List<Element> toHrDomElements(Document doc) { +        throw new IllegalStateException( +                "Turning DataCategory or DataType into human-readable DOM elements requires" +                        + " visibility into parent elements. The logic resides in DataLabels."); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java index 37d99e7ef85e..90424fe00504 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataCategoryFactory.java @@ -50,4 +50,31 @@ public class DataCategoryFactory implements AslMarshallableFactory<DataCategory>          return new DataCategory(categoryName, dataTypeMap);      } + +    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ +    @Override +    public DataCategory createFromOdElements(List<Element> elements) throws MalformedXmlException { +        Element dataCategoryEle = XmlUtils.getSingleElement(elements); +        Map<String, DataType> dataTypeMap = new LinkedHashMap<String, DataType>(); +        String categoryName = dataCategoryEle.getAttribute(XmlUtils.OD_ATTR_NAME); +        var odDataTypes = XmlUtils.asElementList(dataCategoryEle.getChildNodes()); +        for (Element odDataTypeEle : odDataTypes) { +            String dataTypeName = odDataTypeEle.getAttribute(XmlUtils.OD_ATTR_NAME); +            if (!DataTypeConstants.getValidDataTypes().containsKey(categoryName)) { +                throw new MalformedXmlException( +                        String.format("Unrecognized data category %s", categoryName)); +            } +            if (!DataTypeConstants.getValidDataTypes().get(categoryName).contains(dataTypeName)) { +                throw new MalformedXmlException( +                        String.format( +                                "Unrecognized data type name %s for category %s", +                                dataTypeName, categoryName)); +            } +            dataTypeMap.put( +                    dataTypeName, +                    new DataTypeFactory().createFromOdElements(XmlUtils.listOf(odDataTypeEle))); +        } + +        return new DataCategory(categoryName, dataTypeMap); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java index 7516faf9f77a..4a0d75977d78 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabels.java @@ -79,6 +79,16 @@ public class DataLabels implements AslMarshallable {          return XmlUtils.listOf(dataLabelsEle);      } +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    @Override +    public List<Element> toHrDomElements(Document doc) { +        Element dataLabelsEle = doc.createElement(XmlUtils.HR_TAG_DATA_LABELS); +        maybeAppendHrDataUsages(doc, dataLabelsEle, mDataAccessed, XmlUtils.HR_TAG_DATA_ACCESSED); +        maybeAppendHrDataUsages(doc, dataLabelsEle, mDataCollected, XmlUtils.HR_TAG_DATA_COLLECTED); +        maybeAppendHrDataUsages(doc, dataLabelsEle, mDataShared, XmlUtils.HR_TAG_DATA_SHARED); +        return XmlUtils.listOf(dataLabelsEle); +    } +      private void maybeAppendDataUsages(              Document doc,              Element dataLabelsEle, @@ -100,4 +110,42 @@ public class DataLabels implements AslMarshallable {          }          dataLabelsEle.appendChild(dataUsageEle);      } + +    private void maybeAppendHrDataUsages( +            Document doc, +            Element dataLabelsEle, +            Map<String, DataCategory> dataCategoriesMap, +            String dataUsageTypeName) { +        if (dataCategoriesMap.isEmpty()) { +            return; +        } +        for (String dataCategoryName : dataCategoriesMap.keySet()) { +            DataCategory dataCategory = dataCategoriesMap.get(dataCategoryName); +            for (String dataTypeName : dataCategory.getDataTypes().keySet()) { +                DataType dataType = dataCategory.getDataTypes().get(dataTypeName); +                // XmlUtils.appendChildren(dataLabelsEle, dataType.toHrDomElements(doc)); +                Element hrDataTypeEle = doc.createElement(dataUsageTypeName); +                hrDataTypeEle.setAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY, dataCategoryName); +                hrDataTypeEle.setAttribute(XmlUtils.HR_ATTR_DATA_TYPE, dataTypeName); +                XmlUtils.maybeSetHrBoolAttr( +                        hrDataTypeEle, +                        XmlUtils.HR_ATTR_IS_COLLECTION_OPTIONAL, +                        dataType.getIsCollectionOptional()); +                XmlUtils.maybeSetHrBoolAttr( +                        hrDataTypeEle, +                        XmlUtils.HR_ATTR_IS_SHARING_OPTIONAL, +                        dataType.getIsSharingOptional()); +                XmlUtils.maybeSetHrBoolAttr( +                        hrDataTypeEle, XmlUtils.HR_ATTR_EPHEMERAL, dataType.getEphemeral()); +                hrDataTypeEle.setAttribute( +                        XmlUtils.HR_ATTR_PURPOSES, +                        String.join( +                                "|", +                                dataType.getPurposes().stream() +                                        .map(DataType.Purpose::toString) +                                        .toList())); +                dataLabelsEle.appendChild(hrDataTypeEle); +            } +        } +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java index dc77fd08aa53..5473e010cc65 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataLabelsFactory.java @@ -22,7 +22,6 @@ import com.android.asllib.util.MalformedXmlException;  import com.android.asllib.util.XmlUtils;  import org.w3c.dom.Element; -import org.w3c.dom.NodeList;  import java.util.HashSet;  import java.util.LinkedHashMap; @@ -46,9 +45,82 @@ public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> {                  getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_COLLECTED);          Map<String, DataCategory> dataShared =                  getDataCategoriesWithTag(ele, XmlUtils.HR_TAG_DATA_SHARED); +        DataLabels dataLabels = new DataLabels(dataAccessed, dataCollected, dataShared); +        validateIsXOptional(dataLabels); +        return dataLabels; +    } + +    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ +    @Override +    public DataLabels createFromOdElements(List<Element> elements) throws MalformedXmlException { +        Element dataLabelsEle = XmlUtils.getSingleElement(elements); +        if (dataLabelsEle == null) { +            AslgenUtil.logI("Found no DataLabels in od format."); +            return null; +        } +        Map<String, DataCategory> dataAccessed = +                getOdDataCategoriesWithTag(dataLabelsEle, XmlUtils.OD_NAME_DATA_ACCESSED); +        Map<String, DataCategory> dataCollected = +                getOdDataCategoriesWithTag(dataLabelsEle, XmlUtils.OD_NAME_DATA_COLLECTED); +        Map<String, DataCategory> dataShared = +                getOdDataCategoriesWithTag(dataLabelsEle, XmlUtils.OD_NAME_DATA_SHARED); +        DataLabels dataLabels = new DataLabels(dataAccessed, dataCollected, dataShared); +        validateIsXOptional(dataLabels); +        return dataLabels; +    } + +    private static Map<String, DataCategory> getOdDataCategoriesWithTag( +            Element dataLabelsEle, String dataCategoryUsageTypeTag) throws MalformedXmlException { +        Map<String, DataCategory> dataCategoryMap = new LinkedHashMap<String, DataCategory>(); +        Element dataUsageEle = +                XmlUtils.getOdPbundleWithName(dataLabelsEle, dataCategoryUsageTypeTag, false); +        if (dataUsageEle == null) { +            return dataCategoryMap; +        } +        List<Element> dataCategoryEles = XmlUtils.asElementList(dataUsageEle.getChildNodes()); +        for (Element dataCategoryEle : dataCategoryEles) { +            String dataCategoryName = dataCategoryEle.getAttribute(XmlUtils.OD_ATTR_NAME); +            DataCategory dataCategory = +                    new DataCategoryFactory().createFromOdElements(List.of(dataCategoryEle)); +            dataCategoryMap.put(dataCategoryName, dataCategory); +        } +        return dataCategoryMap; +    } +    private static Map<String, DataCategory> getDataCategoriesWithTag( +            Element dataLabelsEle, String dataCategoryUsageTypeTag) throws MalformedXmlException { +        List<Element> dataUsedElements = +                XmlUtils.getChildrenByTagName(dataLabelsEle, dataCategoryUsageTypeTag); +        Map<String, DataCategory> dataCategoryMap = new LinkedHashMap<String, DataCategory>(); + +        Set<String> dataCategoryNames = new HashSet<String>(); +        for (int i = 0; i < dataUsedElements.size(); i++) { +            Element dataUsedEle = dataUsedElements.get(i); +            String dataCategoryName = dataUsedEle.getAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY); +            if (!DataCategoryConstants.getValidDataCategories().contains(dataCategoryName)) { +                throw new MalformedXmlException( +                        String.format("Unrecognized category name: %s", dataCategoryName)); +            } +            dataCategoryNames.add(dataCategoryName); +        } +        for (String dataCategoryName : dataCategoryNames) { +            var dataCategoryElements = +                    dataUsedElements.stream() +                            .filter( +                                    ele -> +                                            ele.getAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY) +                                                    .equals(dataCategoryName)) +                            .toList(); +            DataCategory dataCategory = +                    new DataCategoryFactory().createFromHrElements(dataCategoryElements); +            dataCategoryMap.put(dataCategoryName, dataCategory); +        } +        return dataCategoryMap; +    } + +    private void validateIsXOptional(DataLabels dataLabels) throws MalformedXmlException {          // Validate booleans such as isCollectionOptional, isSharingOptional. -        for (DataCategory dataCategory : dataAccessed.values()) { +        for (DataCategory dataCategory : dataLabels.getDataAccessed().values()) {              for (DataType dataType : dataCategory.getDataTypes().values()) {                  if (dataType.getIsSharingOptional() != null) {                      throw new MalformedXmlException( @@ -66,7 +138,7 @@ public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> {                  }              }          } -        for (DataCategory dataCategory : dataCollected.values()) { +        for (DataCategory dataCategory : dataLabels.getDataCollected().values()) {              for (DataType dataType : dataCategory.getDataTypes().values()) {                  if (dataType.getIsSharingOptional() != null) {                      throw new MalformedXmlException( @@ -77,7 +149,7 @@ public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> {                  }              }          } -        for (DataCategory dataCategory : dataShared.values()) { +        for (DataCategory dataCategory : dataLabels.getDataShared().values()) {              for (DataType dataType : dataCategory.getDataTypes().values()) {                  if (dataType.getIsCollectionOptional() != null) {                      throw new MalformedXmlException( @@ -88,37 +160,5 @@ public class DataLabelsFactory implements AslMarshallableFactory<DataLabels> {                  }              }          } - -        return new DataLabels(dataAccessed, dataCollected, dataShared); -    } - -    private static Map<String, DataCategory> getDataCategoriesWithTag( -            Element dataLabelsEle, String dataCategoryUsageTypeTag) throws MalformedXmlException { -        NodeList dataUsedNodeList = dataLabelsEle.getElementsByTagName(dataCategoryUsageTypeTag); -        Map<String, DataCategory> dataCategoryMap = new LinkedHashMap<String, DataCategory>(); - -        Set<String> dataCategoryNames = new HashSet<String>(); -        for (int i = 0; i < dataUsedNodeList.getLength(); i++) { -            Element dataUsedEle = (Element) dataUsedNodeList.item(i); -            String dataCategoryName = dataUsedEle.getAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY); -            if (!DataCategoryConstants.getValidDataCategories().contains(dataCategoryName)) { -                throw new MalformedXmlException( -                        String.format("Unrecognized category name: %s", dataCategoryName)); -            } -            dataCategoryNames.add(dataCategoryName); -        } -        for (String dataCategoryName : dataCategoryNames) { -            var dataCategoryElements = -                    XmlUtils.asElementList(dataUsedNodeList).stream() -                            .filter( -                                    ele -> -                                            ele.getAttribute(XmlUtils.HR_ATTR_DATA_CATEGORY) -                                                    .equals(dataCategoryName)) -                            .toList(); -            DataCategory dataCategory = -                    new DataCategoryFactory().createFromHrElements(dataCategoryElements); -            dataCategoryMap.put(dataCategoryName, dataCategory); -        } -        return dataCategoryMap;      }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java index 347136237966..97304cb36081 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataType.java @@ -160,6 +160,14 @@ public class DataType implements AslMarshallable {          return XmlUtils.listOf(dataTypeEle);      } +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    @Override +    public List<Element> toHrDomElements(Document doc) { +        throw new IllegalStateException( +                "Turning DataCategory or DataType into human-readable DOM elements requires" +                        + " visibility into parent elements. The logic resides in DataLabels."); +    } +      private static void maybeAddBoolToOdElement(              Document doc, Element parentEle, Boolean b, String odName) {          if (b == null) { diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java index ed434cda0823..488c2595912a 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DataTypeFactory.java @@ -51,4 +51,31 @@ public class DataTypeFactory implements AslMarshallableFactory<DataType> {          return new DataType(                  dataTypeName, purposes, isCollectionOptional, isSharingOptional, ephemeral);      } + +    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ +    @Override +    public DataType createFromOdElements(List<Element> elements) throws MalformedXmlException { +        Element odDataTypeEle = XmlUtils.getSingleElement(elements); +        String dataTypeName = odDataTypeEle.getAttribute(XmlUtils.OD_ATTR_NAME); +        List<Integer> purposeInts = +                XmlUtils.getOdIntArray(odDataTypeEle, XmlUtils.OD_NAME_PURPOSES, true); +        List<DataType.Purpose> purposes = +                purposeInts.stream().map(DataType.Purpose::forValue).collect(Collectors.toList()); +        if (purposes.isEmpty()) { +            throw new MalformedXmlException(String.format("Found no purpose in: %s", dataTypeName)); +        } +        if (new HashSet<>(purposes).size() != purposes.size()) { +            throw new MalformedXmlException( +                    String.format("Found non-unique purposes in: %s", dataTypeName)); +        } +        Boolean isCollectionOptional = +                XmlUtils.getOdBoolEle( +                        odDataTypeEle, XmlUtils.OD_NAME_IS_COLLECTION_OPTIONAL, false); +        Boolean isSharingOptional = +                XmlUtils.getOdBoolEle(odDataTypeEle, XmlUtils.OD_NAME_IS_SHARING_OPTIONAL, false); +        Boolean ephemeral = XmlUtils.getOdBoolEle(odDataTypeEle, XmlUtils.OD_NAME_EPHEMERAL, false); + +        return new DataType( +                dataTypeName, purposes, isCollectionOptional, isSharingOptional, ephemeral); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java index 382a1f0d0eca..94fad9607880 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfo.java @@ -139,4 +139,35 @@ public class DeveloperInfo implements AslMarshallable {          return XmlUtils.listOf(developerInfoEle);      } + +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    @Override +    public List<Element> toHrDomElements(Document doc) { +        Element developerInfoEle = doc.createElement(XmlUtils.HR_TAG_DEVELOPER_INFO); +        if (mName != null) { +            developerInfoEle.setAttribute(XmlUtils.HR_ATTR_NAME, mName); +        } +        if (mEmail != null) { +            developerInfoEle.setAttribute(XmlUtils.HR_ATTR_EMAIL, mEmail); +        } +        if (mAddress != null) { +            developerInfoEle.setAttribute(XmlUtils.HR_ATTR_ADDRESS, mAddress); +        } +        if (mCountryRegion != null) { +            developerInfoEle.setAttribute(XmlUtils.HR_ATTR_COUNTRY_REGION, mCountryRegion); +        } +        if (mDeveloperRelationship != null) { +            developerInfoEle.setAttribute( +                    XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP, mDeveloperRelationship.toString()); +        } +        if (mWebsite != null) { +            developerInfoEle.setAttribute(XmlUtils.HR_ATTR_WEBSITE, mWebsite); +        } +        if (mAppDeveloperRegistryId != null) { +            developerInfoEle.setAttribute( +                    XmlUtils.HR_ATTR_APP_DEVELOPER_REGISTRY_ID, mAppDeveloperRegistryId); +        } + +        return XmlUtils.listOf(developerInfoEle); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java index b5310bac232a..0f3b41cd5d1a 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/DeveloperInfoFactory.java @@ -34,15 +34,15 @@ public class DeveloperInfoFactory implements AslMarshallableFactory<DeveloperInf              AslgenUtil.logI("No DeveloperInfo found in hr format.");              return null;          } -        String name = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_NAME); -        String email = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_EMAIL); -        String address = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_ADDRESS); +        String name = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_NAME, true); +        String email = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_EMAIL, true); +        String address = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_ADDRESS, true);          String countryRegion = -                XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_COUNTRY_REGION); +                XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_COUNTRY_REGION, true);          DeveloperInfo.DeveloperRelationship developerRelationship =                  DeveloperInfo.DeveloperRelationship.forString(                          XmlUtils.getStringAttr( -                                developerInfoEle, XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP)); +                                developerInfoEle, XmlUtils.HR_ATTR_DEVELOPER_RELATIONSHIP, true));          String website = XmlUtils.getStringAttr(developerInfoEle, XmlUtils.HR_ATTR_WEBSITE, false);          String appDeveloperRegistryId =                  XmlUtils.getStringAttr( @@ -57,4 +57,40 @@ public class DeveloperInfoFactory implements AslMarshallableFactory<DeveloperInf                  website,                  appDeveloperRegistryId);      } + +    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ +    @Override +    public DeveloperInfo createFromOdElements(List<Element> elements) throws MalformedXmlException { +        Element developerInfoEle = XmlUtils.getSingleElement(elements); +        if (developerInfoEle == null) { +            AslgenUtil.logI("No DeveloperInfo found in od format."); +            return null; +        } +        String name = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_NAME, true); +        String email = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_EMAIL, true); +        String address = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_ADDRESS, true); +        String countryRegion = +                XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_COUNTRY_REGION, true); +        DeveloperInfo.DeveloperRelationship developerRelationship = +                DeveloperInfo.DeveloperRelationship.forValue( +                        (int) +                                (long) +                                        XmlUtils.getOdLongEle( +                                                developerInfoEle, +                                                XmlUtils.OD_NAME_DEVELOPER_RELATIONSHIP, +                                                true)); +        String website = XmlUtils.getOdStringEle(developerInfoEle, XmlUtils.OD_NAME_WEBSITE, false); +        String appDeveloperRegistryId = +                XmlUtils.getOdStringEle( +                        developerInfoEle, XmlUtils.OD_NAME_APP_DEVELOPER_REGISTRY_ID, false); + +        return new DeveloperInfo( +                name, +                email, +                address, +                countryRegion, +                developerRelationship, +                website, +                appDeveloperRegistryId); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java index 8c2186a628e3..6af80715f7c1 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabels.java @@ -70,4 +70,22 @@ public class SafetyLabels implements AslMarshallable {          }          return XmlUtils.listOf(safetyLabelsEle);      } + +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    @Override +    public List<Element> toHrDomElements(Document doc) { +        Element safetyLabelsEle = doc.createElement(XmlUtils.HR_TAG_SAFETY_LABELS); +        safetyLabelsEle.setAttribute(XmlUtils.HR_ATTR_VERSION, String.valueOf(mVersion)); + +        if (mDataLabels != null) { +            XmlUtils.appendChildren(safetyLabelsEle, mDataLabels.toHrDomElements(doc)); +        } +        if (mSecurityLabels != null) { +            XmlUtils.appendChildren(safetyLabelsEle, mSecurityLabels.toHrDomElements(doc)); +        } +        if (mThirdPartyVerification != null) { +            XmlUtils.appendChildren(safetyLabelsEle, mThirdPartyVerification.toHrDomElements(doc)); +        } +        return XmlUtils.listOf(safetyLabelsEle); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java index 0f7aa8161c64..2644b435311b 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SafetyLabelsFactory.java @@ -62,4 +62,41 @@ public class SafetyLabelsFactory implements AslMarshallableFactory<SafetyLabels>                                                  false)));          return new SafetyLabels(version, dataLabels, securityLabels, thirdPartyVerification);      } + +    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ +    @Override +    public SafetyLabels createFromOdElements(List<Element> elements) throws MalformedXmlException { +        Element safetyLabelsEle = XmlUtils.getSingleElement(elements); +        if (safetyLabelsEle == null) { +            AslgenUtil.logI("No SafetyLabels found in od format."); +            return null; +        } +        Long version = XmlUtils.getOdLongEle(safetyLabelsEle, XmlUtils.OD_NAME_VERSION, true); + +        DataLabels dataLabels = +                new DataLabelsFactory() +                        .createFromOdElements( +                                XmlUtils.listOf( +                                        XmlUtils.getOdPbundleWithName( +                                                safetyLabelsEle, +                                                XmlUtils.OD_NAME_DATA_LABELS, +                                                false))); +        SecurityLabels securityLabels = +                new SecurityLabelsFactory() +                        .createFromOdElements( +                                XmlUtils.listOf( +                                        XmlUtils.getOdPbundleWithName( +                                                safetyLabelsEle, +                                                XmlUtils.OD_NAME_SECURITY_LABELS, +                                                false))); +        ThirdPartyVerification thirdPartyVerification = +                new ThirdPartyVerificationFactory() +                        .createFromOdElements( +                                XmlUtils.listOf( +                                        XmlUtils.getOdPbundleWithName( +                                                safetyLabelsEle, +                                                XmlUtils.OD_NAME_THIRD_PARTY_VERIFICATION, +                                                false))); +        return new SafetyLabels(version, dataLabels, securityLabels, thirdPartyVerification); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java index 529b50364255..48643ba0e3ab 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabels.java @@ -50,4 +50,17 @@ public class SecurityLabels implements AslMarshallable {          }          return XmlUtils.listOf(ele);      } + +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    @Override +    public List<Element> toHrDomElements(Document doc) { +        Element ele = doc.createElement(XmlUtils.HR_TAG_SECURITY_LABELS); +        if (mIsDataDeletable != null) { +            ele.setAttribute(XmlUtils.HR_ATTR_IS_DATA_DELETABLE, String.valueOf(mIsDataDeletable)); +        } +        if (mIsDataEncrypted != null) { +            ele.setAttribute(XmlUtils.HR_ATTR_IS_DATA_ENCRYPTED, String.valueOf(mIsDataEncrypted)); +        } +        return XmlUtils.listOf(ele); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java index 84024520035e..525a80388261 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SecurityLabelsFactory.java @@ -41,4 +41,20 @@ public class SecurityLabelsFactory implements AslMarshallableFactory<SecurityLab                  XmlUtils.getBoolAttr(ele, XmlUtils.HR_ATTR_IS_DATA_ENCRYPTED, false);          return new SecurityLabels(isDataDeletable, isDataEncrypted);      } + +    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ +    @Override +    public SecurityLabels createFromOdElements(List<Element> elements) +            throws MalformedXmlException { +        Element ele = XmlUtils.getSingleElement(elements); +        if (ele == null) { +            AslgenUtil.logI("No SecurityLabels found in od format."); +            return null; +        } +        Boolean isDataDeletable = +                XmlUtils.getOdBoolEle(ele, XmlUtils.OD_NAME_IS_DATA_DELETABLE, false); +        Boolean isDataEncrypted = +                XmlUtils.getOdBoolEle(ele, XmlUtils.OD_NAME_IS_DATA_ENCRYPTED, false); +        return new SecurityLabels(isDataDeletable, isDataEncrypted); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java index 595d748b59af..854c0d0ac3e1 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabel.java @@ -46,4 +46,13 @@ public class SystemAppSafetyLabel implements AslMarshallable {                  XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_URL, mUrl));          return XmlUtils.listOf(systemAppSafetyLabelEle);      } + +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    @Override +    public List<Element> toHrDomElements(Document doc) { +        Element systemAppSafetyLabelEle = +                doc.createElement(XmlUtils.HR_TAG_SYSTEM_APP_SAFETY_LABEL); +        systemAppSafetyLabelEle.setAttribute(XmlUtils.HR_ATTR_URL, mUrl); +        return XmlUtils.listOf(systemAppSafetyLabelEle); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java index f99955993d6c..c8e22b6c42cd 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/SystemAppSafetyLabelFactory.java @@ -36,7 +36,20 @@ public class SystemAppSafetyLabelFactory implements AslMarshallableFactory<Syste              return null;          } -        String url = XmlUtils.getStringAttr(systemAppSafetyLabelEle, XmlUtils.HR_ATTR_URL); +        String url = XmlUtils.getStringAttr(systemAppSafetyLabelEle, XmlUtils.HR_ATTR_URL, true); +        return new SystemAppSafetyLabel(url); +    } + +    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ +    @Override +    public SystemAppSafetyLabel createFromOdElements(List<Element> elements) +            throws MalformedXmlException { +        Element systemAppSafetyLabelEle = XmlUtils.getSingleElement(elements); +        if (systemAppSafetyLabelEle == null) { +            AslgenUtil.logI("No SystemAppSafetyLabel found in od format."); +            return null; +        } +        String url = XmlUtils.getOdStringEle(systemAppSafetyLabelEle, XmlUtils.OD_NAME_URL, true);          return new SystemAppSafetyLabel(url);      }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java index a1b22f885fe6..d74f3f062513 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerification.java @@ -40,4 +40,12 @@ public class ThirdPartyVerification implements AslMarshallable {          ele.appendChild(XmlUtils.createOdStringEle(doc, XmlUtils.OD_NAME_URL, mUrl));          return XmlUtils.listOf(ele);      } + +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    @Override +    public List<Element> toHrDomElements(Document doc) { +        Element ele = doc.createElement(XmlUtils.HR_TAG_THIRD_PARTY_VERIFICATION); +        ele.setAttribute(XmlUtils.HR_ATTR_URL, mUrl); +        return XmlUtils.listOf(ele); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java index c3e4964c0b9d..197e7aa77743 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/ThirdPartyVerificationFactory.java @@ -37,7 +37,21 @@ public class ThirdPartyVerificationFactory              return null;          } -        String url = XmlUtils.getStringAttr(ele, XmlUtils.HR_ATTR_URL); +        String url = XmlUtils.getStringAttr(ele, XmlUtils.HR_ATTR_URL, true); +        return new ThirdPartyVerification(url); +    } + +    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ +    @Override +    public ThirdPartyVerification createFromOdElements(List<Element> elements) +            throws MalformedXmlException { +        Element ele = XmlUtils.getSingleElement(elements); +        if (ele == null) { +            AslgenUtil.logI("No ThirdPartyVerification found in od format."); +            return null; +        } + +        String url = XmlUtils.getOdStringEle(ele, XmlUtils.OD_NAME_URL, true);          return new ThirdPartyVerification(url);      }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java index ddd3557616ca..6a8700a10d3f 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfo.java @@ -57,4 +57,17 @@ public class TransparencyInfo implements AslMarshallable {          }          return XmlUtils.listOf(transparencyInfoEle);      } + +    /** Creates the human-readable DOM elements from the AslMarshallable Java Object. */ +    @Override +    public List<Element> toHrDomElements(Document doc) { +        Element transparencyInfoEle = doc.createElement(XmlUtils.HR_TAG_TRANSPARENCY_INFO); +        if (mDeveloperInfo != null) { +            XmlUtils.appendChildren(transparencyInfoEle, mDeveloperInfo.toHrDomElements(doc)); +        } +        if (mAppInfo != null) { +            XmlUtils.appendChildren(transparencyInfoEle, mAppInfo.toHrDomElements(doc)); +        } +        return XmlUtils.listOf(transparencyInfoEle); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java index d9c2af41fcac..94c564087918 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/marshallable/TransparencyInfoFactory.java @@ -49,4 +49,28 @@ public class TransparencyInfoFactory implements AslMarshallableFactory<Transpare          return new TransparencyInfo(developerInfo, appInfo);      } + +    /** Creates an {@link AslMarshallableFactory} from on-device DOM elements */ +    @Override +    public TransparencyInfo createFromOdElements(List<Element> elements) +            throws MalformedXmlException { +        Element transparencyInfoEle = XmlUtils.getSingleElement(elements); +        if (transparencyInfoEle == null) { +            AslgenUtil.logI("No TransparencyInfo found in od format."); +            return null; +        } + +        Element developerInfoEle = +                XmlUtils.getOdPbundleWithName( +                        transparencyInfoEle, XmlUtils.OD_NAME_DEVELOPER_INFO, false); +        DeveloperInfo developerInfo = +                new DeveloperInfoFactory().createFromOdElements(XmlUtils.listOf(developerInfoEle)); + +        Element appInfoEle = +                XmlUtils.getOdPbundleWithName( +                        transparencyInfoEle, XmlUtils.OD_NAME_APP_INFO, false); +        AppInfo appInfo = new AppInfoFactory().createFromOdElements(XmlUtils.listOf(appInfoEle)); + +        return new TransparencyInfo(developerInfo, appInfo); +    }  } diff --git a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java index ed3d7f8372d6..1d54ead0a28d 100644 --- a/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java +++ b/tools/app_metadata_bundles/src/lib/java/com/android/asllib/util/XmlUtils.java @@ -16,8 +16,10 @@  package com.android.asllib.util; +  import org.w3c.dom.Document;  import org.w3c.dom.Element; +import org.w3c.dom.Node;  import org.w3c.dom.NodeList;  import java.util.ArrayList; @@ -118,59 +120,37 @@ public class XmlUtils {      public static final String TRUE_STR = "true";      public static final String FALSE_STR = "false"; -    /** Gets the single top-level {@link Element} having the {@param tagName}. */ -    public static Element getSingleElement(Document doc, String tagName) -            throws MalformedXmlException { -        var elements = doc.getElementsByTagName(tagName); -        return getSingleElement(elements, tagName); +    /** Gets the top-level children with the tag name.. */ +    public static List<Element> getChildrenByTagName(Node parentEle, String tagName) { +        var elements = XmlUtils.asElementList(parentEle.getChildNodes()); +        return elements.stream().filter(e -> e.getTagName().equals(tagName)).toList();      }      /**       * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}.       */ -    public static Element getSingleChildElement(Element parentEle, String tagName) +    public static Element getSingleChildElement(Node parentEle, String tagName, boolean required)              throws MalformedXmlException { -        var elements = parentEle.getElementsByTagName(tagName); -        return getSingleElement(elements, tagName, true); -    } +        String parentTagNameForErrorMsg = +                (parentEle instanceof Element) ? ((Element) parentEle).getTagName() : "Node"; +        var elements = getChildrenByTagName(parentEle, tagName); -    /** -     * Gets the single {@link Element} within {@param parentEle} and having the {@param tagName}. -     */ -    public static Element getSingleChildElement(Element parentEle, String tagName, boolean required) -            throws MalformedXmlException { -        var elements = parentEle.getElementsByTagName(tagName); -        return getSingleElement(elements, tagName, required); -    } - -    /** Gets the single {@link Element} from {@param elements} */ -    public static Element getSingleElement(NodeList elements, String tagName) -            throws MalformedXmlException { -        return getSingleElement(elements, tagName, true); -    } - -    /** Gets the single {@link Element} from {@param elements} */ -    public static Element getSingleElement(NodeList elements, String tagName, boolean required) -            throws MalformedXmlException { -        if (elements.getLength() > 1) { +        if (elements.size() > 1) {              throw new MalformedXmlException(                      String.format( -                            "Expected 1 element \"%s\" in NodeList but got %s.", -                            tagName, elements.getLength())); -        } else if (elements.getLength() == 0) { +                            "Expected 1 %s in %s but got %s.", +                            tagName, parentTagNameForErrorMsg, elements.size())); +        } else if (elements.isEmpty()) {              if (required) {                  throw new MalformedXmlException( -                        String.format("Found no element \"%s\" in NodeList.", tagName)); +                        String.format( +                                "Expected 1 %s in %s but got 0.", +                                tagName, parentTagNameForErrorMsg));              } else {                  return null;              }          } -        var elementAsNode = elements.item(0); -        if (!(elementAsNode instanceof Element)) { -            throw new MalformedXmlException( -                    String.format("%s was not a valid XML element.", tagName)); -        } -        return ((Element) elementAsNode); +        return elements.get(0);      }      /** Gets the single {@link Element} within {@param elements}. */ @@ -229,6 +209,13 @@ public class XmlUtils {          return ele;      } +    /** Sets human-readable bool attribute if non-null. */ +    public static void maybeSetHrBoolAttr(Element ele, String attrName, Boolean b) { +        if (b != null) { +            ele.setAttribute(attrName, String.valueOf(b)); +        } +    } +      /** Create an on-device Long DOM Element with the given attribute name. */      public static Element createOdLongEle(Document doc, String name, long l) {          var ele = doc.createElement(XmlUtils.OD_TAG_LONG); @@ -303,6 +290,114 @@ public class XmlUtils {          return b;      } +    /** Gets a Boolean attribute. */ +    public static Boolean getOdBoolEle(Element ele, String nameName, boolean required) +            throws MalformedXmlException { +        List<Element> boolEles = +                XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_BOOLEAN).stream() +                        .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) +                        .toList(); +        if (boolEles.size() > 1) { +            throw new MalformedXmlException( +                    String.format("Found more than one %s in %s.", nameName, ele.getTagName())); +        } +        if (boolEles.isEmpty()) { +            if (required) { +                throw new MalformedXmlException( +                        String.format("Found no %s in %s.", nameName, ele.getTagName())); +            } +            return null; +        } +        Element boolEle = boolEles.get(0); + +        Boolean b = XmlUtils.fromString(boolEle.getAttribute(XmlUtils.OD_ATTR_VALUE)); +        if (b == null && required) { +            throw new MalformedXmlException( +                    String.format( +                            "Boolean %s was required but missing, in %s.", +                            nameName, ele.getTagName())); +        } +        return b; +    } + +    /** Gets an on-device Long attribute. */ +    public static Long getOdLongEle(Element ele, String nameName, boolean required) +            throws MalformedXmlException { +        List<Element> longEles = +                XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_LONG).stream() +                        .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) +                        .toList(); +        if (longEles.size() > 1) { +            throw new MalformedXmlException( +                    String.format("Found more than one %s in %s.", nameName, ele.getTagName())); +        } +        if (longEles.isEmpty()) { +            if (required) { +                throw new MalformedXmlException( +                        String.format("Found no %s in %s.", nameName, ele.getTagName())); +            } +            return null; +        } +        Element longEle = longEles.get(0); +        Long l = null; +        try { +            l = Long.parseLong(longEle.getAttribute(XmlUtils.OD_ATTR_VALUE)); +        } catch (NumberFormatException e) { +            throw new MalformedXmlException( +                    String.format( +                            "%s in %s was not formatted as long", nameName, ele.getTagName())); +        } +        return l; +    } + +    /** Gets an on-device String attribute. */ +    public static String getOdStringEle(Element ele, String nameName, boolean required) +            throws MalformedXmlException { +        List<Element> eles = +                XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_STRING).stream() +                        .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) +                        .toList(); +        if (eles.size() > 1) { +            throw new MalformedXmlException( +                    String.format("Found more than one %s in %s.", nameName, ele.getTagName())); +        } +        if (eles.isEmpty()) { +            if (required) { +                throw new MalformedXmlException( +                        String.format("Found no %s in %s.", nameName, ele.getTagName())); +            } +            return null; +        } +        String str = eles.get(0).getAttribute(XmlUtils.OD_ATTR_VALUE); +        if (XmlUtils.isNullOrEmpty(str) && required) { +            throw new MalformedXmlException( +                    String.format( +                            "%s in %s was empty or missing value", nameName, ele.getTagName())); +        } +        return str; +    } + +    /** Gets a OD Pbundle Element attribute with the specified name. */ +    public static Element getOdPbundleWithName(Element ele, String nameName, boolean required) +            throws MalformedXmlException { +        List<Element> eles = +                XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_PBUNDLE_AS_MAP).stream() +                        .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) +                        .toList(); +        if (eles.size() > 1) { +            throw new MalformedXmlException( +                    String.format("Found more than one %s in %s.", nameName, ele.getTagName())); +        } +        if (eles.isEmpty()) { +            if (required) { +                throw new MalformedXmlException( +                        String.format("Found no %s in %s.", nameName, ele.getTagName())); +            } +            return null; +        } +        return eles.get(0); +    } +      /** Gets a required String attribute. */      public static String getStringAttr(Element ele, String attrName) throws MalformedXmlException {          return getStringAttr(ele, attrName, true); @@ -325,6 +420,60 @@ public class XmlUtils {          return s;      } +    /** Gets on-device style int array. */ +    public static List<Integer> getOdIntArray(Element ele, String nameName, boolean required) +            throws MalformedXmlException { +        List<Element> intArrayEles = +                XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_INT_ARRAY).stream() +                        .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) +                        .toList(); +        if (intArrayEles.size() > 1) { +            throw new MalformedXmlException( +                    String.format("Found more than one %s in %s.", nameName, ele.getTagName())); +        } +        if (intArrayEles.isEmpty()) { +            if (required) { +                throw new MalformedXmlException( +                        String.format("Found no %s in %s.", nameName, ele.getTagName())); +            } +            return null; +        } +        Element intArrayEle = intArrayEles.get(0); +        List<Element> itemEles = XmlUtils.getChildrenByTagName(intArrayEle, XmlUtils.OD_TAG_ITEM); +        List<Integer> ints = new ArrayList<Integer>(); +        for (Element itemEle : itemEles) { +            ints.add(Integer.parseInt(XmlUtils.getStringAttr(itemEle, XmlUtils.OD_ATTR_VALUE))); +        } +        return ints; +    } + +    /** Gets on-device style String array. */ +    public static List<String> getOdStringArray(Element ele, String nameName, boolean required) +            throws MalformedXmlException { +        List<Element> arrayEles = +                XmlUtils.getChildrenByTagName(ele, XmlUtils.OD_TAG_STRING_ARRAY).stream() +                        .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(nameName)) +                        .toList(); +        if (arrayEles.size() > 1) { +            throw new MalformedXmlException( +                    String.format("Found more than one %s in %s.", nameName, ele.getTagName())); +        } +        if (arrayEles.isEmpty()) { +            if (required) { +                throw new MalformedXmlException( +                        String.format("Found no %s in %s.", nameName, ele.getTagName())); +            } +            return null; +        } +        Element arrayEle = arrayEles.get(0); +        List<Element> itemEles = XmlUtils.getChildrenByTagName(arrayEle, XmlUtils.OD_TAG_ITEM); +        List<String> strs = new ArrayList<String>(); +        for (Element itemEle : itemEles) { +            strs.add(XmlUtils.getStringAttr(itemEle, XmlUtils.OD_ATTR_VALUE, true)); +        } +        return strs; +    } +      /**       * Utility method for making a List from one element, to support easier refactoring if needed.       * For example, List.of() doesn't support null elements. diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java index e2588d7bb3e7..d2e0fc338243 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/AslgenTests.java @@ -56,18 +56,35 @@ public class AslgenTests {              InputStream hrStream =                      getClass().getClassLoader().getResourceAsStream(hrPath.toString()); -            String hrContents = new String(hrStream.readAllBytes(), StandardCharsets.UTF_8); +            String hrContents = +                    TestUtils.getFormattedXml( +                            new String(hrStream.readAllBytes(), StandardCharsets.UTF_8), false);              InputStream odStream =                      getClass().getClassLoader().getResourceAsStream(odPath.toString()); -            String odContents = new String(odStream.readAllBytes(), StandardCharsets.UTF_8); -            AndroidSafetyLabel asl = +            String odContents = +                    TestUtils.getFormattedXml( +                            new String(odStream.readAllBytes(), StandardCharsets.UTF_8), false); +            AndroidSafetyLabel aslFromHr =                      AslConverter.readFromString(hrContents, AslConverter.Format.HUMAN_READABLE); -            String out = AslConverter.getXmlAsString(asl, AslConverter.Format.ON_DEVICE); -            System.out.println("out: " + out); +            String aslToOdStr = +                    TestUtils.getFormattedXml( +                            AslConverter.getXmlAsString(aslFromHr, AslConverter.Format.ON_DEVICE), +                            false); +            AndroidSafetyLabel aslFromOd = +                    AslConverter.readFromString(odContents, AslConverter.Format.ON_DEVICE); +            String aslToHrStr = +                    TestUtils.getFormattedXml( +                            AslConverter.getXmlAsString( +                                    aslFromOd, AslConverter.Format.HUMAN_READABLE), +                            false); -            assertEquals( -                    TestUtils.getFormattedXml(out, false), -                    TestUtils.getFormattedXml(odContents, false)); +            System.out.println("od expected: " + odContents); +            System.out.println("asl to od: " + aslToOdStr); +            assertEquals(odContents, aslToOdStr); + +            System.out.println("hr expected: " + hrContents); +            System.out.println("asl to hr: " + aslToHrStr); +            assertEquals(hrContents, aslToHrStr);          }      }  } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java index 013700728e50..61a78232801c 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AndroidSafetyLabelTest.java @@ -22,7 +22,6 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.junit.runners.JUnit4; -import org.w3c.dom.Document;  @RunWith(JUnit4.class)  public class AndroidSafetyLabelTest { @@ -38,12 +37,9 @@ public class AndroidSafetyLabelTest {              "with-system-app-safety-label.xml";      private static final String WITH_TRANSPARENCY_INFO_FILE_NAME = "with-transparency-info.xml"; -    private Document mDoc = null; -      @Before      public void setUp() throws Exception {          System.out.println("set up."); -        mDoc = TestUtils.document();      }      /** Test for android safety label missing version. */ @@ -51,6 +47,7 @@ public class AndroidSafetyLabelTest {      public void testAndroidSafetyLabelMissingVersion() throws Exception {          System.out.println("starting testAndroidSafetyLabelMissingVersion.");          hrToOdExpectException(MISSING_VERSION_FILE_NAME); +        odToHrExpectException(MISSING_VERSION_FILE_NAME);      }      /** Test for android safety label valid empty. */ @@ -58,6 +55,7 @@ public class AndroidSafetyLabelTest {      public void testAndroidSafetyLabelValidEmptyFile() throws Exception {          System.out.println("starting testAndroidSafetyLabelValidEmptyFile.");          testHrToOdAndroidSafetyLabel(VALID_EMPTY_FILE_NAME); +        testOdToHrAndroidSafetyLabel(VALID_EMPTY_FILE_NAME);      }      /** Test for android safety label with safety labels. */ @@ -65,6 +63,7 @@ public class AndroidSafetyLabelTest {      public void testAndroidSafetyLabelWithSafetyLabels() throws Exception {          System.out.println("starting testAndroidSafetyLabelWithSafetyLabels.");          testHrToOdAndroidSafetyLabel(WITH_SAFETY_LABELS_FILE_NAME); +        testOdToHrAndroidSafetyLabel(WITH_SAFETY_LABELS_FILE_NAME);      }      /** Test for android safety label with system app safety label. */ @@ -72,6 +71,7 @@ public class AndroidSafetyLabelTest {      public void testAndroidSafetyLabelWithSystemAppSafetyLabel() throws Exception {          System.out.println("starting testAndroidSafetyLabelWithSystemAppSafetyLabel.");          testHrToOdAndroidSafetyLabel(WITH_SYSTEM_APP_SAFETY_LABEL_FILE_NAME); +        testOdToHrAndroidSafetyLabel(WITH_SYSTEM_APP_SAFETY_LABEL_FILE_NAME);      }      /** Test for android safety label with transparency info. */ @@ -79,6 +79,7 @@ public class AndroidSafetyLabelTest {      public void testAndroidSafetyLabelWithTransparencyInfo() throws Exception {          System.out.println("starting testAndroidSafetyLabelWithTransparencyInfo.");          testHrToOdAndroidSafetyLabel(WITH_TRANSPARENCY_INFO_FILE_NAME); +        testOdToHrAndroidSafetyLabel(WITH_TRANSPARENCY_INFO_FILE_NAME);      }      private void hrToOdExpectException(String fileName) { @@ -86,12 +87,26 @@ public class AndroidSafetyLabelTest {                  new AndroidSafetyLabelFactory(), ANDROID_SAFETY_LABEL_HR_PATH, fileName);      } +    private void odToHrExpectException(String fileName) { +        TestUtils.odToHrExpectException( +                new AndroidSafetyLabelFactory(), ANDROID_SAFETY_LABEL_OD_PATH, fileName); +    } +      private void testHrToOdAndroidSafetyLabel(String fileName) throws Exception {          TestUtils.testHrToOd( -                mDoc, +                TestUtils.document(),                  new AndroidSafetyLabelFactory(),                  ANDROID_SAFETY_LABEL_HR_PATH,                  ANDROID_SAFETY_LABEL_OD_PATH,                  fileName);      } + +    private void testOdToHrAndroidSafetyLabel(String fileName) throws Exception { +        TestUtils.testOdToHr( +                TestUtils.document(), +                new AndroidSafetyLabelFactory(), +                ANDROID_SAFETY_LABEL_OD_PATH, +                ANDROID_SAFETY_LABEL_HR_PATH, +                fileName); +    }  } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java index a015e2eacac5..9e91c6f22641 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/AppInfoTest.java @@ -25,7 +25,6 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.junit.runners.JUnit4; -import org.w3c.dom.Document;  import java.nio.file.Paths;  import java.util.List; @@ -48,19 +47,31 @@ public class AppInfoTest {                      "serviceProviderEndpoints",                      "category",                      "email"); +    public static final List<String> REQUIRED_FIELD_NAMES_OD = +            List.of( +                    "title", +                    "description", +                    "contains_ads", +                    "obey_aps", +                    "ads_fingerprinting", +                    "security_fingerprinting", +                    "privacy_policy", +                    "security_endpoint", +                    "first_party_endpoint", +                    "service_provider_endpoint", +                    "category", +                    "email");      public static final List<String> OPTIONAL_FIELD_NAMES = List.of("website"); +    public static final List<String> OPTIONAL_FIELD_NAMES_OD = List.of("website");      private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml"; -    private Document mDoc = null; -      /** Logic for setting up tests (empty if not yet needed). */      public static void main(String[] params) throws Exception {}      @Before      public void setUp() throws Exception {          System.out.println("set up."); -        mDoc = TestUtils.document();      }      /** Test for all fields valid. */ @@ -68,6 +79,7 @@ public class AppInfoTest {      public void testAllFieldsValid() throws Exception {          System.out.println("starting testAllFieldsValid.");          testHrToOdAppInfo(ALL_FIELDS_VALID_FILE_NAME); +        testOdToHrAppInfo(ALL_FIELDS_VALID_FILE_NAME);      }      /** Tests missing required fields fails. */ @@ -75,7 +87,7 @@ public class AppInfoTest {      public void testMissingRequiredFields() throws Exception {          System.out.println("Starting testMissingRequiredFields");          for (String reqField : REQUIRED_FIELD_NAMES) { -            System.out.println("testing missing required field: " + reqField); +            System.out.println("testing missing required field hr: " + reqField);              var appInfoEle =                      TestUtils.getElementsFromResource(                              Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME)); @@ -85,6 +97,17 @@ public class AppInfoTest {                      MalformedXmlException.class,                      () -> new AppInfoFactory().createFromHrElements(appInfoEle));          } + +        for (String reqField : REQUIRED_FIELD_NAMES_OD) { +            System.out.println("testing missing required field od: " + reqField); +            var appInfoEle = +                    TestUtils.getElementsFromResource( +                            Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); +            TestUtils.removeOdChildEleWithName(appInfoEle.get(0), reqField); +            assertThrows( +                    MalformedXmlException.class, +                    () -> new AppInfoFactory().createFromOdElements(appInfoEle)); +        }      }      /** Tests missing optional fields passes. */ @@ -96,12 +119,34 @@ public class AppInfoTest {                              Paths.get(APP_INFO_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));              ele.get(0).removeAttribute(optField);              AppInfo appInfo = new AppInfoFactory().createFromHrElements(ele); -            appInfo.toOdDomElements(mDoc); +            appInfo.toOdDomElements(TestUtils.document()); +        } + +        for (String optField : OPTIONAL_FIELD_NAMES_OD) { +            var ele = +                    TestUtils.getElementsFromResource( +                            Paths.get(APP_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); +            TestUtils.removeOdChildEleWithName(ele.get(0), optField); +            AppInfo appInfo = new AppInfoFactory().createFromOdElements(ele); +            appInfo.toHrDomElements(TestUtils.document());          }      }      private void testHrToOdAppInfo(String fileName) throws Exception {          TestUtils.testHrToOd( -                mDoc, new AppInfoFactory(), APP_INFO_HR_PATH, APP_INFO_OD_PATH, fileName); +                TestUtils.document(), +                new AppInfoFactory(), +                APP_INFO_HR_PATH, +                APP_INFO_OD_PATH, +                fileName); +    } + +    private void testOdToHrAppInfo(String fileName) throws Exception { +        TestUtils.testOdToHr( +                TestUtils.document(), +                new AppInfoFactory(), +                APP_INFO_OD_PATH, +                APP_INFO_HR_PATH, +                fileName);      }  } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataCategoryTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataCategoryTest.java index 822f1753f662..ebb31865843f 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataCategoryTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataCategoryTest.java @@ -22,7 +22,6 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.junit.runners.JUnit4; -import org.w3c.dom.Document;  @RunWith(JUnit4.class)  public class DataCategoryTest { @@ -57,15 +56,12 @@ public class DataCategoryTest {              "data-category-personal-unrecognized-type.xml";      private static final String UNRECOGNIZED_CATEGORY_FILE_NAME = "data-category-unrecognized.xml"; -    private Document mDoc = null; -      /** Logic for setting up tests (empty if not yet needed). */      public static void main(String[] params) throws Exception {}      @Before      public void setUp() throws Exception {          System.out.println("set up."); -        mDoc = TestUtils.document();      }      /** Test for data category personal. */ @@ -207,7 +203,7 @@ public class DataCategoryTest {      private void testHrToOdDataCategory(String fileName) throws Exception {          TestUtils.testHrToOd( -                mDoc, +                TestUtils.document(),                  new DataCategoryFactory(),                  DATA_CATEGORY_HR_PATH,                  DATA_CATEGORY_OD_PATH, diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java index 2be447e182b2..26617264b2e9 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DataLabelsTest.java @@ -22,7 +22,6 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.junit.runners.JUnit4; -import org.w3c.dom.Document;  @RunWith(JUnit4.class)  public class DataLabelsTest { @@ -41,12 +40,33 @@ public class DataLabelsTest {      private static final String SHARED_INVALID_BOOL_FILE_NAME =              "data-labels-shared-invalid-bool.xml"; -    private Document mDoc = null; +    private static final String ACTIONS_IN_APP_FILE_NAME = "data-category-actions-in-app.xml"; +    private static final String APP_PERFORMANCE_FILE_NAME = "data-category-app-performance.xml"; +    private static final String AUDIO_FILE_NAME = "data-category-audio.xml"; +    private static final String CALENDAR_FILE_NAME = "data-category-calendar.xml"; +    private static final String CONTACTS_FILE_NAME = "data-category-contacts.xml"; +    private static final String EMAIL_TEXT_MESSAGE_FILE_NAME = +            "data-category-email-text-message.xml"; +    private static final String FINANCIAL_FILE_NAME = "data-category-financial.xml"; +    private static final String HEALTH_FITNESS_FILE_NAME = "data-category-health-fitness.xml"; +    private static final String IDENTIFIERS_FILE_NAME = "data-category-identifiers.xml"; +    private static final String LOCATION_FILE_NAME = "data-category-location.xml"; +    private static final String PERSONAL_FILE_NAME = "data-category-personal.xml"; +    private static final String PERSONAL_PARTIAL_FILE_NAME = "data-category-personal-partial.xml"; +    private static final String PHOTO_VIDEO_FILE_NAME = "data-category-photo-video.xml"; +    private static final String SEARCH_AND_BROWSING_FILE_NAME = +            "data-category-search-and-browsing.xml"; +    private static final String STORAGE_FILE_NAME = "data-category-storage.xml"; +    private static final String PERSONAL_MISSING_PURPOSE_FILE_NAME = +            "data-category-personal-missing-purpose.xml"; +    private static final String PERSONAL_EMPTY_PURPOSE_FILE_NAME = +            "data-category-personal-empty-purpose.xml"; +    private static final String UNRECOGNIZED_FILE_NAME = "data-category-unrecognized.xml"; +    private static final String UNRECOGNIZED_TYPE_FILE_NAME = "data-category-unrecognized-type.xml";      @Before      public void setUp() throws Exception {          System.out.println("set up."); -        mDoc = TestUtils.document();      }      /** Test for data labels accessed valid bool. */ @@ -54,6 +74,7 @@ public class DataLabelsTest {      public void testDataLabelsAccessedValidBool() throws Exception {          System.out.println("starting testDataLabelsAccessedValidBool.");          testHrToOdDataLabels(ACCESSED_VALID_BOOL_FILE_NAME); +        testOdToHrDataLabels(ACCESSED_VALID_BOOL_FILE_NAME);      }      /** Test for data labels accessed invalid bool. */ @@ -68,6 +89,7 @@ public class DataLabelsTest {      public void testDataLabelsCollectedValidBool() throws Exception {          System.out.println("starting testDataLabelsCollectedValidBool.");          testHrToOdDataLabels(COLLECTED_VALID_BOOL_FILE_NAME); +        testOdToHrDataLabels(COLLECTED_VALID_BOOL_FILE_NAME);      }      /** Test for data labels collected invalid bool. */ @@ -75,6 +97,7 @@ public class DataLabelsTest {      public void testDataLabelsCollectedInvalidBool() throws Exception {          System.out.println("starting testDataLabelsCollectedInvalidBool.");          hrToOdExpectException(COLLECTED_INVALID_BOOL_FILE_NAME); +        odToHrExpectException(COLLECTED_INVALID_BOOL_FILE_NAME);      }      /** Test for data labels shared valid bool. */ @@ -82,6 +105,7 @@ public class DataLabelsTest {      public void testDataLabelsSharedValidBool() throws Exception {          System.out.println("starting testDataLabelsSharedValidBool.");          testHrToOdDataLabels(SHARED_VALID_BOOL_FILE_NAME); +        testOdToHrDataLabels(SHARED_VALID_BOOL_FILE_NAME);      }      /** Test for data labels shared invalid bool. */ @@ -91,12 +115,207 @@ public class DataLabelsTest {          hrToOdExpectException(SHARED_INVALID_BOOL_FILE_NAME);      } +    /* Data categories bidirectional tests... */ + +    /** Test for data labels actions in app. */ +    @Test +    public void testDataLabelsActionsInApp() throws Exception { +        System.out.println("starting testDataLabelsActionsInApp."); +        testHrToOdDataLabels(ACTIONS_IN_APP_FILE_NAME); +        testOdToHrDataLabels(ACTIONS_IN_APP_FILE_NAME); +    } + +    /** Test for data labels app performance. */ +    @Test +    public void testDataLabelsAppPerformance() throws Exception { +        System.out.println("starting testDataLabelsAppPerformance."); +        testHrToOdDataLabels(APP_PERFORMANCE_FILE_NAME); +        testOdToHrDataLabels(APP_PERFORMANCE_FILE_NAME); +    } + +    /** Test for data labels audio. */ +    @Test +    public void testDataLabelsAudio() throws Exception { +        System.out.println("starting testDataLabelsAudio."); +        testHrToOdDataLabels(AUDIO_FILE_NAME); +        testOdToHrDataLabels(AUDIO_FILE_NAME); +    } + +    /** Test for data labels calendar. */ +    @Test +    public void testDataLabelsCalendar() throws Exception { +        System.out.println("starting testDataLabelsCalendar."); +        testHrToOdDataLabels(CALENDAR_FILE_NAME); +        testOdToHrDataLabels(CALENDAR_FILE_NAME); +    } + +    /** Test for data labels contacts. */ +    @Test +    public void testDataLabelsContacts() throws Exception { +        System.out.println("starting testDataLabelsContacts."); +        testHrToOdDataLabels(CONTACTS_FILE_NAME); +        testOdToHrDataLabels(CONTACTS_FILE_NAME); +    } + +    /** Test for data labels email text message. */ +    @Test +    public void testDataLabelsEmailTextMessage() throws Exception { +        System.out.println("starting testDataLabelsEmailTextMessage."); +        testHrToOdDataLabels(EMAIL_TEXT_MESSAGE_FILE_NAME); +        testOdToHrDataLabels(EMAIL_TEXT_MESSAGE_FILE_NAME); +    } + +    /** Test for data labels financial. */ +    @Test +    public void testDataLabelsFinancial() throws Exception { +        System.out.println("starting testDataLabelsFinancial."); +        testHrToOdDataLabels(FINANCIAL_FILE_NAME); +        testOdToHrDataLabels(FINANCIAL_FILE_NAME); +    } + +    /** Test for data labels health fitness. */ +    @Test +    public void testDataLabelsHealthFitness() throws Exception { +        System.out.println("starting testDataLabelsHealthFitness."); +        testHrToOdDataLabels(HEALTH_FITNESS_FILE_NAME); +        testOdToHrDataLabels(HEALTH_FITNESS_FILE_NAME); +    } + +    /** Test for data labels identifiers. */ +    @Test +    public void testDataLabelsIdentifiers() throws Exception { +        System.out.println("starting testDataLabelsIdentifiers."); +        testHrToOdDataLabels(IDENTIFIERS_FILE_NAME); +        testOdToHrDataLabels(IDENTIFIERS_FILE_NAME); +    } + +    /** Test for data labels location. */ +    @Test +    public void testDataLabelsLocation() throws Exception { +        System.out.println("starting testDataLabelsLocation."); +        testHrToOdDataLabels(LOCATION_FILE_NAME); +        testOdToHrDataLabels(LOCATION_FILE_NAME); +    } + +    /** Test for data labels personal. */ +    @Test +    public void testDataLabelsPersonal() throws Exception { +        System.out.println("starting testDataLabelsPersonal."); +        testHrToOdDataLabels(PERSONAL_FILE_NAME); +        testOdToHrDataLabels(PERSONAL_FILE_NAME); +    } + +    /** Test for data labels personal partial. */ +    @Test +    public void testDataLabelsPersonalPartial() throws Exception { +        System.out.println("starting testDataLabelsPersonalPartial."); +        testHrToOdDataLabels(PERSONAL_PARTIAL_FILE_NAME); +        testOdToHrDataLabels(PERSONAL_PARTIAL_FILE_NAME); +    } + +    /** Test for data labels photo video. */ +    @Test +    public void testDataLabelsPhotoVideo() throws Exception { +        System.out.println("starting testDataLabelsPhotoVideo."); +        testHrToOdDataLabels(PHOTO_VIDEO_FILE_NAME); +        testOdToHrDataLabels(PHOTO_VIDEO_FILE_NAME); +    } + +    /** Test for data labels search and browsing. */ +    @Test +    public void testDataLabelsSearchAndBrowsing() throws Exception { +        System.out.println("starting testDataLabelsSearchAndBrowsing."); +        testHrToOdDataLabels(SEARCH_AND_BROWSING_FILE_NAME); +        testOdToHrDataLabels(SEARCH_AND_BROWSING_FILE_NAME); +    } + +    /** Test for data labels storage. */ +    @Test +    public void testDataLabelsStorage() throws Exception { +        System.out.println("starting testDataLabelsStorage."); +        testHrToOdDataLabels(STORAGE_FILE_NAME); +        testOdToHrDataLabels(STORAGE_FILE_NAME); +    } + +    /** Test for data labels hr unrecognized data category. */ +    @Test +    public void testDataLabelsHrUnrecognizedDataCategory() throws Exception { +        System.out.println("starting testDataLabelsHrUnrecognizedDataCategory."); +        hrToOdExpectException(UNRECOGNIZED_FILE_NAME); +    } + +    /** Test for data labels hr unrecognized data type. */ +    @Test +    public void testDataLabelsHrUnrecognizedDataType() throws Exception { +        System.out.println("starting testDataLabelsHrUnrecognizedDataType."); +        hrToOdExpectException(UNRECOGNIZED_TYPE_FILE_NAME); +    } + +    /** Test for data labels hr missing purpose. */ +    @Test +    public void testDataLabelsHrMissingPurpose() throws Exception { +        System.out.println("starting testDataLabelsHrMissingPurpose."); +        hrToOdExpectException(PERSONAL_MISSING_PURPOSE_FILE_NAME); +    } + +    /** Test for data labels hr empty purpose. */ +    @Test +    public void testDataLabelsHrEmptyPurpose() throws Exception { +        System.out.println("starting testDataLabelsHrEmptyPurpose."); +        hrToOdExpectException(PERSONAL_EMPTY_PURPOSE_FILE_NAME); +    } + +    /** Test for data labels od unrecognized data category. */ +    @Test +    public void testDataLabelsOdUnrecognizedDataCategory() throws Exception { +        System.out.println("starting testDataLabelsOdUnrecognizedDataCategory."); +        odToHrExpectException(UNRECOGNIZED_FILE_NAME); +    } + +    /** Test for data labels od unrecognized data type. */ +    @Test +    public void testDataLabelsOdUnrecognizedDataType() throws Exception { +        System.out.println("starting testDataLabelsOdUnrecognizedDataCategory."); +        odToHrExpectException(UNRECOGNIZED_TYPE_FILE_NAME); +    } + +    /** Test for data labels od missing purpose. */ +    @Test +    public void testDataLabelsOdMissingPurpose() throws Exception { +        System.out.println("starting testDataLabelsOdMissingPurpose."); +        odToHrExpectException(PERSONAL_MISSING_PURPOSE_FILE_NAME); +    } + +    /** Test for data labels od empty purpose. */ +    @Test +    public void testDataLabelsOdEmptyPurpose() throws Exception { +        System.out.println("starting testDataLabelsOdEmptyPurpose."); +        odToHrExpectException(PERSONAL_EMPTY_PURPOSE_FILE_NAME); +    } +      private void hrToOdExpectException(String fileName) {          TestUtils.hrToOdExpectException(new DataLabelsFactory(), DATA_LABELS_HR_PATH, fileName);      } +    private void odToHrExpectException(String fileName) { +        TestUtils.odToHrExpectException(new DataLabelsFactory(), DATA_LABELS_OD_PATH, fileName); +    } +      private void testHrToOdDataLabels(String fileName) throws Exception {          TestUtils.testHrToOd( -                mDoc, new DataLabelsFactory(), DATA_LABELS_HR_PATH, DATA_LABELS_OD_PATH, fileName); +                TestUtils.document(), +                new DataLabelsFactory(), +                DATA_LABELS_HR_PATH, +                DATA_LABELS_OD_PATH, +                fileName); +    } + +    private void testOdToHrDataLabels(String fileName) throws Exception { +        TestUtils.testOdToHr( +                TestUtils.document(), +                new DataLabelsFactory(), +                DATA_LABELS_OD_PATH, +                DATA_LABELS_HR_PATH, +                fileName);      }  } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java index ff8346a526ad..72e8d654b542 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/DeveloperInfoTest.java @@ -25,7 +25,6 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.junit.runners.JUnit4; -import org.w3c.dom.Document;  import java.nio.file.Paths;  import java.util.List; @@ -36,19 +35,20 @@ public class DeveloperInfoTest {      private static final String DEVELOPER_INFO_OD_PATH = "com/android/asllib/developerinfo/od";      public static final List<String> REQUIRED_FIELD_NAMES =              List.of("address", "countryRegion", "email", "name", "relationship"); +    public static final List<String> REQUIRED_FIELD_NAMES_OD = +            List.of("address", "country_region", "email", "name", "relationship");      public static final List<String> OPTIONAL_FIELD_NAMES = List.of("website", "registryId"); +    public static final List<String> OPTIONAL_FIELD_NAMES_OD = +            List.of("website", "app_developer_registry_id");      private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml"; -    private Document mDoc = null; -      /** Logic for setting up tests (empty if not yet needed). */      public static void main(String[] params) throws Exception {}      @Before      public void setUp() throws Exception {          System.out.println("set up."); -        mDoc = TestUtils.document();      }      /** Test for all fields valid. */ @@ -56,6 +56,7 @@ public class DeveloperInfoTest {      public void testAllFieldsValid() throws Exception {          System.out.println("starting testAllFieldsValid.");          testHrToOdDeveloperInfo(ALL_FIELDS_VALID_FILE_NAME); +        testOdToHrDeveloperInfo(ALL_FIELDS_VALID_FILE_NAME);      }      /** Tests missing required fields fails. */ @@ -73,6 +74,18 @@ public class DeveloperInfoTest {                      MalformedXmlException.class,                      () -> new DeveloperInfoFactory().createFromHrElements(developerInfoEle));          } + +        for (String reqField : REQUIRED_FIELD_NAMES_OD) { +            System.out.println("testing missing required field od: " + reqField); +            var developerInfoEle = +                    TestUtils.getElementsFromResource( +                            Paths.get(DEVELOPER_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); +            TestUtils.removeOdChildEleWithName(developerInfoEle.get(0), reqField); + +            assertThrows( +                    MalformedXmlException.class, +                    () -> new DeveloperInfoFactory().createFromOdElements(developerInfoEle)); +        }      }      /** Tests missing optional fields passes. */ @@ -85,16 +98,35 @@ public class DeveloperInfoTest {              developerInfoEle.get(0).removeAttribute(optField);              DeveloperInfo developerInfo =                      new DeveloperInfoFactory().createFromHrElements(developerInfoEle); -            developerInfo.toOdDomElements(mDoc); +            developerInfo.toOdDomElements(TestUtils.document()); +        } + +        for (String optField : OPTIONAL_FIELD_NAMES_OD) { +            var developerInfoEle = +                    TestUtils.getElementsFromResource( +                            Paths.get(DEVELOPER_INFO_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); +            TestUtils.removeOdChildEleWithName(developerInfoEle.get(0), optField); +            DeveloperInfo developerInfo = +                    new DeveloperInfoFactory().createFromOdElements(developerInfoEle); +            developerInfo.toHrDomElements(TestUtils.document());          }      }      private void testHrToOdDeveloperInfo(String fileName) throws Exception {          TestUtils.testHrToOd( -                mDoc, +                TestUtils.document(),                  new DeveloperInfoFactory(),                  DEVELOPER_INFO_HR_PATH,                  DEVELOPER_INFO_OD_PATH,                  fileName);      } + +    private void testOdToHrDeveloperInfo(String fileName) throws Exception { +        TestUtils.testOdToHr( +                TestUtils.document(), +                new DeveloperInfoFactory(), +                DEVELOPER_INFO_OD_PATH, +                DEVELOPER_INFO_HR_PATH, +                fileName); +    }  } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java index c52d6c873646..bba6b548beaf 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SafetyLabelsTest.java @@ -22,7 +22,6 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.junit.runners.JUnit4; -import org.w3c.dom.Document;  @RunWith(JUnit4.class)  public class SafetyLabelsTest { @@ -36,12 +35,9 @@ public class SafetyLabelsTest {      private static final String WITH_THIRD_PARTY_VERIFICATION_FILE_NAME =              "with-third-party-verification.xml"; -    private Document mDoc = null; -      @Before      public void setUp() throws Exception {          System.out.println("set up."); -        mDoc = TestUtils.document();      }      /** Test for safety labels missing version. */ @@ -49,6 +45,7 @@ public class SafetyLabelsTest {      public void testSafetyLabelsMissingVersion() throws Exception {          System.out.println("starting testSafetyLabelsMissingVersion.");          hrToOdExpectException(MISSING_VERSION_FILE_NAME); +        odToHrExpectException(MISSING_VERSION_FILE_NAME);      }      /** Test for safety labels valid empty. */ @@ -56,6 +53,7 @@ public class SafetyLabelsTest {      public void testSafetyLabelsValidEmptyFile() throws Exception {          System.out.println("starting testSafetyLabelsValidEmptyFile.");          testHrToOdSafetyLabels(VALID_EMPTY_FILE_NAME); +        testOdToHrSafetyLabels(VALID_EMPTY_FILE_NAME);      }      /** Test for safety labels with data labels. */ @@ -63,6 +61,7 @@ public class SafetyLabelsTest {      public void testSafetyLabelsWithDataLabels() throws Exception {          System.out.println("starting testSafetyLabelsWithDataLabels.");          testHrToOdSafetyLabels(WITH_DATA_LABELS_FILE_NAME); +        testOdToHrSafetyLabels(WITH_DATA_LABELS_FILE_NAME);      }      /** Test for safety labels with security labels. */ @@ -70,6 +69,7 @@ public class SafetyLabelsTest {      public void testSafetyLabelsWithSecurityLabels() throws Exception {          System.out.println("starting testSafetyLabelsWithSecurityLabels.");          testHrToOdSafetyLabels(WITH_SECURITY_LABELS_FILE_NAME); +        testOdToHrSafetyLabels(WITH_SECURITY_LABELS_FILE_NAME);      }      /** Test for safety labels with third party verification. */ @@ -77,18 +77,32 @@ public class SafetyLabelsTest {      public void testSafetyLabelsWithThirdPartyVerification() throws Exception {          System.out.println("starting testSafetyLabelsWithThirdPartyVerification.");          testHrToOdSafetyLabels(WITH_THIRD_PARTY_VERIFICATION_FILE_NAME); +        testOdToHrSafetyLabels(WITH_THIRD_PARTY_VERIFICATION_FILE_NAME);      }      private void hrToOdExpectException(String fileName) {          TestUtils.hrToOdExpectException(new SafetyLabelsFactory(), SAFETY_LABELS_HR_PATH, fileName);      } +    private void odToHrExpectException(String fileName) { +        TestUtils.odToHrExpectException(new SafetyLabelsFactory(), SAFETY_LABELS_OD_PATH, fileName); +    } +      private void testHrToOdSafetyLabels(String fileName) throws Exception {          TestUtils.testHrToOd( -                mDoc, +                TestUtils.document(),                  new SafetyLabelsFactory(),                  SAFETY_LABELS_HR_PATH,                  SAFETY_LABELS_OD_PATH,                  fileName);      } + +    private void testOdToHrSafetyLabels(String fileName) throws Exception { +        TestUtils.testOdToHr( +                TestUtils.document(), +                new SafetyLabelsFactory(), +                SAFETY_LABELS_OD_PATH, +                SAFETY_LABELS_HR_PATH, +                fileName); +    }  } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java index c0d0d728f762..a940bc63c685 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SecurityLabelsTest.java @@ -23,7 +23,6 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.junit.runners.JUnit4; -import org.w3c.dom.Document;  import java.nio.file.Paths;  import java.util.List; @@ -35,18 +34,17 @@ public class SecurityLabelsTest {      public static final List<String> OPTIONAL_FIELD_NAMES =              List.of("isDataDeletable", "isDataEncrypted"); +    public static final List<String> OPTIONAL_FIELD_NAMES_OD = +            List.of("is_data_deletable", "is_data_encrypted");      private static final String ALL_FIELDS_VALID_FILE_NAME = "all-fields-valid.xml"; -    private Document mDoc = null; -      /** Logic for setting up tests (empty if not yet needed). */      public static void main(String[] params) throws Exception {}      @Before      public void setUp() throws Exception {          System.out.println("set up."); -        mDoc = TestUtils.document();      }      /** Test for all fields valid. */ @@ -54,6 +52,7 @@ public class SecurityLabelsTest {      public void testAllFieldsValid() throws Exception {          System.out.println("starting testAllFieldsValid.");          testHrToOdSecurityLabels(ALL_FIELDS_VALID_FILE_NAME); +        testOdToHrSecurityLabels(ALL_FIELDS_VALID_FILE_NAME);      }      /** Tests missing optional fields passes. */ @@ -65,16 +64,33 @@ public class SecurityLabelsTest {                              Paths.get(SECURITY_LABELS_HR_PATH, ALL_FIELDS_VALID_FILE_NAME));              ele.get(0).removeAttribute(optField);              SecurityLabels securityLabels = new SecurityLabelsFactory().createFromHrElements(ele); -            securityLabels.toOdDomElements(mDoc); +            securityLabels.toOdDomElements(TestUtils.document()); +        } +        for (String optField : OPTIONAL_FIELD_NAMES_OD) { +            var ele = +                    TestUtils.getElementsFromResource( +                            Paths.get(SECURITY_LABELS_OD_PATH, ALL_FIELDS_VALID_FILE_NAME)); +            TestUtils.removeOdChildEleWithName(ele.get(0), optField); +            SecurityLabels securityLabels = new SecurityLabelsFactory().createFromOdElements(ele); +            securityLabels.toHrDomElements(TestUtils.document());          }      }      private void testHrToOdSecurityLabels(String fileName) throws Exception {          TestUtils.testHrToOd( -                mDoc, +                TestUtils.document(),                  new SecurityLabelsFactory(),                  SECURITY_LABELS_HR_PATH,                  SECURITY_LABELS_OD_PATH,                  fileName);      } + +    private void testOdToHrSecurityLabels(String fileName) throws Exception { +        TestUtils.testOdToHr( +                TestUtils.document(), +                new SecurityLabelsFactory(), +                SECURITY_LABELS_OD_PATH, +                SECURITY_LABELS_HR_PATH, +                fileName); +    }  } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java index 191091a9e187..33c276487c64 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/SystemAppSafetyLabelTest.java @@ -22,7 +22,6 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.junit.runners.JUnit4; -import org.w3c.dom.Document;  @RunWith(JUnit4.class)  public class SystemAppSafetyLabelTest { @@ -34,15 +33,12 @@ public class SystemAppSafetyLabelTest {      private static final String VALID_FILE_NAME = "valid.xml";      private static final String MISSING_URL_FILE_NAME = "missing-url.xml"; -    private Document mDoc = null; -      /** Logic for setting up tests (empty if not yet needed). */      public static void main(String[] params) throws Exception {}      @Before      public void setUp() throws Exception {          System.out.println("set up."); -        mDoc = TestUtils.document();      }      /** Test for valid. */ @@ -50,6 +46,7 @@ public class SystemAppSafetyLabelTest {      public void testValid() throws Exception {          System.out.println("starting testValid.");          testHrToOdSystemAppSafetyLabel(VALID_FILE_NAME); +        testOdToHrSystemAppSafetyLabel(VALID_FILE_NAME);      }      /** Tests missing url. */ @@ -57,6 +54,7 @@ public class SystemAppSafetyLabelTest {      public void testMissingUrl() throws Exception {          System.out.println("starting testMissingUrl.");          hrToOdExpectException(MISSING_URL_FILE_NAME); +        odToHrExpectException(MISSING_URL_FILE_NAME);      }      private void hrToOdExpectException(String fileName) { @@ -64,12 +62,26 @@ public class SystemAppSafetyLabelTest {                  new SystemAppSafetyLabelFactory(), SYSTEM_APP_SAFETY_LABEL_HR_PATH, fileName);      } +    private void odToHrExpectException(String fileName) { +        TestUtils.odToHrExpectException( +                new SystemAppSafetyLabelFactory(), SYSTEM_APP_SAFETY_LABEL_OD_PATH, fileName); +    } +      private void testHrToOdSystemAppSafetyLabel(String fileName) throws Exception {          TestUtils.testHrToOd( -                mDoc, +                TestUtils.document(),                  new SystemAppSafetyLabelFactory(),                  SYSTEM_APP_SAFETY_LABEL_HR_PATH,                  SYSTEM_APP_SAFETY_LABEL_OD_PATH,                  fileName);      } + +    private void testOdToHrSystemAppSafetyLabel(String fileName) throws Exception { +        TestUtils.testOdToHr( +                TestUtils.document(), +                new SystemAppSafetyLabelFactory(), +                SYSTEM_APP_SAFETY_LABEL_OD_PATH, +                SYSTEM_APP_SAFETY_LABEL_HR_PATH, +                fileName); +    }  } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java index ab8e85cd022b..ec86d0f863af 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/ThirdPartyVerificationTest.java @@ -22,7 +22,6 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.junit.runners.JUnit4; -import org.w3c.dom.Document;  @RunWith(JUnit4.class)  public class ThirdPartyVerificationTest { @@ -34,15 +33,12 @@ public class ThirdPartyVerificationTest {      private static final String VALID_FILE_NAME = "valid.xml";      private static final String MISSING_URL_FILE_NAME = "missing-url.xml"; -    private Document mDoc = null; -      /** Logic for setting up tests (empty if not yet needed). */      public static void main(String[] params) throws Exception {}      @Before      public void setUp() throws Exception {          System.out.println("set up."); -        mDoc = TestUtils.document();      }      /** Test for valid. */ @@ -50,6 +46,7 @@ public class ThirdPartyVerificationTest {      public void testValid() throws Exception {          System.out.println("starting testValid.");          testHrToOdThirdPartyVerification(VALID_FILE_NAME); +        testOdToHrThirdPartyVerification(VALID_FILE_NAME);      }      /** Tests missing url. */ @@ -57,6 +54,7 @@ public class ThirdPartyVerificationTest {      public void testMissingUrl() throws Exception {          System.out.println("starting testMissingUrl.");          hrToOdExpectException(MISSING_URL_FILE_NAME); +        odToHrExpectException(MISSING_URL_FILE_NAME);      }      private void hrToOdExpectException(String fileName) { @@ -64,12 +62,26 @@ public class ThirdPartyVerificationTest {                  new ThirdPartyVerificationFactory(), THIRD_PARTY_VERIFICATION_HR_PATH, fileName);      } +    private void odToHrExpectException(String fileName) { +        TestUtils.odToHrExpectException( +                new ThirdPartyVerificationFactory(), THIRD_PARTY_VERIFICATION_OD_PATH, fileName); +    } +      private void testHrToOdThirdPartyVerification(String fileName) throws Exception {          TestUtils.testHrToOd( -                mDoc, +                TestUtils.document(),                  new ThirdPartyVerificationFactory(),                  THIRD_PARTY_VERIFICATION_HR_PATH,                  THIRD_PARTY_VERIFICATION_OD_PATH,                  fileName);      } + +    private void testOdToHrThirdPartyVerification(String fileName) throws Exception { +        TestUtils.testOdToHr( +                TestUtils.document(), +                new ThirdPartyVerificationFactory(), +                THIRD_PARTY_VERIFICATION_OD_PATH, +                THIRD_PARTY_VERIFICATION_HR_PATH, +                fileName); +    }  } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java index 56503f7d6c6b..f49424061427 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/marshallable/TransparencyInfoTest.java @@ -22,7 +22,6 @@ import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.junit.runners.JUnit4; -import org.w3c.dom.Document;  @RunWith(JUnit4.class)  public class TransparencyInfoTest { @@ -35,12 +34,9 @@ public class TransparencyInfoTest {      private static final String WITH_DEVELOPER_INFO_FILE_NAME = "with-developer-info.xml";      private static final String WITH_APP_INFO_FILE_NAME = "with-app-info.xml"; -    private Document mDoc = null; -      @Before      public void setUp() throws Exception {          System.out.println("set up."); -        mDoc = TestUtils.document();      }      /** Test for transparency info valid empty. */ @@ -48,6 +44,7 @@ public class TransparencyInfoTest {      public void testTransparencyInfoValidEmptyFile() throws Exception {          System.out.println("starting testTransparencyInfoValidEmptyFile.");          testHrToOdTransparencyInfo(VALID_EMPTY_FILE_NAME); +        testOdToHrTransparencyInfo(VALID_EMPTY_FILE_NAME);      }      /** Test for transparency info with developer info. */ @@ -55,6 +52,7 @@ public class TransparencyInfoTest {      public void testTransparencyInfoWithDeveloperInfo() throws Exception {          System.out.println("starting testTransparencyInfoWithDeveloperInfo.");          testHrToOdTransparencyInfo(WITH_DEVELOPER_INFO_FILE_NAME); +        testOdToHrTransparencyInfo(WITH_DEVELOPER_INFO_FILE_NAME);      }      /** Test for transparency info with app info. */ @@ -62,14 +60,24 @@ public class TransparencyInfoTest {      public void testTransparencyInfoWithAppInfo() throws Exception {          System.out.println("starting testTransparencyInfoWithAppInfo.");          testHrToOdTransparencyInfo(WITH_APP_INFO_FILE_NAME); +        testOdToHrTransparencyInfo(WITH_APP_INFO_FILE_NAME);      }      private void testHrToOdTransparencyInfo(String fileName) throws Exception {          TestUtils.testHrToOd( -                mDoc, +                TestUtils.document(),                  new TransparencyInfoFactory(),                  TRANSPARENCY_INFO_HR_PATH,                  TRANSPARENCY_INFO_OD_PATH,                  fileName);      } + +    private void testOdToHrTransparencyInfo(String fileName) throws Exception { +        TestUtils.testOdToHr( +                TestUtils.document(), +                new TransparencyInfoFactory(), +                TRANSPARENCY_INFO_OD_PATH, +                TRANSPARENCY_INFO_HR_PATH, +                fileName); +    }  } diff --git a/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java b/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java index faea340ae7bd..ea90993e0785 100644 --- a/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java +++ b/tools/app_metadata_bundles/src/test/java/com/android/asllib/testutils/TestUtils.java @@ -26,6 +26,8 @@ import com.android.asllib.util.XmlUtils;  import org.w3c.dom.Document;  import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList;  import org.xml.sax.SAXException;  import java.io.ByteArrayInputStream; @@ -36,6 +38,7 @@ import java.nio.charset.StandardCharsets;  import java.nio.file.Path;  import java.nio.file.Paths;  import java.util.List; +import java.util.Optional;  import javax.xml.parsers.DocumentBuilderFactory;  import javax.xml.parsers.ParserConfigurationException; @@ -72,7 +75,7 @@ public class TestUtils {                              .findFirst()                              .get()                              .getTagName(); -            return XmlUtils.asElementList(root.getElementsByTagName(tagName)); +            return XmlUtils.getChildrenByTagName(root, tagName);          } else {              return List.of(root);          } @@ -96,6 +99,19 @@ public class TestUtils {          return outStream.toString(StandardCharsets.UTF_8);      } +    /** Removes on-device style child with the corresponding name */ +    public static void removeOdChildEleWithName(Element ele, String childNameName) { +        Optional<Element> childEle = +                XmlUtils.asElementList(ele.getChildNodes()).stream() +                        .filter(e -> e.getAttribute(XmlUtils.OD_ATTR_NAME).equals(childNameName)) +                        .findFirst(); +        if (childEle.isEmpty()) { +            throw new IllegalStateException( +                    String.format("%s was not found in %s", childNameName, ele.getTagName())); +        } +        ele.removeChild(childEle.get()); +    } +      /**       * Gets formatted XML for slightly more robust comparison checking than naive string comparison.       */ @@ -105,7 +121,7 @@ public class TestUtils {          DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();          factory.setNamespaceAware(true);          Document document = factory.newDocumentBuilder().parse(stream); - +        stripEmptyElements(document);          return docToStr(document, omitXmlDeclaration);      } @@ -125,6 +141,17 @@ public class TestUtils {                  });      } +    /** Helper for testing on-device to human-readable conversion expecting exception */ +    public static <T extends AslMarshallable> void odToHrExpectException( +            AslMarshallableFactory<T> factory, String odFolderPath, String fileName) { +        assertThrows( +                MalformedXmlException.class, +                () -> { +                    factory.createFromOdElements( +                            TestUtils.getElementsFromResource(Paths.get(odFolderPath, fileName))); +                }); +    } +      /** Helper for testing human-readable to on-device conversion */      public static <T extends AslMarshallable> void testHrToOd(              Document doc, @@ -133,20 +160,71 @@ public class TestUtils {              String odFolderPath,              String fileName)              throws Exception { +        testFormatToFormat(doc, factory, hrFolderPath, odFolderPath, fileName, true); +    } + +    /** Helper for testing on-device to human-readable conversion */ +    public static <T extends AslMarshallable> void testOdToHr( +            Document doc, +            AslMarshallableFactory<T> factory, +            String odFolderPath, +            String hrFolderPath, +            String fileName) +            throws Exception { +        testFormatToFormat(doc, factory, odFolderPath, hrFolderPath, fileName, false); +    } + +    /** Helper for testing format to format conversion */ +    private static <T extends AslMarshallable> void testFormatToFormat( +            Document doc, +            AslMarshallableFactory<T> factory, +            String inFolderPath, +            String outFolderPath, +            String fileName, +            boolean hrToOd) +            throws Exception {          AslMarshallable marshallable = -                factory.createFromHrElements( -                        TestUtils.getElementsFromResource(Paths.get(hrFolderPath, fileName))); +                hrToOd +                        ? factory.createFromHrElements( +                                TestUtils.getElementsFromResource( +                                        Paths.get(inFolderPath, fileName))) +                        : factory.createFromOdElements( +                                TestUtils.getElementsFromResource( +                                        Paths.get(inFolderPath, fileName))); + +        List<Element> elements = +                hrToOd ? marshallable.toOdDomElements(doc) : marshallable.toHrDomElements(doc); +        if (elements.isEmpty()) { +            throw new IllegalStateException("elements was empty."); +        } else if (elements.size() == 1) { +            doc.appendChild(elements.get(0)); +        } else { +            Element root = doc.createElement(TestUtils.HOLDER_TAG_NAME); +            for (var child : elements) { +                root.appendChild(child); +            } +            doc.appendChild(root); +        } +        String converted = TestUtils.getFormattedXml(TestUtils.docToStr(doc, true), true); +        System.out.println("Converted: " + converted); +        String expectedOutContents = +                TestUtils.getFormattedXml( +                        TestUtils.readStrFromResource(Paths.get(outFolderPath, fileName)), true); +        System.out.println("Expected: " + expectedOutContents); +        assertEquals(expectedOutContents, converted); +    } -        for (var child : marshallable.toOdDomElements(doc)) { -            doc.appendChild(child); +    private static void stripEmptyElements(Node node) { +        NodeList children = node.getChildNodes(); +        for (int i = 0; i < children.getLength(); ++i) { +            Node child = children.item(i); +            if (child.getNodeType() == Node.TEXT_NODE) { +                if (child.getTextContent().trim().length() == 0) { +                    child.getParentNode().removeChild(child); +                    i--; +                } +            } +            stripEmptyElements(child);          } -        String converted = TestUtils.docToStr(doc, true); -        System.out.println("converted: " + converted); - -        String expectedOdContents = -                TestUtils.readStrFromResource(Paths.get(odFolderPath, fileName)); -        assertEquals( -                TestUtils.getFormattedXml(expectedOdContents, true), -                TestUtils.getFormattedXml(converted, true));      }  } diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml new file mode 100644 index 000000000000..1aa3aa94ca6d --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/androidsafetylabel/od/missing-version.xml @@ -0,0 +1,2 @@ +<bundle> +</bundle>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-actions-in-app.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-actions-in-app.xml new file mode 100644 index 000000000000..68e191e8ebe3 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-actions-in-app.xml @@ -0,0 +1,17 @@ +<data-labels> +    <data-shared dataCategory="actions_in_app" +        dataType="user_interaction" +        purposes="analytics" /> +    <data-shared dataCategory="actions_in_app" +        dataType="in_app_search_history" +        purposes="analytics" /> +    <data-shared dataCategory="actions_in_app" +        dataType="installed_apps" +        purposes="analytics" /> +    <data-shared dataCategory="actions_in_app" +        dataType="user_generated_content" +        purposes="analytics" /> +    <data-shared dataCategory="actions_in_app" +        dataType="other" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-app-performance.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-app-performance.xml new file mode 100644 index 000000000000..a6bd17d63704 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-app-performance.xml @@ -0,0 +1,11 @@ +<data-labels> +    <data-shared dataCategory="app_performance" +        dataType="crash_logs" +        purposes="analytics" /> +    <data-shared dataCategory="app_performance" +        dataType="performance_diagnostics" +        purposes="analytics" /> +    <data-shared dataCategory="app_performance" +        dataType="other" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-audio.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-audio.xml new file mode 100644 index 000000000000..6274604f3431 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-audio.xml @@ -0,0 +1,11 @@ +<data-labels> +    <data-shared dataCategory="audio" +        dataType="sound_recordings" +        purposes="analytics" /> +    <data-shared dataCategory="audio" +        dataType="music_files" +        purposes="analytics" /> +    <data-shared dataCategory="audio" +        dataType="other" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-calendar.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-calendar.xml new file mode 100644 index 000000000000..f7201f625629 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-calendar.xml @@ -0,0 +1,5 @@ +<data-labels> +    <data-shared dataCategory="calendar" +        dataType="calendar" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-contacts.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-contacts.xml new file mode 100644 index 000000000000..e8d40be91d90 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-contacts.xml @@ -0,0 +1,5 @@ +<data-labels> +    <data-shared dataCategory="contacts" +        dataType="contacts" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-email-text-message.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-email-text-message.xml new file mode 100644 index 000000000000..69e9b87db287 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-email-text-message.xml @@ -0,0 +1,11 @@ +<data-labels> +    <data-shared dataCategory="email_text_message" +        dataType="emails" +        purposes="analytics" /> +    <data-shared dataCategory="email_text_message" +        dataType="text_messages" +        purposes="analytics" /> +    <data-shared dataCategory="email_text_message" +        dataType="other" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-financial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-financial.xml new file mode 100644 index 000000000000..fdd84569a5df --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-financial.xml @@ -0,0 +1,14 @@ +<data-labels> +    <data-shared dataCategory="financial" +        dataType="card_bank_account" +        purposes="analytics" /> +    <data-shared dataCategory="financial" +    dataType="purchase_history" +    purposes="analytics" /> +    <data-shared dataCategory="financial" +        dataType="credit_score" +        purposes="analytics" /> +    <data-shared dataCategory="financial" +        dataType="other" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-health-fitness.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-health-fitness.xml new file mode 100644 index 000000000000..bac58e6fb7df --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-health-fitness.xml @@ -0,0 +1,8 @@ +<data-labels> +    <data-shared dataCategory="health_fitness" +        dataType="health" +        purposes="analytics" /> +    <data-shared dataCategory="health_fitness" +        dataType="fitness" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-identifiers.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-identifiers.xml new file mode 100644 index 000000000000..ee45f269eb7f --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-identifiers.xml @@ -0,0 +1,5 @@ +<data-labels> +    <data-shared dataCategory="identifiers" +        dataType="other" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-location.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-location.xml new file mode 100644 index 000000000000..e8e59118f69c --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-location.xml @@ -0,0 +1,8 @@ +<data-labels> +    <data-shared dataCategory="location" +        dataType="approx_location" +        purposes="analytics" /> +    <data-shared dataCategory="location" +        dataType="precise_location" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-empty-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-empty-purpose.xml new file mode 100644 index 000000000000..0b220f43e5af --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-empty-purpose.xml @@ -0,0 +1,5 @@ +<data-labels> +    <data-shared dataCategory="personal" +    dataType="email_address" +    purposes="" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-missing-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-missing-purpose.xml new file mode 100644 index 000000000000..ac221f208577 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-missing-purpose.xml @@ -0,0 +1,4 @@ +<data-labels> +    <data-shared dataCategory="personal" +    dataType="email_address" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-partial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-partial.xml new file mode 100644 index 000000000000..11b73689230b --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-partial.xml @@ -0,0 +1,8 @@ +<data-labels> +    <data-shared dataCategory="personal" +        dataType="name" +        purposes="analytics|developer_communications" /> +    <data-shared dataCategory="personal" +    dataType="email_address" +    purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-unrecognized-type.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-unrecognized-type.xml new file mode 100644 index 000000000000..f1fbd56571b2 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal-unrecognized-type.xml @@ -0,0 +1,5 @@ +<data-labels> +    <data-shared dataCategory="personal" +    dataType="unrecognized" +    purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal.xml new file mode 100644 index 000000000000..59074628de70 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-personal.xml @@ -0,0 +1,31 @@ +<data-labels> +    <data-shared dataCategory="personal" +        dataType="name" +        ephemeral="true" +        isSharingOptional="true" +        purposes="analytics|developer_communications" /> +    <data-shared dataCategory="personal" +    dataType="email_address" +    purposes="analytics" /> +    <data-shared dataCategory="personal" +    dataType="physical_address" +    purposes="analytics" /> +    <data-shared dataCategory="personal" +    dataType="phone_number" +    purposes="analytics" /> +    <data-shared dataCategory="personal" +    dataType="race_ethnicity" +    purposes="analytics" /> +    <data-shared dataCategory="personal" +    dataType="political_or_religious_beliefs" +    purposes="analytics" /> +    <data-shared dataCategory="personal" +    dataType="sexual_orientation_or_gender_identity" +    purposes="analytics" /> +    <data-shared dataCategory="personal" +    dataType="personal_identifiers" +    purposes="analytics" /> +    <data-shared dataCategory="personal" +    dataType="other" +    purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-photo-video.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-photo-video.xml new file mode 100644 index 000000000000..05fe159a1d7c --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-photo-video.xml @@ -0,0 +1,8 @@ +<data-labels> +    <data-shared dataCategory="photo_video" +        dataType="photos" +        purposes="analytics" /> +    <data-shared dataCategory="photo_video" +        dataType="videos" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-search-and-browsing.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-search-and-browsing.xml new file mode 100644 index 000000000000..a5de7bed4152 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-search-and-browsing.xml @@ -0,0 +1,5 @@ +<data-labels> +    <data-shared dataCategory="search_and_browsing" +        dataType="web_browsing_history" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-storage.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-storage.xml new file mode 100644 index 000000000000..f01e2df8d99a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-storage.xml @@ -0,0 +1,5 @@ +<data-labels> +    <data-shared dataCategory="storage" +        dataType="files_docs" +        purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized-type.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized-type.xml new file mode 100644 index 000000000000..f1fbd56571b2 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized-type.xml @@ -0,0 +1,5 @@ +<data-labels> +    <data-shared dataCategory="personal" +    dataType="unrecognized" +    purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized.xml new file mode 100644 index 000000000000..c5be68424226 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-category-unrecognized.xml @@ -0,0 +1,5 @@ +<data-labels> +    <data-shared dataCategory="unrecognized" +    dataType="email_address" +    purposes="analytics" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-collected-shared.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-collected-shared.xml new file mode 100644 index 000000000000..161057a51b79 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/hr/data-labels-accessed-collected-shared.xml @@ -0,0 +1,11 @@ +<data-labels> +    <data-accessed dataCategory="location" +        dataType="approx_location" +        purposes="app_functionality" /> +    <data-collected dataCategory="location" +        dataType="precise_location" +        purposes="app_functionality" /> +    <data-shared dataCategory="personal" +        dataType="name" +        purposes="app_functionality" /> +</data-labels>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-actions-in-app.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-actions-in-app.xml new file mode 100644 index 000000000000..c5fef58cb25c --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-actions-in-app.xml @@ -0,0 +1,31 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="actions_in_app"> +            <pbundle_as_map name="user_interaction"> +                <int-array name="purposes" num="1"> +                    <item value="2" /> +                </int-array> +            </pbundle_as_map> +            <pbundle_as_map name="in_app_search_history"> +                <int-array name="purposes" num="1"> +                    <item value="2" /> +                </int-array> +            </pbundle_as_map> +            <pbundle_as_map name="installed_apps"> +                <int-array name="purposes" num="1"> +                    <item value="2" /> +                </int-array> +            </pbundle_as_map> +            <pbundle_as_map name="user_generated_content"> +                <int-array name="purposes" num="1"> +                    <item value="2" /> +                </int-array> +            </pbundle_as_map> +            <pbundle_as_map name="other"> +                <int-array name="purposes" num="1"> +                    <item value="2" /> +                </int-array> +            </pbundle_as_map> +        </pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-app-performance.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-app-performance.xml new file mode 100644 index 000000000000..4570145a0436 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-app-performance.xml @@ -0,0 +1,21 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="app_performance"> +    <pbundle_as_map name="crash_logs"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="performance_diagnostics"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="other"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-audio.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-audio.xml new file mode 100644 index 000000000000..120f626549f7 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-audio.xml @@ -0,0 +1,21 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="audio"> +    <pbundle_as_map name="sound_recordings"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="music_files"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="other"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-calendar.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-calendar.xml new file mode 100644 index 000000000000..59eb93812690 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-calendar.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="calendar"> +    <pbundle_as_map name="calendar"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-contacts.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-contacts.xml new file mode 100644 index 000000000000..f952bfb4df79 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-contacts.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="contacts"> +    <pbundle_as_map name="contacts"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-email-text-message.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-email-text-message.xml new file mode 100644 index 000000000000..bcaa716559d4 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-email-text-message.xml @@ -0,0 +1,21 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="email_text_message"> +    <pbundle_as_map name="emails"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="text_messages"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="other"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-financial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-financial.xml new file mode 100644 index 000000000000..a7bc82e38dac --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-financial.xml @@ -0,0 +1,26 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="financial"> +    <pbundle_as_map name="card_bank_account"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="purchase_history"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="credit_score"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="other"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-health-fitness.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-health-fitness.xml new file mode 100644 index 000000000000..f3ab2bd90733 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-health-fitness.xml @@ -0,0 +1,16 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="health_fitness"> +    <pbundle_as_map name="health"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="fitness"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-identifiers.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-identifiers.xml new file mode 100644 index 000000000000..05c07e54c5a8 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-identifiers.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="identifiers"> +    <pbundle_as_map name="other"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-location.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-location.xml new file mode 100644 index 000000000000..931d1adc0218 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-location.xml @@ -0,0 +1,16 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="location"> +    <pbundle_as_map name="approx_location"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="precise_location"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-empty-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-empty-purpose.xml new file mode 100644 index 000000000000..83f4a67cd54d --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-empty-purpose.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="personal"> +    <pbundle_as_map name="email_address"> + +        <int-array name="purposes" num="2"> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-missing-purpose.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-missing-purpose.xml new file mode 100644 index 000000000000..532f5deee655 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-missing-purpose.xml @@ -0,0 +1,8 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="personal"> +    <pbundle_as_map name="email_address"> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-partial.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-partial.xml new file mode 100644 index 000000000000..14f9ef2b74ad --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal-partial.xml @@ -0,0 +1,17 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="personal"> +    <pbundle_as_map name="name"> +        <int-array name="purposes" num="2"> +            <item value="2" /> +            <item value="3" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="email_address"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal.xml new file mode 100644 index 000000000000..1c87de9e67a7 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-personal.xml @@ -0,0 +1,54 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="personal"> +    <pbundle_as_map name="name"> +        <int-array name="purposes" num="2"> +            <item value="2" /> +            <item value="3" /> +        </int-array> +        <boolean name="is_sharing_optional" value="true" /> +        <boolean name="ephemeral" value="true" /> +    </pbundle_as_map> +    <pbundle_as_map name="email_address"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="physical_address"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="phone_number"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="race_ethnicity"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="political_or_religious_beliefs"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="sexual_orientation_or_gender_identity"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="personal_identifiers"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="other"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-photo-video.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-photo-video.xml new file mode 100644 index 000000000000..a752b5152c25 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-photo-video.xml @@ -0,0 +1,16 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="photo_video"> +    <pbundle_as_map name="photos"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +    <pbundle_as_map name="videos"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-search-and-browsing.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-search-and-browsing.xml new file mode 100644 index 000000000000..99bc1881b4f1 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-search-and-browsing.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="search_and_browsing"> +    <pbundle_as_map name="web_browsing_history"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-storage.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-storage.xml new file mode 100644 index 000000000000..a4d2a6249119 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-storage.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="storage"> +    <pbundle_as_map name="files_docs"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized-type.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized-type.xml new file mode 100644 index 000000000000..16195df53b3a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized-type.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="personal"> +    <pbundle_as_map name="unrecognized"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized.xml new file mode 100644 index 000000000000..511940eafd4a --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-category-unrecognized.xml @@ -0,0 +1,11 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="unrecognized"> +    <pbundle_as_map name="email_address"> +        <int-array name="purposes" num="1"> +            <item value="2" /> +        </int-array> +    </pbundle_as_map> +</pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-collected-shared.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-collected-shared.xml new file mode 100644 index 000000000000..f86dbc1a63b2 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-accessed-collected-shared.xml @@ -0,0 +1,29 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_accessed"> +        <pbundle_as_map name="location"> +            <pbundle_as_map name="approx_location"> +                <int-array name="purposes" num="1"> +                    <item value="1"/> +                </int-array> +            </pbundle_as_map> +        </pbundle_as_map> +    </pbundle_as_map> +    <pbundle_as_map name="data_collected"> +        <pbundle_as_map name="location"> +            <pbundle_as_map name="precise_location"> +                <int-array name="purposes" num="1"> +                    <item value="1"/> +                </int-array> +            </pbundle_as_map> +        </pbundle_as_map> +    </pbundle_as_map> +    <pbundle_as_map name="data_shared"> +        <pbundle_as_map name="personal"> +            <pbundle_as_map name="name"> +                <int-array name="purposes" num="1"> +                    <item value="1"/> +                </int-array> +            </pbundle_as_map> +        </pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-invalid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-invalid-bool.xml new file mode 100644 index 000000000000..54cc8e7049b2 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-collected-invalid-bool.xml @@ -0,0 +1,13 @@ +<pbundle_as_map name="data_labels"> +    <pbundle_as_map name="data_collected"> +        <pbundle_as_map name="location"> +            <pbundle_as_map name="approx_location"> +                <int-array name="purposes" num="1"> +                    <item value="1"/> +                </int-array> +                <boolean name="is_sharing_optional" value="false"/> +                <boolean name="ephemeral" value="false"/> +            </pbundle_as_map> +        </pbundle_as_map> +    </pbundle_as_map> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-shared-valid-bool.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-shared-valid-bool.xml index d1d4e33e855a..3864f986d20d 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-shared-valid-bool.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/datalabels/od/data-labels-shared-valid-bool.xml @@ -1,5 +1,5 @@  <pbundle_as_map name="data_labels"> -    <pbundle_as_map name="data_shared"> +<pbundle_as_map name="data_shared">          <pbundle_as_map name="location">              <pbundle_as_map name="approx_location">                  <int-array name="purposes" num="1"> diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml new file mode 100644 index 000000000000..3fbe3599cd82 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/safetylabels/od/missing-version.xml @@ -0,0 +1,2 @@ +<pbundle_as_map name="safety_labels"> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/missing-url.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/missing-url.xml new file mode 100644 index 000000000000..33b796552463 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/systemappsafetylabel/od/missing-url.xml @@ -0,0 +1,2 @@ +<pbundle_as_map name="system_app_safety_label"> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/missing-url.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/missing-url.xml new file mode 100644 index 000000000000..0b5a46f904e4 --- /dev/null +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/thirdpartyverification/od/missing-url.xml @@ -0,0 +1,2 @@ +<pbundle_as_map name="third_party_verification"> +</pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml index 862bda465b25..d16caaea320f 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/hr/with-developer-info.xml @@ -7,5 +7,5 @@          countryRegion="US"          relationship="aosp"          website="example.com" -        appDeveloperRegistryId="registry_id" /> +        registryId="registry_id" />  </transparency-info>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml index 101c98bd8e60..d7a4e1a959b7 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/transparencyinfo/od/with-developer-info.xml @@ -7,5 +7,6 @@          <string name="country_region" value="US"/>          <long name="relationship" value="5"/>          <string name="website" value="example.com"/> +        <string name="app_developer_registry_id" value="registry_id"/>      </pbundle_as_map>  </pbundle_as_map>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml index 36beb93319cd..8f854ad1107e 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/hr.xml @@ -1,6 +1,4 @@  <app-metadata-bundles version="123"> -    <system-app-safety-label url="www.example.com"> -    </system-app-safety-label>      <safety-labels version="12345">          <data-labels>              <data-shared dataCategory="location" @@ -21,6 +19,8 @@          <third-party-verification url="www.example.com">          </third-party-verification>      </safety-labels> +    <system-app-safety-label url="www.example.com"> +    </system-app-safety-label>      <transparency-info>          <developer-info              name="max" @@ -29,7 +29,7 @@              countryRegion="US"              relationship="aosp"              website="example.com" -            appDeveloperRegistryId="registry_id" /> +            registryId="registry_id" />          <app-info title="beervision" description="a beer app" containsAds="true" obeyAps="false" adsFingerprinting="false" securityFingerprinting="false" privacyPolicy="www.example.com" securityEndpoints="url1|url2|url3" firstPartyEndpoints="url1" serviceProviderEndpoints="url55|url56" category="Food and drink" email="max@maxloh.com" />      </transparency-info>  </app-metadata-bundles>
\ No newline at end of file diff --git a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml index db21280ad61b..8f1dc6475b78 100644 --- a/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml +++ b/tools/app_metadata_bundles/src/test/resources/com/android/asllib/validmappings/general/od.xml @@ -42,6 +42,7 @@              <string name="country_region" value="US"/>              <long name="relationship" value="5"/>              <string name="website" value="example.com"/> +            <string name="app_developer_registry_id" value="registry_id"/>          </pbundle_as_map>          <pbundle_as_map name="app_info">              <string name="title" value="beervision"/>  |